mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	merged master
This commit is contained in:
		
						commit
						c87e55a2cc
					
				
					 45 changed files with 2155 additions and 1144 deletions
				
			
		
							
								
								
									
										71
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										71
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -3,7 +3,7 @@ simple-rtmp-server
 | 
			
		|||
 | 
			
		||||
srs(simple rtmp origin live server) over state-threads.<br/>
 | 
			
		||||
srs is a simple, high-performance, running in single process, origin live server.<br/>
 | 
			
		||||
srs supports rtmp, HLS, transcoding, forward, http hooks. <br/>
 | 
			
		||||
srs supports vhost, rtmp, HLS, transcoding, forward, http hooks. <br/>
 | 
			
		||||
blog: [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin) <br/>
 | 
			
		||||
see also: [https://github.com/winlinvip/simple-rtmp-server](https://github.com/winlinvip/simple-rtmp-server) <br/>
 | 
			
		||||
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
 | 
			
		|||
winlin(winterserver): [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin)
 | 
			
		||||
 | 
			
		||||
### Usage
 | 
			
		||||
step 1: build srs <br/>
 | 
			
		||||
<strong>step 1:</strong> build srs <br/>
 | 
			
		||||
<pre>
 | 
			
		||||
tar xf simple-rtmp-server-*.*.tar.gz
 | 
			
		||||
cd simple-rtmp-server-*.*/trunk
 | 
			
		||||
./configure --with-ssl --with-hls --with-ffmpeg --with-http
 | 
			
		||||
make
 | 
			
		||||
</pre>
 | 
			
		||||
step 2: start srs <br/>
 | 
			
		||||
or get the latest code:<br/>
 | 
			
		||||
<pre>
 | 
			
		||||
./objs/simple_rtmp_server -c conf/srs.conf
 | 
			
		||||
git clone  https://github.com/winlinvip/simple-rtmp-server
 | 
			
		||||
cd simple-rtmp-server/trunk
 | 
			
		||||
./configure --with-ssl --with-hls --with-ffmpeg --with-http
 | 
			
		||||
</pre>
 | 
			
		||||
step 3(optinal): start srs listen at 19350 to forward to<br/>
 | 
			
		||||
<strong>step 2:</strong> start srs <br/>
 | 
			
		||||
<pre>
 | 
			
		||||
./objs/simple_rtmp_server -c conf/srs.19350.conf
 | 
			
		||||
./objs/srs -c conf/srs.conf
 | 
			
		||||
</pre>
 | 
			
		||||
step 4(optional): start nginx for HLS <br/>
 | 
			
		||||
<strong>step 3(optinal):</strong> start srs listen at 19350 to forward to<br/>
 | 
			
		||||
<pre>
 | 
			
		||||
./objs/srs -c conf/srs.19350.conf
 | 
			
		||||
</pre>
 | 
			
		||||
<strong>step 4(optinal):</strong> start nginx for HLS <br/>
 | 
			
		||||
<pre>
 | 
			
		||||
sudo ./objs/nginx/sbin/nginx
 | 
			
		||||
</pre>
 | 
			
		||||
step 5(optional): start http hooks for srs callback <br/>
 | 
			
		||||
<strong>step 5(optinal):</strong> start http hooks for srs callback <br/>
 | 
			
		||||
<pre>
 | 
			
		||||
python ./research/api-server/server.py 8085
 | 
			
		||||
</pre>
 | 
			
		||||
step 6: publish live stream <br/>
 | 
			
		||||
<strong>step 6:</strong> publish live stream <br/>
 | 
			
		||||
<pre>
 | 
			
		||||
FMS URL: rtmp://127.0.0.1:1935/live
 | 
			
		||||
Stream:  livestream
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +53,7 @@ For example, use ffmpeg to publish:
 | 
			
		|||
        sleep 1; \
 | 
			
		||||
    done
 | 
			
		||||
</pre>
 | 
			
		||||
step 7: add server ip to client hosts as demo. <br/>
 | 
			
		||||
<strong>step 7:</strong> add server ip to client hosts as demo. <br/>
 | 
			
		||||
<pre>
 | 
			
		||||
# edit the folowing file:
 | 
			
		||||
# linux: /etc/hosts
 | 
			
		||||
| 
						 | 
				
			
			@ -55,26 +61,41 @@ step 7: add server ip to client hosts as demo. <br/>
 | 
			
		|||
# where server ip is 192.168.2.111
 | 
			
		||||
192.168.2.111 demo 
 | 
			
		||||
</pre>
 | 
			
		||||
step 8: play live stream. <br/>
 | 
			
		||||
<strong>step 8:</strong> play live stream. <br/>
 | 
			
		||||
<pre>
 | 
			
		||||
players: http://demo:80/players
 | 
			
		||||
rtmp url: rtmp://demo:1935/live/livestream
 | 
			
		||||
m3u8 url: http://demo:80/live/livestream.m3u8
 | 
			
		||||
for android: http://demo:80/live/livestream.html
 | 
			
		||||
</pre>
 | 
			
		||||
step 9: play live stream auto transcoded<br/>
 | 
			
		||||
<strong>step 9(optinal):</strong> play live stream auto transcoded<br/>
 | 
			
		||||
<pre>
 | 
			
		||||
rtmp url: rtmp://demo:1935/live/livestream_ld
 | 
			
		||||
m3u8 url: http://demo:80/live/livestream_ld.m3u8
 | 
			
		||||
for android: http://demo:80/live/livestream_ld.html
 | 
			
		||||
rtmp url: rtmp://demo:1935/live/livestream_sd
 | 
			
		||||
m3u8 url: http://demo:80/live/livestream_sd.m3u8
 | 
			
		||||
for android: http://demo:80/live/livestream_sd.html
 | 
			
		||||
</pre>
 | 
			
		||||
step 10: play live stream auto forwarded, the hls dir change to /forward<br/>
 | 
			
		||||
<strong>step 10(optinal):</strong> play live stream auto forwarded, the hls dir change to /forward<br/>
 | 
			
		||||
<pre>
 | 
			
		||||
rtmp url: rtmp://demo:19350/live/livestream
 | 
			
		||||
m3u8 url: http://demo:80/forward/live/livestream.m3u8
 | 
			
		||||
for android: http://demo:80/forward/live/livestream.html
 | 
			
		||||
rtmp url: rtmp://demo:19350/live/livestream_ld
 | 
			
		||||
m3u8 url: http://demo:80/forward/live/livestream_ld.m3u8
 | 
			
		||||
for android: http://demo:80/forward/live/livestream_ld.html
 | 
			
		||||
rtmp url: rtmp://demo:19350/live/livestream_sd
 | 
			
		||||
m3u8 url: http://demo:80/forward/live/livestream_sd.m3u8
 | 
			
		||||
for android: http://demo:80/forward/live/livestream_sd.html
 | 
			
		||||
</pre>
 | 
			
		||||
<strong>step 11(optinal):</strong> modify the config and reload it (all features support reload)<br/>
 | 
			
		||||
<pre>
 | 
			
		||||
killall -1 srs
 | 
			
		||||
</pre>
 | 
			
		||||
or use specified signal to reload:<br/>
 | 
			
		||||
<pre>
 | 
			
		||||
killall -s SIGHUP srs
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
### Architecture
 | 
			
		||||
| 
						 | 
				
			
			@ -192,7 +213,15 @@ usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw
 | 
			
		|||
* nginx v1.5.0: 139524 lines <br/>
 | 
			
		||||
 | 
			
		||||
### History
 | 
			
		||||
* v0.8, 2013-12-08, v0.8 released. 19186 lines.
 | 
			
		||||
* v0.9, 2013-12-15, ensure the HLS(ts) is continous when republish stream.
 | 
			
		||||
* v0.9, 2013-12-15, fix the hls reload bug, feed it the sequence header.
 | 
			
		||||
* v0.9, 2013-12-15, refine protocol, use int64_t timestamp for ts and jitter.
 | 
			
		||||
* v0.9, 2013-12-15, support set the live queue length(in seconds), drop when full.
 | 
			
		||||
* v0.9, 2013-12-15, fix the forwarder reconnect bug, feed it the sequence header.
 | 
			
		||||
* v0.9, 2013-12-15, support reload the hls/forwarder/transcoder.
 | 
			
		||||
* v0.9, 2013-12-14, refine the thread model for the retry threads.
 | 
			
		||||
* v0.9, 2013-12-10, auto install depends tools/libs on centos/ubuntu.
 | 
			
		||||
* v0.8, 2013-12-08, [v0.8](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.8) released. 19186 lines.
 | 
			
		||||
* v0.8, 2013-12-08, support http hooks: on_connect/close/publish/unpublish/play/stop.
 | 
			
		||||
* v0.8, 2013-12-08, support multiple http hooks for a event.
 | 
			
		||||
* 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
 | 
			
		|||
* v0.8, 2013-12-06, support max_connections, drop if exceed.
 | 
			
		||||
* v0.8, 2013-12-05, support log_dir, write ffmpeg log to file.
 | 
			
		||||
* v0.8, 2013-12-05, fix the forward/hls/encoder bug.
 | 
			
		||||
* v0.7, 2013-12-03, v0.7 released. 17605 lines.
 | 
			
		||||
* v0.7, 2013-12-03, [v0.7](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.7) released. 17605 lines.
 | 
			
		||||
* v0.7, 2013-12-01, support dead-loop detect for forwarder and transcoder.
 | 
			
		||||
* v0.7, 2013-12-01, support all ffmpeg filters and params.
 | 
			
		||||
* v0.7, 2013-11-30, support live stream transcoder by ffmpeg.
 | 
			
		||||
* v0.7, 2013-11-30, support --with/without -ffmpeg, build ffmpeg-2.1.
 | 
			
		||||
* v0.7, 2013-11-30, add ffmpeg-2.1, x264-core138, lame-3.99.5, libaacplus-2.0.2.
 | 
			
		||||
* v0.6, 2013-11-29, v0.6 released. 16094 lines.
 | 
			
		||||
* v0.6, 2013-11-29, [v0.6](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.6) released. 16094 lines.
 | 
			
		||||
* v0.6, 2013-11-29, add performance summary, 1800 clients, 900Mbps, CPU 90.2%, 41MB.
 | 
			
		||||
* v0.6, 2013-11-29, support forward stream to other edge server.
 | 
			
		||||
* v0.6, 2013-11-29, support forward stream to other origin server.
 | 
			
		||||
* v0.6, 2013-11-28, fix memory leak bug, aac decode bug.
 | 
			
		||||
* v0.6, 2013-11-27, support --with or --without -hls and -ssl options.
 | 
			
		||||
* v0.6, 2013-11-27, support AAC 44100HZ sample rate for iphone, adjust the timestamp.
 | 
			
		||||
* v0.5, 2013-11-26, v0.5 released. 14449 lines.
 | 
			
		||||
* v0.5, 2013-11-26, [v0.5](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.5) released. 14449 lines.
 | 
			
		||||
* v0.5, 2013-11-24, support HLS(m3u8), fragment and window.
 | 
			
		||||
* v0.5, 2013-11-24, support record to ts file for HLS.
 | 
			
		||||
* v0.5, 2013-11-21, add ts_info tool to demux ts file.
 | 
			
		||||
* v0.5, 2013-11-16, add rtmp players(OSMF/jwplayer5/jwplayer6).
 | 
			
		||||
* v0.4, 2013-11-10, v0.4 released. 12500 lines.
 | 
			
		||||
* v0.4, 2013-11-10, [v0.4](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.4) released. 12500 lines.
 | 
			
		||||
* v0.4, 2013-11-10, support config and reload the pithy print.
 | 
			
		||||
* v0.4, 2013-11-09, support reload config(vhost and its detail).
 | 
			
		||||
* v0.4, 2013-11-09, support reload config(listen and chunk_size) by SIGHUP(1).
 | 
			
		||||
* v0.4, 2013-11-09, support longtime(>4.6hours) publish/play.
 | 
			
		||||
* v0.4, 2013-11-09, support config the chunk_size.
 | 
			
		||||
* v0.4, 2013-11-09, support pause for live stream.
 | 
			
		||||
* v0.3, 2013-11-04, v0.3 released. 11773 lines.
 | 
			
		||||
* v0.3, 2013-11-04, [v0.3](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.3) released. 11773 lines.
 | 
			
		||||
* v0.3, 2013-11-04, support refer/play-refer/publish-refer.
 | 
			
		||||
* v0.3, 2013-11-04, support vhosts specified config.
 | 
			
		||||
* 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
 | 
			
		|||
* v0.3, 2013-10-29, support pithy print log message specified by stage.
 | 
			
		||||
* v0.3, 2013-10-28, support librtmp without extended-timestamp in 0xCX chunk packet.
 | 
			
		||||
* v0.3, 2013-10-27, support cache last gop for client fast startup.
 | 
			
		||||
* v0.2, 2013-10-25, v0.2 released. 10125 lines.
 | 
			
		||||
* v0.2, 2013-10-25, [v0.2](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.2) released. 10125 lines.
 | 
			
		||||
* v0.2, 2013-10-25, support flash publish.
 | 
			
		||||
* v0.2, 2013-10-25, support h264/avc codec by rtmp complex handshake.
 | 
			
		||||
* v0.2, 2013-10-24, support time jitter detect and correct algorithm
 | 
			
		||||
* v0.2, 2013-10-24, support decode codec type to cache the h264/avc sequence header.
 | 
			
		||||
* v0.1, 2013-10-23, v0.1 released. 8287 lines.
 | 
			
		||||
* v0.1, 2013-10-23, [v0.1](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.1) released. 8287 lines.
 | 
			
		||||
* v0.1, 2013-10-23, support basic amf0 codec, simplify the api using c-style api.
 | 
			
		||||
* v0.1, 2013-10-23, support shared ptr msg for zero memory copy.
 | 
			
		||||
* v0.1, 2013-10-22, support vp6 codec with rtmp protocol specified simple handshake.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,7 +59,9 @@ else
 | 
			
		|||
    echo "build x264"
 | 
			
		||||
    cd $ff_current_dir &&
 | 
			
		||||
    rm -rf x264-snapshot-20131129-2245-stable && unzip -q ${ff_src_dir}/x264-snapshot-20131129-2245-stable.zip &&
 | 
			
		||||
    cd x264-snapshot-20131129-2245-stable && ./configure --prefix=${ff_release_dir} --bit-depth=8 --enable-static && make && make install
 | 
			
		||||
    cd x264-snapshot-20131129-2245-stable && 
 | 
			
		||||
    ./configure --prefix=${ff_release_dir} --disable-opencl --bit-depth=8 --enable-static && 
 | 
			
		||||
    make && make install
 | 
			
		||||
    ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build x264 failed"; exit 1; fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +88,8 @@ else
 | 
			
		|||
        --enable-postproc --enable-bzlib --enable-zlib --enable-parsers \
 | 
			
		||||
        --enable-libfreetype \
 | 
			
		||||
        --enable-libx264 --enable-libmp3lame --enable-libaacplus \
 | 
			
		||||
        --enable-pthreads --extra-libs=-lpthread --enable-encoders --enable-decoders --enable-avfilter --enable-muxers --enable-demuxers && 
 | 
			
		||||
        --enable-pthreads --extra-libs=-lpthread \
 | 
			
		||||
        --enable-encoders --enable-decoders --enable-avfilter --enable-muxers --enable-demuxers && 
 | 
			
		||||
    make && make install
 | 
			
		||||
    ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build x264 failed"; exit 1; fi
 | 
			
		||||
    ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build ffmpeg failed"; exit 1; fi
 | 
			
		||||
fi
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,168 @@
 | 
			
		|||
# TODO: check gcc/g++
 | 
			
		||||
echo "check gcc/g++/gdb/make/openssl-devel"
 | 
			
		||||
echo "depends tools are ok"
 | 
			
		||||
#####################################################################################
 | 
			
		||||
# for Ubuntu
 | 
			
		||||
#####################################################################################
 | 
			
		||||
function Ubuntu_prepare()
 | 
			
		||||
{
 | 
			
		||||
    uname -v|grep Ubuntu >/dev/null 2>&1
 | 
			
		||||
    ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        return;
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "Ubuntu detected, install tools if needed"
 | 
			
		||||
    
 | 
			
		||||
    gcc --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install gcc"
 | 
			
		||||
        require_sudoer "sudo apt-get install -y gcc"
 | 
			
		||||
        sudo apt-get install -y gcc
 | 
			
		||||
        echo "install gcc success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    g++ --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install g++"
 | 
			
		||||
        require_sudoer "sudo apt-get install -y g++"
 | 
			
		||||
        sudo apt-get install -y g++
 | 
			
		||||
        echo "install g++ success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    make --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install make"
 | 
			
		||||
        require_sudoer "sudo apt-get install -y make"
 | 
			
		||||
        sudo apt-get install -y make
 | 
			
		||||
        echo "install make success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    autoconf --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install autoconf"
 | 
			
		||||
        require_sudoer "sudo apt-get install -y autoconf"
 | 
			
		||||
        sudo apt-get install -y autoconf
 | 
			
		||||
        echo "install autoconf success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    libtool --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install libtool"
 | 
			
		||||
        require_sudoer "sudo apt-get install -y libtool"
 | 
			
		||||
        sudo apt-get install -y libtool
 | 
			
		||||
        echo "install libtool success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if [[ ! -f /usr/include/pcre.h ]]; then
 | 
			
		||||
        echo "install libpcre3-dev"
 | 
			
		||||
        require_sudoer "sudo apt-get install -y libpcre3-dev"
 | 
			
		||||
        sudo apt-get install -y libpcre3-dev
 | 
			
		||||
        echo "install libpcre3-dev success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if [[ ! -f /usr/include/zlib.h ]]; then
 | 
			
		||||
        echo "install zlib1g-dev"
 | 
			
		||||
        require_sudoer "sudo apt-get install -y zlib1g-dev"
 | 
			
		||||
        sudo apt-get install -y zlib1g-dev
 | 
			
		||||
        echo "install zlib1g-dev success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if [[ ! -d /usr/include/freetype2 ]]; then
 | 
			
		||||
        echo "install libfreetype6-dev"
 | 
			
		||||
        require_sudoer "sudo apt-get install -y libfreetype6-dev"
 | 
			
		||||
        sudo apt-get install -y libfreetype6-dev
 | 
			
		||||
        echo "install libfreetype6-dev success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if [[ ! -d /usr/include/openssl ]]; then
 | 
			
		||||
        echo "install libssl-dev"
 | 
			
		||||
        require_sudoer "sudo apt-get install -y libssl-dev"
 | 
			
		||||
        sudo apt-get install -y libssl-dev
 | 
			
		||||
        echo "install libssl-dev success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    echo "Ubuntu install tools success"
 | 
			
		||||
}
 | 
			
		||||
Ubuntu_prepare
 | 
			
		||||
#####################################################################################
 | 
			
		||||
# for Centos
 | 
			
		||||
#####################################################################################
 | 
			
		||||
function Centos_prepare()
 | 
			
		||||
{
 | 
			
		||||
    if [[ ! -f /etc/redhat-release ]]; then
 | 
			
		||||
        return;
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "Centos detected, install tools if needed"
 | 
			
		||||
    
 | 
			
		||||
    gcc --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install gcc"
 | 
			
		||||
        require_sudoer "sudo yum install -y gcc"
 | 
			
		||||
        sudo yum install -y gcc
 | 
			
		||||
        echo "install gcc success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    g++ --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install gcc-c++"
 | 
			
		||||
        require_sudoer "sudo yum install -y gcc-c++"
 | 
			
		||||
        sudo yum install -y gcc-c++
 | 
			
		||||
        echo "install gcc-c++ success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    make --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install make"
 | 
			
		||||
        require_sudoer "sudo yum install -y make"
 | 
			
		||||
        sudo yum install -y make
 | 
			
		||||
        echo "install make success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    automake --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install automake"
 | 
			
		||||
        require_sudoer "sudo yum install -y automake"
 | 
			
		||||
        sudo yum install -y automake
 | 
			
		||||
        echo "install automake success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    autoconf --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install autoconf"
 | 
			
		||||
        require_sudoer "sudo yum install -y autoconf"
 | 
			
		||||
        sudo yum install -y autoconf
 | 
			
		||||
        echo "install autoconf success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    libtool --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
 | 
			
		||||
        echo "install libtool"
 | 
			
		||||
        require_sudoer "sudo yum install -y libtool"
 | 
			
		||||
        sudo yum install -y libtool
 | 
			
		||||
        echo "install libtool success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if [[ ! -f /usr/include/pcre.h ]]; then
 | 
			
		||||
        echo "install pcre-devel"
 | 
			
		||||
        require_sudoer "sudo yum install -y pcre-devel"
 | 
			
		||||
        sudo yum install -y pcre-devel
 | 
			
		||||
        echo "install pcre-devel success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if [[ ! -f /usr/include/zlib.h ]]; then
 | 
			
		||||
        echo "install zlib-devel"
 | 
			
		||||
        require_sudoer "sudo yum install -y zlib-devel"
 | 
			
		||||
        sudo yum install -y zlib-devel
 | 
			
		||||
        echo "install zlib-devel success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if [[ ! -d /usr/include/freetype2 ]]; then
 | 
			
		||||
        echo "install freetype-devel"
 | 
			
		||||
        require_sudoer "sudo yum install -y freetype-devel"
 | 
			
		||||
        sudo yum install -y freetype-devel
 | 
			
		||||
        echo "install freetype-devel success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if [[ ! -d /usr/include/openssl ]]; then
 | 
			
		||||
        echo "install openssl-devel"
 | 
			
		||||
        require_sudoer "sudo yum install -y openssl-devel"
 | 
			
		||||
        sudo yum install -y openssl-devel
 | 
			
		||||
        echo "install openssl-devel success"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    echo "Centos install tools success"
 | 
			
		||||
}
 | 
			
		||||
Centos_prepare
 | 
			
		||||
 | 
			
		||||
#####################################################################################
 | 
			
		||||
# st-1.9
 | 
			
		||||
| 
						 | 
				
			
			@ -48,6 +210,16 @@ fi
 | 
			
		|||
#####################################################################################
 | 
			
		||||
# nginx for HLS, nginx-1.5.0
 | 
			
		||||
#####################################################################################
 | 
			
		||||
function write_nginx_html5()
 | 
			
		||||
{
 | 
			
		||||
    cat<<END >> ${html_file}
 | 
			
		||||
<video width="640" height="360"
 | 
			
		||||
        autoplay controls autobuffer 
 | 
			
		||||
        src="${hls_stream}"
 | 
			
		||||
        type="application/vnd.apple.mpegurl">
 | 
			
		||||
</video>
 | 
			
		||||
END
 | 
			
		||||
}
 | 
			
		||||
if [ $SRS_HLS = YES ]; then
 | 
			
		||||
    if [[ -f ${SRS_OBJS}/nginx/sbin/nginx ]]; then
 | 
			
		||||
        echo "nginx-1.5.7 is ok.";
 | 
			
		||||
| 
						 | 
				
			
			@ -72,6 +244,17 @@ if [ $SRS_HLS = YES ]; then
 | 
			
		|||
    
 | 
			
		||||
    # create forward dir
 | 
			
		||||
    mkdir -p ${SRS_OBJS}/nginx/html/forward
 | 
			
		||||
    
 | 
			
		||||
    # generate default html pages for android.
 | 
			
		||||
    html_file=${SRS_OBJS}/nginx/html/live/livestream.html && hls_stream=livestream.m3u8 && write_nginx_html5
 | 
			
		||||
    html_file=${SRS_OBJS}/nginx/html/live/livestream_ld.html && hls_stream=livestream_ld.m3u8 && write_nginx_html5
 | 
			
		||||
    html_file=${SRS_OBJS}/nginx/html/live/livestream_sd.html && hls_stream=livestream_sd.m3u8 && write_nginx_html5
 | 
			
		||||
    html_file=${SRS_OBJS}/nginx/html/forward/live/livestream.html && hls_stream=livestream.m3u8 && write_nginx_html5
 | 
			
		||||
    html_file=${SRS_OBJS}/nginx/html/forward/live/livestream_ld.html && hls_stream=livestream_ld.m3u8 && write_nginx_html5
 | 
			
		||||
    html_file=${SRS_OBJS}/nginx/html/forward/live/livestream_sd.html && hls_stream=livestream_sd.m3u8 && write_nginx_html5
 | 
			
		||||
    
 | 
			
		||||
    # copy players to nginx html dir.
 | 
			
		||||
    cp research/players ${SRS_OBJS}/nginx/html/ -r
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ $SRS_HLS = YES ]; then
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +270,7 @@ if [ $SRS_HTTP = YES ]; then
 | 
			
		|||
    if [[ -f ${SRS_OBJS}/CherryPy-3.2.4/setup.py ]]; then
 | 
			
		||||
        echo "CherryPy-3.2.4 is ok.";
 | 
			
		||||
    else
 | 
			
		||||
        require_sudoer "configure --with-http"
 | 
			
		||||
        echo "install CherryPy-3.2.4"; 
 | 
			
		||||
        (
 | 
			
		||||
            sudo rm -rf ${SRS_OBJS}/CherryPy-3.2.4 && cd ${SRS_OBJS} && 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,14 @@
 | 
			
		|||
# the listen ports, split by space.
 | 
			
		||||
listen              1935;
 | 
			
		||||
<<<<<<< HEAD
 | 
			
		||||
=======
 | 
			
		||||
# the default chunk size is 128, max is 65536,
 | 
			
		||||
# some client does not support chunk size change,
 | 
			
		||||
# however, most clients supports it and it can improve 
 | 
			
		||||
# performance about 10%.
 | 
			
		||||
# default: 4096
 | 
			
		||||
chunk_size          65000;
 | 
			
		||||
>>>>>>> upstream/master
 | 
			
		||||
# the logs dir.
 | 
			
		||||
# if enabled ffmpeg, each stracoding stream will create a log file.
 | 
			
		||||
# default: ./objs/logs
 | 
			
		||||
| 
						 | 
				
			
			@ -21,14 +30,26 @@ vhost __defaultVhost__ {
 | 
			
		|||
	chunk_size		65000;
 | 
			
		||||
    enabled         on;
 | 
			
		||||
    gop_cache       on;
 | 
			
		||||
    hls             on;
 | 
			
		||||
    hls_path        ./objs/nginx/html;
 | 
			
		||||
    hls_fragment    5;
 | 
			
		||||
    hls_window      30;
 | 
			
		||||
    queue_length    30;
 | 
			
		||||
    forward         127.0.0.1:19350;
 | 
			
		||||
    hls {
 | 
			
		||||
        enabled         on;
 | 
			
		||||
        hls_path        ./objs/nginx/html;
 | 
			
		||||
        hls_fragment    5;
 | 
			
		||||
        hls_window      30;
 | 
			
		||||
    }
 | 
			
		||||
    http_hooks {
 | 
			
		||||
        enabled         off;
 | 
			
		||||
        on_connect      http://127.0.0.1:8085/api/v1/clients;
 | 
			
		||||
        on_close        http://127.0.0.1:8085/api/v1/clients;
 | 
			
		||||
        on_publish      http://127.0.0.1:8085/api/v1/streams;
 | 
			
		||||
        on_unpublish    http://127.0.0.1:8085/api/v1/streams;
 | 
			
		||||
        on_play         http://127.0.0.1:8085/api/v1/sessions;
 | 
			
		||||
        on_stop         http://127.0.0.1:8085/api/v1/sessions;
 | 
			
		||||
    }
 | 
			
		||||
    transcode {
 | 
			
		||||
        enabled     on;
 | 
			
		||||
        ffmpeg      ./objs/ffmpeg/bin/ffmpeg;
 | 
			
		||||
        enabled         on;
 | 
			
		||||
        ffmpeg          ./objs/ffmpeg/bin/ffmpeg;
 | 
			
		||||
        engine ld {
 | 
			
		||||
            enabled         on;
 | 
			
		||||
            vfilter {
 | 
			
		||||
| 
						 | 
				
			
			@ -82,11 +103,17 @@ vhost dev {
 | 
			
		|||
	chunk_size		65000;
 | 
			
		||||
    enabled         on;
 | 
			
		||||
    gop_cache       on;
 | 
			
		||||
    hls             on;
 | 
			
		||||
    hls_path        ./objs/nginx/html;
 | 
			
		||||
    hls_fragment    5;
 | 
			
		||||
    hls_window      30;
 | 
			
		||||
    queue_length    10;
 | 
			
		||||
    forward         127.0.0.1:19350;
 | 
			
		||||
<<<<<<< HEAD
 | 
			
		||||
=======
 | 
			
		||||
    hls {
 | 
			
		||||
        enabled         on;
 | 
			
		||||
        hls_path        ./objs/nginx/html;
 | 
			
		||||
        hls_fragment    5;
 | 
			
		||||
        hls_window      30;
 | 
			
		||||
    }
 | 
			
		||||
>>>>>>> upstream/master
 | 
			
		||||
    http_hooks {
 | 
			
		||||
        enabled         off;
 | 
			
		||||
        on_connect      http://127.0.0.1:8085/api/v1/clients;
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +124,7 @@ vhost dev {
 | 
			
		|||
        on_stop         http://127.0.0.1:8085/api/v1/sessions;
 | 
			
		||||
    }
 | 
			
		||||
    transcode {
 | 
			
		||||
        enabled     on;
 | 
			
		||||
        enabled     off;
 | 
			
		||||
        ffmpeg      ./objs/ffmpeg/bin/ffmpeg;
 | 
			
		||||
        engine dev {
 | 
			
		||||
            enabled         on;
 | 
			
		||||
| 
						 | 
				
			
			@ -641,36 +668,40 @@ vhost removed.vhost.com {
 | 
			
		|||
    enabled         off;
 | 
			
		||||
}
 | 
			
		||||
# the vhost with hls specified.
 | 
			
		||||
vhost no-hls.vhost.com {
 | 
			
		||||
    # whether the hls is enabled.
 | 
			
		||||
    # if off, donot write hls(ts and m3u8) when publish.
 | 
			
		||||
    # default: on
 | 
			
		||||
    hls             on;
 | 
			
		||||
    # the hls output path.
 | 
			
		||||
    # the app dir is auto created under the hls_path.
 | 
			
		||||
    # for example, for rtmp stream:
 | 
			
		||||
    #   rtmp://127.0.0.1/live/livestream
 | 
			
		||||
    #   http://127.0.0.1/live/livestream.m3u8
 | 
			
		||||
    # where hls_path is /hls, srs will create the following files:
 | 
			
		||||
    #   /hls/live       the app dir for all streams.
 | 
			
		||||
    #   /hls/live/livestream.m3u8   the HLS m3u8 file.
 | 
			
		||||
    #   /hls/live/livestream-1.ts   the HLS media/ts file.
 | 
			
		||||
    # in a word, the hls_path is for vhost.
 | 
			
		||||
    # default: ./objs/nginx/html
 | 
			
		||||
    hls_path        /data/nginx/html;
 | 
			
		||||
    # the hls fragment in seconds, the duration of a piece of ts.
 | 
			
		||||
    # default: 10
 | 
			
		||||
    hls_fragment    10;
 | 
			
		||||
    # the hls window in seconds, the number of ts in m3u8.
 | 
			
		||||
    # default: 60
 | 
			
		||||
    hls_window      60;
 | 
			
		||||
vhost with-hls.vhost.com {
 | 
			
		||||
    hls {
 | 
			
		||||
        # whether the hls is enabled.
 | 
			
		||||
        # if off, donot write hls(ts and m3u8) when publish.
 | 
			
		||||
        # default: off
 | 
			
		||||
        enabled         on;
 | 
			
		||||
        # the hls output path.
 | 
			
		||||
        # the app dir is auto created under the hls_path.
 | 
			
		||||
        # for example, for rtmp stream:
 | 
			
		||||
        #   rtmp://127.0.0.1/live/livestream
 | 
			
		||||
        #   http://127.0.0.1/live/livestream.m3u8
 | 
			
		||||
        # where hls_path is /hls, srs will create the following files:
 | 
			
		||||
        #   /hls/live       the app dir for all streams.
 | 
			
		||||
        #   /hls/live/livestream.m3u8   the HLS m3u8 file.
 | 
			
		||||
        #   /hls/live/livestream-1.ts   the HLS media/ts file.
 | 
			
		||||
        # in a word, the hls_path is for vhost.
 | 
			
		||||
        # default: ./objs/nginx/html
 | 
			
		||||
        hls_path        /data/nginx/html;
 | 
			
		||||
        # the hls fragment in seconds, the duration of a piece of ts.
 | 
			
		||||
        # default: 10
 | 
			
		||||
        hls_fragment    10;
 | 
			
		||||
        # the hls window in seconds, the number of ts in m3u8.
 | 
			
		||||
        # default: 60
 | 
			
		||||
        hls_window      60;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
# the vhost with hls disabled.
 | 
			
		||||
vhost no-hls.vhost.com {
 | 
			
		||||
    # whether the hls is enabled.
 | 
			
		||||
    # if off, donot write hls(ts and m3u8) when publish.
 | 
			
		||||
    # default: on
 | 
			
		||||
    hls             off;
 | 
			
		||||
    hls {
 | 
			
		||||
        # whether the hls is enabled.
 | 
			
		||||
        # if off, donot write hls(ts and m3u8) when publish.
 | 
			
		||||
        # default: off
 | 
			
		||||
        enabled         off;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
# the vhost for min delay, donot cache any stream.
 | 
			
		||||
vhost min.delay.com {
 | 
			
		||||
| 
						 | 
				
			
			@ -683,6 +714,11 @@ vhost min.delay.com {
 | 
			
		|||
    # set to on if requires client fast startup.
 | 
			
		||||
    # default: on
 | 
			
		||||
    gop_cache       off;
 | 
			
		||||
    # the max live queue length in seconds.
 | 
			
		||||
    # if the messages in the queue exceed the max length, 
 | 
			
		||||
    # drop the old whole gop.
 | 
			
		||||
    # default: 30
 | 
			
		||||
    queue_length    10;
 | 
			
		||||
}
 | 
			
		||||
# the vhost for antisuck.
 | 
			
		||||
vhost refer.anti_suck.com {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								trunk/configure
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								trunk/configure
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -15,14 +15,15 @@ BLACK="\\e[0m"
 | 
			
		|||
# parse user options.
 | 
			
		||||
. auto/options.sh
 | 
			
		||||
 | 
			
		||||
# if specifies http, requires sudo to install the CherryPy.
 | 
			
		||||
if [ $SRS_HTTP = YES ]; then
 | 
			
		||||
function require_sudoer()
 | 
			
		||||
{
 | 
			
		||||
    sudo echo "" >/dev/null 2>&1
 | 
			
		||||
    ret=$?; if [[ 0 -ne $ret ]]; then echo 
 | 
			
		||||
        "--with-http requires sudoer, ret=$ret"; 
 | 
			
		||||
    
 | 
			
		||||
    ret=$?; if [[ 0 -ne $ret ]]; then 
 | 
			
		||||
        echo "\"$1\" require sudoer failed. ret=$ret";
 | 
			
		||||
        exit $ret; 
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# clean the exists
 | 
			
		||||
if [[ -f Makefile ]]; then
 | 
			
		||||
| 
						 | 
				
			
			@ -56,11 +57,11 @@ help:
 | 
			
		|||
	@echo "  server     build the srs(simple rtmp server) over st(state-threads)"
 | 
			
		||||
 | 
			
		||||
clean: 
 | 
			
		||||
	(rm -f Makefile; cd ${SRS_OBJS}; rm -rf Makefile *.hpp src st_*_load)
 | 
			
		||||
	(rm -f Makefile; cd ${SRS_OBJS}; rm -rf srs Makefile *.hpp src st_*_load)
 | 
			
		||||
 | 
			
		||||
server: _prepare_dir
 | 
			
		||||
	@echo "build the srs(simple rtmp server) over st(state-threads)"
 | 
			
		||||
	\$(MAKE) -f ${SRS_OBJS}/${SRS_MAKEFILE} simple_rtmp_server
 | 
			
		||||
	\$(MAKE) -f ${SRS_OBJS}/${SRS_MAKEFILE} srs
 | 
			
		||||
 | 
			
		||||
# the ./configure will generate it.
 | 
			
		||||
_prepare_dir:
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +87,7 @@ GCC = g++
 | 
			
		|||
LINK = \$(GCC)
 | 
			
		||||
AR = ar
 | 
			
		||||
 | 
			
		||||
.PHONY: default simple_rtmp_server 
 | 
			
		||||
.PHONY: default srs 
 | 
			
		||||
 | 
			
		||||
default:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +116,7 @@ MODULE_FILES=("srs_core" "srs_core_log" "srs_core_server"
 | 
			
		|||
        "srs_core_handshake" "srs_core_pithy_print"
 | 
			
		||||
        "srs_core_config" "srs_core_refer" "srs_core_reload"
 | 
			
		||||
        "srs_core_hls" "srs_core_forward" "srs_core_encoder"
 | 
			
		||||
        "srs_core_http")
 | 
			
		||||
        "srs_core_http" "srs_core_thread")
 | 
			
		||||
MODULE_DIR="src/core" . auto/modules.sh
 | 
			
		||||
CORE_OBJS="${MODULE_OBJS[@]}"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +142,7 @@ if [ $SRS_SSL = YES ]; then
 | 
			
		|||
else
 | 
			
		||||
    LINK_OPTIONS="-ldl"
 | 
			
		||||
fi
 | 
			
		||||
BUILD_KEY="simple_rtmp_server" APP_MAIN="srs_main_server" APP_NAME="simple_rtmp_server" SO_PATH="" . auto/apps.sh
 | 
			
		||||
BUILD_KEY="srs" APP_MAIN="srs_main_server" APP_NAME="srs" SO_PATH="" . auto/apps.sh
 | 
			
		||||
 | 
			
		||||
echo 'configure ok! '
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -179,6 +180,7 @@ echo "\" make \" to build the srs(simple rtmp server)."
 | 
			
		|||
echo "\" make help \" to get the usage of make"
 | 
			
		||||
if [ $SRS_HLS = YES ]; then
 | 
			
		||||
    echo "\" sudo ./objs/nginx/sbin/nginx  \" to start the nginx http server for hls"
 | 
			
		||||
    echo "\" http://demo:80/players \" rtmp players(OSMF/JWPlayer)"
 | 
			
		||||
fi
 | 
			
		||||
if [ $SRS_FFMPEG = YES ]; then
 | 
			
		||||
    echo -e "\" ./objs/ffmpeg/bin/ffmpeg  \" is used for live stream transcoding"
 | 
			
		||||
| 
						 | 
				
			
			@ -186,4 +188,4 @@ fi
 | 
			
		|||
if [ $SRS_HTTP = YES ]; then
 | 
			
		||||
    echo -e "\" python ./research/api-server/server.py 8085  \" to start the api-server"
 | 
			
		||||
fi
 | 
			
		||||
echo "\" ./objs/simple_rtmp_server -c conf/srs.conf \" to start the srs live server"
 | 
			
		||||
echo "\" ./objs/srs -c conf/srs.conf \" to start the srs live server"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								trunk/research/players/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										1
									
								
								trunk/research/players/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							| 
						 | 
				
			
			@ -9,4 +9,5 @@
 | 
			
		|||
    <p><a href="osmf/index.html">OSMF播放器</a></p>
 | 
			
		||||
    <p><a href="jwplayer5/index.html">JWPlayer5</a></p>
 | 
			
		||||
    <p><a href="jwplayer6/index.html">JWPlayer6</a></p>
 | 
			
		||||
    <p><a href="http://www.videolan.org/vlc/">VLC for HLS/rtmp/rtsp/http....</a></p>
 | 
			
		||||
</body>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								trunk/research/players/jwplayer5/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										2
									
								
								trunk/research/players/jwplayer5/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
<div class="main">
 | 
			
		||||
    <div id="player"></div>
 | 
			
		||||
    <div class="control" id="control">
 | 
			
		||||
        Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://dev:1935/live/livestream"></input>
 | 
			
		||||
        Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://demo:1935/live/livestream"></input>
 | 
			
		||||
        <input type="button" class="play" value="Play" onclick="play()"></input>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								trunk/research/players/jwplayer6/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										2
									
								
								trunk/research/players/jwplayer6/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
<div class="main">
 | 
			
		||||
    <div id="player"></div>
 | 
			
		||||
    <div class="control" id="control">
 | 
			
		||||
        Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://dev:1935/live/livestream"></input>
 | 
			
		||||
        Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://demo:1935/live/livestream"></input>
 | 
			
		||||
        <input type="button" class="play" value="Play" onclick="play()"></input>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								trunk/research/players/osmf/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										2
									
								
								trunk/research/players/osmf/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							| 
						 | 
				
			
			@ -19,7 +19,7 @@ div.control{padding-bottom:10px; background-color:#333333; }
 | 
			
		|||
<div class="main" id="main">
 | 
			
		||||
    <div id="player" class="player"></div>
 | 
			
		||||
    <div class="control" id="control">
 | 
			
		||||
        Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://dev:1935/live/livestream"></input>
 | 
			
		||||
        Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://demo:1935/live/livestream"></input>
 | 
			
		||||
        <select class="type" id="type">
 | 
			
		||||
            <option value="live" selected>live</option>
 | 
			
		||||
            <option value="recorded">vod</option>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										
											BIN
										
									
								
								trunk/research/players/rtmp/RtmpPlayer.swf
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								trunk/research/players/rtmp/RtmpPlayer.swf
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								trunk/research/players/rtmp/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										2
									
								
								trunk/research/players/rtmp/index.html
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							| 
						 | 
				
			
			@ -21,7 +21,7 @@
 | 
			
		|||
<script type="text/javascript">
 | 
			
		||||
    var o = new RtmpPlayer("player", "RtmpPlayer.swf", 1350, 1050);
 | 
			
		||||
 | 
			
		||||
    o.setRtmpUrl("rtmp://dev:1935/live/livestream");
 | 
			
		||||
    o.setRtmpUrl("rtmp://demo:1935/live/livestream");
 | 
			
		||||
    o.admin = "admin";
 | 
			
		||||
    o.password = "123456";
 | 
			
		||||
    o.loop = false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -111,3 +111,17 @@ void srs_vhost_resolve(std::string& vhost, std::string& app)
 | 
			
		|||
		}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void srs_close_stfd(st_netfd_t& stfd)
 | 
			
		||||
{
 | 
			
		||||
	if (stfd) {
 | 
			
		||||
		int fd = st_netfd_fileno(stfd);
 | 
			
		||||
		st_netfd_close(stfd);
 | 
			
		||||
		stfd = NULL;
 | 
			
		||||
		
 | 
			
		||||
		// st does not close it sometimes, 
 | 
			
		||||
		// close it manually.
 | 
			
		||||
		close(fd);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <stddef.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
 | 
			
		||||
// generated by configure.
 | 
			
		||||
#include <srs_auto_headers.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -102,4 +104,7 @@ extern std::string srs_dns_resolve(std::string host);
 | 
			
		|||
//		app...vhost...request_vhost
 | 
			
		||||
extern void srs_vhost_resolve(std::string& vhost, std::string& app);
 | 
			
		||||
 | 
			
		||||
// close the netfd, and close the underlayer fd.
 | 
			
		||||
extern void srs_close_stfd(st_netfd_t& stfd);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <arpa/inet.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
#include <srs_core_error.hpp>
 | 
			
		||||
#include <srs_core_log.hpp>
 | 
			
		||||
#include <srs_core_rtmp.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -55,10 +57,14 @@ SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd)
 | 
			
		|||
#ifdef SRS_HTTP	
 | 
			
		||||
	http_hooks = new SrsHttpHooks();
 | 
			
		||||
#endif
 | 
			
		||||
	
 | 
			
		||||
	config->subscribe(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsClient::~SrsClient()
 | 
			
		||||
{
 | 
			
		||||
	config->unsubscribe(this);
 | 
			
		||||
	
 | 
			
		||||
	srs_freepa(ip);
 | 
			
		||||
	srs_freep(req);
 | 
			
		||||
	srs_freep(res);
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +119,23 @@ int SrsClient::do_cycle()
 | 
			
		|||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsClient::on_reload_vhost_removed(string vhost)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if (req->vhost != vhost) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// if the vhost connected is removed, disconnect the client.
 | 
			
		||||
	srs_trace("vhost %s removed/disabled, close client url=%s", 
 | 
			
		||||
		vhost.c_str(), req->get_stream_url().c_str());
 | 
			
		||||
		
 | 
			
		||||
	srs_close_stfd(stfd);
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
	
 | 
			
		||||
int SrsClient::service_cycle()
 | 
			
		||||
{	
 | 
			
		||||
| 
						 | 
				
			
			@ -180,11 +203,7 @@ int SrsClient::service_cycle()
 | 
			
		|||
	req->strip();
 | 
			
		||||
	srs_trace("identify client success. type=%d, stream_name=%s", type, req->stream.c_str());
 | 
			
		||||
	
 | 
			
		||||
	int chunk_size = 4096;
 | 
			
		||||
    SrsConfDirective* conf = config->get_chunk_size(req->vhost);
 | 
			
		||||
	if (conf && !conf->arg0().empty()) {
 | 
			
		||||
		chunk_size = ::atoi(conf->arg0().c_str());
 | 
			
		||||
	}
 | 
			
		||||
	int chunk_size = config->get_chunk_size();
 | 
			
		||||
	if ((ret = rtmp->set_chunk_size(chunk_size)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("set chunk_size=%d failed. ret=%d", chunk_size, ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -192,7 +211,7 @@ int SrsClient::service_cycle()
 | 
			
		|||
	srs_trace("set chunk_size=%d success", chunk_size);
 | 
			
		||||
	
 | 
			
		||||
	// find a source to publish.
 | 
			
		||||
	SrsSource* source = SrsSource::find(req->get_stream_url());
 | 
			
		||||
	SrsSource* source = SrsSource::find(req);
 | 
			
		||||
	srs_assert(source != NULL);
 | 
			
		||||
	
 | 
			
		||||
	// check publish available.
 | 
			
		||||
| 
						 | 
				
			
			@ -205,14 +224,9 @@ int SrsClient::service_cycle()
 | 
			
		|||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	bool enabled_cache = true;
 | 
			
		||||
	conf = config->get_gop_cache(req->vhost);
 | 
			
		||||
	if (conf && conf->arg0() == "off") {
 | 
			
		||||
		enabled_cache = false;
 | 
			
		||||
	}
 | 
			
		||||
	source->set_cache(enabled_cache);
 | 
			
		||||
 | 
			
		||||
	bool enabled_cache = config->get_gop_cache(req->vhost);
 | 
			
		||||
	srs_info("source found, url=%s, enabled_cache=%d", req->get_stream_url().c_str(), enabled_cache);
 | 
			
		||||
	source->set_cache(enabled_cache);
 | 
			
		||||
	
 | 
			
		||||
	switch (type) {
 | 
			
		||||
		case SrsClientPlay: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <srs_core.hpp>
 | 
			
		||||
 | 
			
		||||
#include <srs_core_conn.hpp>
 | 
			
		||||
#include <srs_core_reload.hpp>
 | 
			
		||||
 | 
			
		||||
class SrsRtmp;
 | 
			
		||||
class SrsRequest;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +47,7 @@ class SrsHttpHooks;
 | 
			
		|||
/**
 | 
			
		||||
* the client provides the main logic control for RTMP clients.
 | 
			
		||||
*/
 | 
			
		||||
class SrsClient : public SrsConnection
 | 
			
		||||
class SrsClient : public SrsConnection, public ISrsReloadHandler
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	char* ip;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,6 +63,9 @@ public:
 | 
			
		|||
	virtual ~SrsClient();
 | 
			
		||||
protected:
 | 
			
		||||
	virtual int do_cycle();
 | 
			
		||||
// interface ISrsReloadHandler
 | 
			
		||||
public:
 | 
			
		||||
	virtual int on_reload_vhost_removed(std::string vhost);
 | 
			
		||||
private:
 | 
			
		||||
	// when valid and connected to vhost/app, service the client.
 | 
			
		||||
	virtual int service_cycle();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -48,25 +48,20 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#define SRS_CONF_DEFAULT_AAC_SYNC 100
 | 
			
		||||
// in ms, for HLS aac flush the audio
 | 
			
		||||
#define SRS_CONF_DEFAULT_AAC_DELAY 300
 | 
			
		||||
// in seconds, the live queue length.
 | 
			
		||||
#define SRS_CONF_DEFAULT_QUEUE_LENGTH 30
 | 
			
		||||
// in seconds, the paused queue length.
 | 
			
		||||
#define SRS_CONF_DEFAULT_PAUSED_LENGTH 10
 | 
			
		||||
 | 
			
		||||
class SrsFileBuffer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	int fd;
 | 
			
		||||
	int line;
 | 
			
		||||
	// start of buffer.
 | 
			
		||||
	char* start;
 | 
			
		||||
	// end of buffer.
 | 
			
		||||
	char* end;
 | 
			
		||||
	// current consumed position.
 | 
			
		||||
	char* pos;
 | 
			
		||||
	// last available position.
 | 
			
		||||
	char* last;
 | 
			
		||||
	
 | 
			
		||||
	SrsFileBuffer();
 | 
			
		||||
	virtual ~SrsFileBuffer();
 | 
			
		||||
	virtual int open(const char* filename);
 | 
			
		||||
};
 | 
			
		||||
#define SRS_CONF_DEFAULT_CHUNK_SIZE 4096
 | 
			
		||||
 | 
			
		||||
#define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300
 | 
			
		||||
#define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100
 | 
			
		||||
#define SRS_STAGE_FORWARDER_INTERVAL_MS 2000
 | 
			
		||||
#define SRS_STAGE_ENCODER_INTERVAL_MS 2000
 | 
			
		||||
#define SRS_STAGE_HLS_INTERVAL_MS 2000
 | 
			
		||||
 | 
			
		||||
class SrsFileBuffer;
 | 
			
		||||
 | 
			
		||||
class SrsConfDirective
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -83,13 +78,13 @@ public:
 | 
			
		|||
	std::string arg2();
 | 
			
		||||
	SrsConfDirective* at(int index);
 | 
			
		||||
	SrsConfDirective* get(std::string _name);
 | 
			
		||||
	SrsConfDirective* get(std::string _name, std::string _arg0);
 | 
			
		||||
public:
 | 
			
		||||
	virtual int parse(const char* filename);
 | 
			
		||||
public:
 | 
			
		||||
	enum SrsDirectiveType{parse_file, parse_block};
 | 
			
		||||
	virtual int parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type);
 | 
			
		||||
	virtual int read_token(SrsFileBuffer* buffer, std::vector<std::string>& args);
 | 
			
		||||
	virtual int refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -106,71 +101,76 @@ private:
 | 
			
		|||
	bool show_version;
 | 
			
		||||
	std::string config_file;
 | 
			
		||||
	SrsConfDirective* root;
 | 
			
		||||
	std::vector<SrsReloadHandler*> subscribes;
 | 
			
		||||
	std::vector<ISrsReloadHandler*> subscribes;
 | 
			
		||||
public:
 | 
			
		||||
	SrsConfig();
 | 
			
		||||
	virtual ~SrsConfig();
 | 
			
		||||
public:
 | 
			
		||||
	virtual int reload();
 | 
			
		||||
	virtual void subscribe(SrsReloadHandler* handler);
 | 
			
		||||
	virtual void unsubscribe(SrsReloadHandler* handler);
 | 
			
		||||
	virtual void subscribe(ISrsReloadHandler* handler);
 | 
			
		||||
	virtual void unsubscribe(ISrsReloadHandler* handler);
 | 
			
		||||
public:
 | 
			
		||||
	virtual int parse_options(int argc, char** argv);
 | 
			
		||||
public:
 | 
			
		||||
    virtual SrsConfDirective* get_vhost(const std::string &vhost);
 | 
			
		||||
    virtual bool    		  get_vhost_enabled(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_vhost_on_connect(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_vhost_on_close(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_vhost_on_publish(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_vhost_on_unpublish(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_vhost_on_play(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_vhost_on_stop(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_transcode(const std::string& vhost, const std::string& scope);
 | 
			
		||||
	virtual bool    		  get_transcode_enabled(SrsConfDirective* transcode);
 | 
			
		||||
	virtual std::string		  get_transcode_ffmpeg(SrsConfDirective* transcode);
 | 
			
		||||
	virtual void 			  get_transcode_engines(SrsConfDirective* transcode, std::vector<SrsConfDirective*>& engines);
 | 
			
		||||
	virtual bool    		  get_engine_enabled(SrsConfDirective* engine);
 | 
			
		||||
	virtual std::string 	  get_engine_vcodec(SrsConfDirective* engine);
 | 
			
		||||
	virtual int		     	  get_engine_vbitrate(SrsConfDirective* engine);
 | 
			
		||||
	virtual double	     	  get_engine_vfps(SrsConfDirective* engine);
 | 
			
		||||
	virtual int		     	  get_engine_vwidth(SrsConfDirective* engine);
 | 
			
		||||
	virtual int		     	  get_engine_vheight(SrsConfDirective* engine);
 | 
			
		||||
	virtual int		     	  get_engine_vthreads(SrsConfDirective* engine);
 | 
			
		||||
	virtual std::string 	  get_engine_vprofile(SrsConfDirective* engine);
 | 
			
		||||
	virtual std::string 	  get_engine_vpreset(SrsConfDirective* engine);
 | 
			
		||||
	virtual void		 	  get_engine_vparams(SrsConfDirective* engine, std::vector<std::string>& vparams);
 | 
			
		||||
	virtual void		 	  get_engine_vfilter(SrsConfDirective* engine, std::vector<std::string>& vfilter);
 | 
			
		||||
	virtual std::string 	  get_engine_acodec(SrsConfDirective* engine);
 | 
			
		||||
	virtual int		     	  get_engine_abitrate(SrsConfDirective* engine);
 | 
			
		||||
	virtual int		     	  get_engine_asample_rate(SrsConfDirective* engine);
 | 
			
		||||
	virtual int		     	  get_engine_achannels(SrsConfDirective* engine);
 | 
			
		||||
	virtual void			  get_engine_aparams(SrsConfDirective* engine, std::vector<std::string>& aparams);
 | 
			
		||||
	virtual std::string 	  get_engine_output(SrsConfDirective* engine);
 | 
			
		||||
	virtual std::string 	  get_log_dir();
 | 
			
		||||
	virtual int			 	  get_max_connections();
 | 
			
		||||
    virtual SrsConfDirective* get_gop_cache(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_forward(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_hls(const std::string &vhost);
 | 
			
		||||
    virtual bool    		  get_hls_enabled(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_hls_path(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_hls_fragment(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_hls_window(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_refer(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_refer_play(const std::string& vhost);
 | 
			
		||||
    virtual SrsConfDirective* get_refer_publish(const std::string& vhost);
 | 
			
		||||
	virtual SrsConfDirective* get_listen();
 | 
			
		||||
    virtual SrsConfDirective* get_chunk_size(const std::string &vhost);
 | 
			
		||||
	virtual SrsConfDirective* get_pithy_print_publish();
 | 
			
		||||
	virtual SrsConfDirective* get_pithy_print_forwarder();
 | 
			
		||||
	virtual SrsConfDirective* get_pithy_print_encoder();
 | 
			
		||||
	virtual SrsConfDirective* get_pithy_print_hls();
 | 
			
		||||
	virtual SrsConfDirective* get_pithy_print_play();
 | 
			
		||||
    virtual bool              get_bw_check_enabled(const std::string &vhost, const std::string &key);
 | 
			
		||||
    virtual void              get_bw_check_settings(const std::string &vhost, int64_t &interval_ms, int &play_kbps, int &pub_kbps);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	virtual int parse_file(const char* filename);
 | 
			
		||||
	virtual int parse_argv(int& i, char** argv);
 | 
			
		||||
	virtual void print_help(char** argv);
 | 
			
		||||
public:
 | 
			
		||||
	virtual SrsConfDirective* 	get_vhost(std::string vhost);
 | 
			
		||||
	virtual bool    		  	get_vhost_enabled(std::string vhost);
 | 
			
		||||
	virtual bool    		  	get_vhost_enabled(SrsConfDirective* vhost);
 | 
			
		||||
	virtual SrsConfDirective* 	get_vhost_on_connect(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective* 	get_vhost_on_close(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective* 	get_vhost_on_publish(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective* 	get_vhost_on_unpublish(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective* 	get_vhost_on_play(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective* 	get_vhost_on_stop(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective* 	get_transcode(std::string vhost, std::string scope);
 | 
			
		||||
	virtual bool    		  	get_transcode_enabled(SrsConfDirective* transcode);
 | 
			
		||||
	virtual std::string			get_transcode_ffmpeg(SrsConfDirective* transcode);
 | 
			
		||||
	virtual void				get_transcode_engines(SrsConfDirective* transcode, std::vector<SrsConfDirective*>& engines);
 | 
			
		||||
	virtual bool				get_engine_enabled(SrsConfDirective* engine);
 | 
			
		||||
	virtual std::string			get_engine_vcodec(SrsConfDirective* engine);
 | 
			
		||||
	virtual int					get_engine_vbitrate(SrsConfDirective* engine);
 | 
			
		||||
	virtual double				get_engine_vfps(SrsConfDirective* engine);
 | 
			
		||||
	virtual int					get_engine_vwidth(SrsConfDirective* engine);
 | 
			
		||||
	virtual int					get_engine_vheight(SrsConfDirective* engine);
 | 
			
		||||
	virtual int					get_engine_vthreads(SrsConfDirective* engine);
 | 
			
		||||
	virtual std::string			get_engine_vprofile(SrsConfDirective* engine);
 | 
			
		||||
	virtual std::string			get_engine_vpreset(SrsConfDirective* engine);
 | 
			
		||||
	virtual void				get_engine_vparams(SrsConfDirective* engine, std::vector<std::string>& vparams);
 | 
			
		||||
	virtual void				get_engine_vfilter(SrsConfDirective* engine, std::vector<std::string>& vfilter);
 | 
			
		||||
	virtual std::string			get_engine_acodec(SrsConfDirective* engine);
 | 
			
		||||
	virtual int					get_engine_abitrate(SrsConfDirective* engine);
 | 
			
		||||
	virtual int					get_engine_asample_rate(SrsConfDirective* engine);
 | 
			
		||||
	virtual int					get_engine_achannels(SrsConfDirective* engine);
 | 
			
		||||
	virtual void				get_engine_aparams(SrsConfDirective* engine, std::vector<std::string>& aparams);
 | 
			
		||||
	virtual std::string			get_engine_output(SrsConfDirective* engine);
 | 
			
		||||
	virtual std::string			get_log_dir();
 | 
			
		||||
	virtual int					get_max_connections();
 | 
			
		||||
	virtual bool				get_gop_cache(std::string vhost);
 | 
			
		||||
	virtual double				get_queue_length(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective*	get_forward(std::string vhost);
 | 
			
		||||
private:
 | 
			
		||||
	virtual SrsConfDirective*	get_hls(std::string vhost);
 | 
			
		||||
public:
 | 
			
		||||
	virtual bool				get_hls_enabled(std::string vhost);
 | 
			
		||||
	virtual std::string			get_hls_path(std::string vhost);
 | 
			
		||||
	virtual double				get_hls_fragment(std::string vhost);
 | 
			
		||||
	virtual double				get_hls_window(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective*	get_refer(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective*	get_refer_play(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective*	get_refer_publish(std::string vhost);
 | 
			
		||||
	virtual SrsConfDirective*	get_listen();
 | 
			
		||||
	virtual int					get_chunk_size();
 | 
			
		||||
	virtual int					get_pithy_print_publish();
 | 
			
		||||
	virtual int					get_pithy_print_forwarder();
 | 
			
		||||
	virtual int					get_pithy_print_encoder();
 | 
			
		||||
	virtual int					get_pithy_print_hls();
 | 
			
		||||
	virtual int					get_pithy_print_play();
 | 
			
		||||
    virtual bool                get_bw_check_enabled(const std::string &vhost, const std::string &key);
 | 
			
		||||
    virtual void                get_bw_check_settings(const std::string &vhost, int64_t &interval_ms, int &play_kbps, int &pub_kbps);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,15 +36,7 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd)
 | 
			
		|||
 | 
			
		||||
SrsConnection::~SrsConnection()
 | 
			
		||||
{
 | 
			
		||||
	if (stfd) {
 | 
			
		||||
		int fd = st_netfd_fileno(stfd);
 | 
			
		||||
		st_netfd_close(stfd);
 | 
			
		||||
		stfd = NULL;
 | 
			
		||||
		
 | 
			
		||||
		// st does not close it sometimes, 
 | 
			
		||||
		// close it manually.
 | 
			
		||||
		close(fd);
 | 
			
		||||
	}
 | 
			
		||||
	srs_close_stfd(stfd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsConnection::start()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,8 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
 | 
			
		||||
#include <srs_core.hpp>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
 | 
			
		||||
class SrsServer;
 | 
			
		||||
class SrsConnection
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -483,13 +483,103 @@ void SrsFFMPEG::stop()
 | 
			
		|||
 | 
			
		||||
SrsEncoder::SrsEncoder()
 | 
			
		||||
{
 | 
			
		||||
	tid = NULL;
 | 
			
		||||
	loop = false;
 | 
			
		||||
	pthread = new SrsThread(this, SRS_ENCODER_SLEEP_MS);
 | 
			
		||||
	pithy_print = new SrsPithyPrint(SRS_STAGE_ENCODER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsEncoder::~SrsEncoder()
 | 
			
		||||
{
 | 
			
		||||
	on_unpublish();
 | 
			
		||||
	
 | 
			
		||||
	srs_freep(pthread);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsEncoder::on_publish(SrsRequest* req)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	ret = parse_scope_engines(req);
 | 
			
		||||
	
 | 
			
		||||
	// ignore the loop encoder
 | 
			
		||||
	if (ret == ERROR_ENCODER_LOOP) {
 | 
			
		||||
		clear_engines();
 | 
			
		||||
		ret = ERROR_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// return for error or no engine.
 | 
			
		||||
	if (ret != ERROR_SUCCESS || ffmpegs.empty()) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
    
 | 
			
		||||
    // start thread to run all encoding engines.
 | 
			
		||||
    if ((ret = pthread->start()) != ERROR_SUCCESS) {
 | 
			
		||||
        srs_error("st_thread_create failed. ret=%d", ret);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsEncoder::on_unpublish()
 | 
			
		||||
{
 | 
			
		||||
	pthread->stop();
 | 
			
		||||
	clear_engines();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsEncoder::cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	std::vector<SrsFFMPEG*>::iterator it;
 | 
			
		||||
	for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
 | 
			
		||||
		SrsFFMPEG* ffmpeg = *it;
 | 
			
		||||
		
 | 
			
		||||
		// start all ffmpegs.
 | 
			
		||||
		if ((ret = ffmpeg->start()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_error("ffmpeg start failed. ret=%d", ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// check ffmpeg status.
 | 
			
		||||
		if ((ret = ffmpeg->cycle()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_error("ffmpeg cycle failed. ret=%d", ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// pithy print
 | 
			
		||||
	encoder();
 | 
			
		||||
	pithy_print->elapse(SRS_ENCODER_SLEEP_MS);
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsEncoder::on_leave_loop()
 | 
			
		||||
{
 | 
			
		||||
	// kill ffmpeg when finished and it alive
 | 
			
		||||
	std::vector<SrsFFMPEG*>::iterator it;
 | 
			
		||||
 | 
			
		||||
	for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
 | 
			
		||||
		SrsFFMPEG* ffmpeg = *it;
 | 
			
		||||
		ffmpeg->stop();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsEncoder::clear_engines()
 | 
			
		||||
{
 | 
			
		||||
	std::vector<SrsFFMPEG*>::iterator it;
 | 
			
		||||
	
 | 
			
		||||
	for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
 | 
			
		||||
		SrsFFMPEG* ffmpeg = *it;
 | 
			
		||||
		srs_freep(ffmpeg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ffmpegs.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsFFMPEG* SrsEncoder::at(int index)
 | 
			
		||||
{
 | 
			
		||||
	return ffmpegs[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsEncoder::parse_scope_engines(SrsRequest* req)
 | 
			
		||||
| 
						 | 
				
			
			@ -531,60 +621,6 @@ int SrsEncoder::parse_scope_engines(SrsRequest* req)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsEncoder::on_publish(SrsRequest* req)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	ret = parse_scope_engines(req);
 | 
			
		||||
	
 | 
			
		||||
	// ignore the loop encoder
 | 
			
		||||
	if (ret == ERROR_ENCODER_LOOP) {
 | 
			
		||||
		ret = ERROR_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// return for error or no engine.
 | 
			
		||||
	if (ret != ERROR_SUCCESS || ffmpegs.empty()) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
    
 | 
			
		||||
    // start thread to run all encoding engines.
 | 
			
		||||
    srs_assert(!tid);
 | 
			
		||||
    if((tid = st_thread_create(encoder_thread, this, 1, 0)) == NULL) {
 | 
			
		||||
		ret = ERROR_ST_CREATE_FORWARD_THREAD;
 | 
			
		||||
        srs_error("st_thread_create failed. ret=%d", ret);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsEncoder::on_unpublish()
 | 
			
		||||
{
 | 
			
		||||
	if (tid) {
 | 
			
		||||
		loop = false;
 | 
			
		||||
		st_thread_interrupt(tid);
 | 
			
		||||
		st_thread_join(tid, NULL);
 | 
			
		||||
		tid = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clear_engines();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsEncoder::clear_engines()
 | 
			
		||||
{
 | 
			
		||||
	std::vector<SrsFFMPEG*>::iterator it;
 | 
			
		||||
	for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
 | 
			
		||||
		SrsFFMPEG* ffmpeg = *it;
 | 
			
		||||
		srs_freep(ffmpeg);
 | 
			
		||||
	}
 | 
			
		||||
	ffmpegs.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsFFMPEG* SrsEncoder::at(int index)
 | 
			
		||||
{
 | 
			
		||||
	return ffmpegs[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
| 
						 | 
				
			
			@ -631,7 +667,6 @@ int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf)
 | 
			
		|||
			
 | 
			
		||||
			// if got a loop, donot transcode the whole stream.
 | 
			
		||||
			if (ret == ERROR_ENCODER_LOOP) {
 | 
			
		||||
				clear_engines();
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
| 
						 | 
				
			
			@ -646,85 +681,14 @@ int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsEncoder::cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	std::vector<SrsFFMPEG*>::iterator it;
 | 
			
		||||
	for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
 | 
			
		||||
		SrsFFMPEG* ffmpeg = *it;
 | 
			
		||||
		
 | 
			
		||||
		// start all ffmpegs.
 | 
			
		||||
		if ((ret = ffmpeg->start()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_error("ffmpeg start failed. ret=%d", ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// check ffmpeg status.
 | 
			
		||||
		if ((ret = ffmpeg->cycle()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_error("ffmpeg cycle failed. ret=%d", ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsEncoder::encoder_cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	log_context->generate_id();
 | 
			
		||||
	srs_trace("encoder cycle start");
 | 
			
		||||
	
 | 
			
		||||
	SrsPithyPrint pithy_print(SRS_STAGE_ENCODER);
 | 
			
		||||
	
 | 
			
		||||
	while (loop) {
 | 
			
		||||
		if ((ret = cycle()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_warn("encoder cycle failed, ignored and retry, ret=%d", ret);
 | 
			
		||||
		} else {
 | 
			
		||||
			srs_info("encoder cycle success, retry");
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (!loop) {
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		encoder(&pithy_print);
 | 
			
		||||
		pithy_print.elapse(SRS_ENCODER_SLEEP_MS);
 | 
			
		||||
		
 | 
			
		||||
		st_usleep(SRS_ENCODER_SLEEP_MS * 1000);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// kill ffmpeg when finished and it alive
 | 
			
		||||
	std::vector<SrsFFMPEG*>::iterator it;
 | 
			
		||||
	for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
 | 
			
		||||
		SrsFFMPEG* ffmpeg = *it;
 | 
			
		||||
		ffmpeg->stop();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	srs_trace("encoder cycle finished");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsEncoder::encoder(SrsPithyPrint* pithy_print)
 | 
			
		||||
void SrsEncoder::encoder()
 | 
			
		||||
{
 | 
			
		||||
	// reportable
 | 
			
		||||
	if (pithy_print->can_print()) {
 | 
			
		||||
		srs_trace("-> time=%"PRId64", encoders=%d",
 | 
			
		||||
			pithy_print->get_age(), (int)ffmpegs.size());
 | 
			
		||||
		// TODO: FIXME: show more info.
 | 
			
		||||
		srs_trace("-> time=%"PRId64", encoders=%d", pithy_print->get_age(), (int)ffmpegs.size());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SrsEncoder::encoder_thread(void* arg)
 | 
			
		||||
{
 | 
			
		||||
	SrsEncoder* obj = (SrsEncoder*)arg;
 | 
			
		||||
	srs_assert(obj != NULL);
 | 
			
		||||
	
 | 
			
		||||
	obj->loop = true;
 | 
			
		||||
	obj->encoder_cycle();
 | 
			
		||||
	
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
#include <srs_core_thread.hpp>
 | 
			
		||||
 | 
			
		||||
class SrsConfDirective;
 | 
			
		||||
class SrsRequest;
 | 
			
		||||
| 
						 | 
				
			
			@ -85,28 +85,29 @@ public:
 | 
			
		|||
* the encoder for a stream,
 | 
			
		||||
* may use multiple ffmpegs to transcode the specified stream.
 | 
			
		||||
*/
 | 
			
		||||
class SrsEncoder
 | 
			
		||||
class SrsEncoder : public ISrsThreadHandler
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	std::vector<SrsFFMPEG*> ffmpegs;
 | 
			
		||||
private:
 | 
			
		||||
	st_thread_t tid;
 | 
			
		||||
	bool loop;
 | 
			
		||||
	SrsThread* pthread;
 | 
			
		||||
	SrsPithyPrint* pithy_print;
 | 
			
		||||
public:
 | 
			
		||||
	SrsEncoder();
 | 
			
		||||
	virtual ~SrsEncoder();
 | 
			
		||||
public:
 | 
			
		||||
	virtual int on_publish(SrsRequest* req);
 | 
			
		||||
	virtual void on_unpublish();
 | 
			
		||||
// interface ISrsThreadHandler.
 | 
			
		||||
public:
 | 
			
		||||
	virtual int cycle();
 | 
			
		||||
	virtual void on_leave_loop();
 | 
			
		||||
private:
 | 
			
		||||
	virtual int parse_scope_engines(SrsRequest* req);
 | 
			
		||||
	virtual void clear_engines();
 | 
			
		||||
	virtual SrsFFMPEG* at(int index);
 | 
			
		||||
	virtual int parse_scope_engines(SrsRequest* req);
 | 
			
		||||
	virtual int parse_transcode(SrsRequest* req, SrsConfDirective* conf);
 | 
			
		||||
	virtual int cycle();
 | 
			
		||||
	virtual void encoder_cycle();
 | 
			
		||||
	virtual void encoder(SrsPithyPrint* pithy_print);
 | 
			
		||||
	static void* encoder_thread(void* arg);
 | 
			
		||||
	virtual void encoder();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,8 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#define ERROR_ST_OPEN_SOCKET			102
 | 
			
		||||
#define ERROR_ST_CREATE_LISTEN_THREAD	103
 | 
			
		||||
#define ERROR_ST_CREATE_CYCLE_THREAD	104
 | 
			
		||||
#define ERROR_ST_CREATE_FORWARD_THREAD	105
 | 
			
		||||
#define ERROR_ST_CONNECT				106
 | 
			
		||||
#define ERROR_ST_CONNECT				105
 | 
			
		||||
 | 
			
		||||
#define ERROR_SOCKET_CREATE 			200
 | 
			
		||||
#define ERROR_SOCKET_SETREUSE 			201
 | 
			
		||||
| 
						 | 
				
			
			@ -85,9 +84,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#define ERROR_SYSTEM_CONFIG_EOF			409
 | 
			
		||||
#define ERROR_SYSTEM_STREAM_BUSY		410
 | 
			
		||||
#define ERROR_SYSTEM_IP_INVALID			411
 | 
			
		||||
#define ERROR_SYSTEM_CONFIG_TOO_LARGE	412
 | 
			
		||||
#define ERROR_SYSTEM_FORWARD_LOOP		413
 | 
			
		||||
#define ERROR_SYSTEM_WAITPID			414
 | 
			
		||||
#define ERROR_SYSTEM_FORWARD_LOOP		412
 | 
			
		||||
#define ERROR_SYSTEM_WAITPID			413
 | 
			
		||||
 | 
			
		||||
// see librtmp.
 | 
			
		||||
// failed when open ssl create the dh
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,32 +35,39 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <srs_core_pithy_print.hpp>
 | 
			
		||||
#include <srs_core_rtmp.hpp>
 | 
			
		||||
#include <srs_core_config.hpp>
 | 
			
		||||
#include <srs_core_source.hpp>
 | 
			
		||||
#include <srs_core_autofree.hpp>
 | 
			
		||||
 | 
			
		||||
#define SRS_PULSE_TIMEOUT_MS 100
 | 
			
		||||
#define SRS_FORWARDER_SLEEP_MS 2000
 | 
			
		||||
#define SRS_SEND_TIMEOUT_US 3000000L
 | 
			
		||||
#define SRS_RECV_TIMEOUT_US SRS_SEND_TIMEOUT_US
 | 
			
		||||
 | 
			
		||||
SrsForwarder::SrsForwarder()
 | 
			
		||||
SrsForwarder::SrsForwarder(SrsSource* _source)
 | 
			
		||||
{
 | 
			
		||||
	source = _source;
 | 
			
		||||
	
 | 
			
		||||
	client = NULL;
 | 
			
		||||
	stfd = NULL;
 | 
			
		||||
	stream_id = 0;
 | 
			
		||||
	
 | 
			
		||||
	tid = NULL;
 | 
			
		||||
	loop = false;
 | 
			
		||||
 | 
			
		||||
	pthread = new SrsThread(this, SRS_FORWARDER_SLEEP_MS);
 | 
			
		||||
	queue = new SrsMessageQueue();
 | 
			
		||||
	jitter = new SrsRtmpJitter();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsForwarder::~SrsForwarder()
 | 
			
		||||
{
 | 
			
		||||
	on_unpublish();
 | 
			
		||||
	
 | 
			
		||||
	std::vector<SrsSharedPtrMessage*>::iterator it;
 | 
			
		||||
	for (it = msgs.begin(); it != msgs.end(); ++it) {
 | 
			
		||||
		SrsSharedPtrMessage* msg = *it;
 | 
			
		||||
		srs_freep(msg);
 | 
			
		||||
	}
 | 
			
		||||
	msgs.clear();
 | 
			
		||||
	srs_freep(pthread);
 | 
			
		||||
	srs_freep(queue);
 | 
			
		||||
	srs_freep(jitter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsForwarder::set_queue_size(double queue_size)
 | 
			
		||||
{
 | 
			
		||||
	queue->set_queue_size(queue_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server)
 | 
			
		||||
| 
						 | 
				
			
			@ -110,41 +117,19 @@ int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server)
 | 
			
		|||
		source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(), 
 | 
			
		||||
		stream_name.c_str());
 | 
			
		||||
	
 | 
			
		||||
	// TODO: seems bug when republish and reforward.
 | 
			
		||||
	
 | 
			
		||||
	// start forward
 | 
			
		||||
	if ((ret = open_socket()) != ERROR_SUCCESS) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
    
 | 
			
		||||
    srs_assert(!tid);
 | 
			
		||||
    if((tid = st_thread_create(forward_thread, this, 1, 0)) == NULL){
 | 
			
		||||
		ret = ERROR_ST_CREATE_FORWARD_THREAD;
 | 
			
		||||
        srs_error("st_thread_create failed. ret=%d", ret);
 | 
			
		||||
	if ((ret = pthread->start()) != ERROR_SUCCESS) {
 | 
			
		||||
        srs_error("start srs thread failed. ret=%d", ret);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsForwarder::on_unpublish()
 | 
			
		||||
{
 | 
			
		||||
	if (tid) {
 | 
			
		||||
		loop = false;
 | 
			
		||||
		st_thread_interrupt(tid);
 | 
			
		||||
		st_thread_join(tid, NULL);
 | 
			
		||||
		tid = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	pthread->stop();
 | 
			
		||||
	
 | 
			
		||||
	if (stfd) {
 | 
			
		||||
		int fd = st_netfd_fileno(stfd);
 | 
			
		||||
		st_netfd_close(stfd);
 | 
			
		||||
		stfd = NULL;
 | 
			
		||||
		
 | 
			
		||||
		// st does not close it sometimes, 
 | 
			
		||||
		// close it manually.
 | 
			
		||||
		close(fd);
 | 
			
		||||
	}
 | 
			
		||||
	close_underlayer_socket();
 | 
			
		||||
	
 | 
			
		||||
	srs_freep(client);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +138,14 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* metadata)
 | 
			
		|||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	msgs.push_back(metadata);
 | 
			
		||||
	if ((ret = jitter->correct(metadata, 0, 0)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_freep(metadata);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = queue->enqueue(metadata)) != ERROR_SUCCESS) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +154,14 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* msg)
 | 
			
		|||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	msgs.push_back(msg);
 | 
			
		||||
	if ((ret = jitter->correct(msg, 0, 0)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_freep(msg);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -171,15 +170,74 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* msg)
 | 
			
		|||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	msgs.push_back(msg);
 | 
			
		||||
	if ((ret = jitter->correct(msg, 0, 0)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_freep(msg);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsForwarder::open_socket()
 | 
			
		||||
int SrsForwarder::cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = connect_server()) != ERROR_SUCCESS) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	srs_assert(client);
 | 
			
		||||
 | 
			
		||||
	client->set_recv_timeout(SRS_RECV_TIMEOUT_US);
 | 
			
		||||
	client->set_send_timeout(SRS_SEND_TIMEOUT_US);
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = client->handshake()) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("handshake with server failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ret = client->connect_app(app, tc_url)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("connect with server failed, tcUrl=%s. ret=%d", tc_url.c_str(), ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ret = client->create_stream(stream_id)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("connect with server failed, stream_id=%d. ret=%d", stream_id, ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = client->publish(stream_name, stream_id)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("connect with server failed, stream_name=%s, stream_id=%d. ret=%d", 
 | 
			
		||||
			stream_name.c_str(), stream_id, ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = source->on_forwarder_start(this)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("callback the source to feed the sequence header failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = forward()) != ERROR_SUCCESS) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsForwarder::close_underlayer_socket()
 | 
			
		||||
{
 | 
			
		||||
	srs_close_stfd(stfd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsForwarder::connect_server()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	// reopen
 | 
			
		||||
	close_underlayer_socket();
 | 
			
		||||
	
 | 
			
		||||
	// open socket.
 | 
			
		||||
	srs_trace("forward stream=%s, tcUrl=%s to server=%s, port=%d",
 | 
			
		||||
		stream_name.c_str(), tc_url.c_str(), server.c_str(), port);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -190,6 +248,7 @@ int SrsForwarder::open_socket()
 | 
			
		|||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    srs_assert(!stfd);
 | 
			
		||||
    stfd = st_netfd_open_socket(sock);
 | 
			
		||||
    if(stfd == NULL){
 | 
			
		||||
        ret = ERROR_ST_OPEN_SOCKET;
 | 
			
		||||
| 
						 | 
				
			
			@ -200,13 +259,7 @@ int SrsForwarder::open_socket()
 | 
			
		|||
	srs_freep(client);
 | 
			
		||||
	client = new SrsRtmpClient(stfd);
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsForwarder::connect_server()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	// connect to server.
 | 
			
		||||
	std::string ip = srs_dns_resolve(server);
 | 
			
		||||
	if (ip.empty()) {
 | 
			
		||||
		ret = ERROR_SYSTEM_IP_INVALID;
 | 
			
		||||
| 
						 | 
				
			
			@ -229,43 +282,6 @@ int SrsForwarder::connect_server()
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsForwarder::cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	client->set_recv_timeout(SRS_RECV_TIMEOUT_US);
 | 
			
		||||
	client->set_send_timeout(SRS_SEND_TIMEOUT_US);
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = connect_server()) != ERROR_SUCCESS) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	srs_assert(client);
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = client->handshake()) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("handshake with server failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ret = client->connect_app(app, tc_url)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("connect with server failed, tcUrl=%s. ret=%d", tc_url.c_str(), ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ret = client->create_stream(stream_id)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("connect with server failed, stream_id=%d. ret=%d", stream_id, ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ret = client->publish(stream_name, stream_id)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("connect with server failed, stream_name=%s, stream_id=%d. ret=%d", 
 | 
			
		||||
			stream_name.c_str(), stream_id, ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = forward()) != ERROR_SUCCESS) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsForwarder::forward()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
| 
						 | 
				
			
			@ -274,9 +290,7 @@ int SrsForwarder::forward()
 | 
			
		|||
	
 | 
			
		||||
	SrsPithyPrint pithy_print(SRS_STAGE_FORWARDER);
 | 
			
		||||
 | 
			
		||||
	while (loop) {
 | 
			
		||||
		pithy_print.elapse(SRS_PULSE_TIMEOUT_MS);
 | 
			
		||||
		
 | 
			
		||||
	while (true) {
 | 
			
		||||
		// switch to other st-threads.
 | 
			
		||||
		st_usleep(0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -292,91 +306,42 @@ int SrsForwarder::forward()
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// forward all messages.
 | 
			
		||||
		int count = 0;
 | 
			
		||||
		SrsSharedPtrMessage** msgs = NULL;
 | 
			
		||||
		if ((ret = queue->get_packets(0, msgs, count)) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_error("get message to forward failed. ret=%d", ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// ignore when no messages.
 | 
			
		||||
		int count = (int)msgs.size();
 | 
			
		||||
		if (msgs.empty()) {
 | 
			
		||||
		if (count <= 0) {
 | 
			
		||||
			srs_verbose("no packets to forward.");
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		SrsAutoFree(SrsSharedPtrMessage*, msgs, true);
 | 
			
		||||
 | 
			
		||||
		// reportable
 | 
			
		||||
		// pithy print
 | 
			
		||||
		pithy_print.elapse(SRS_PULSE_TIMEOUT_MS);
 | 
			
		||||
		if (pithy_print.can_print()) {
 | 
			
		||||
			srs_trace("-> time=%"PRId64", msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d", 
 | 
			
		||||
				pithy_print.get_age(), count, client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps());
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
		// all msgs to forward.
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		for (i = 0; i < count; i++) {
 | 
			
		||||
		for (int i = 0; i < count; i++) {
 | 
			
		||||
			SrsSharedPtrMessage* msg = msgs[i];
 | 
			
		||||
			msgs[i] = NULL;
 | 
			
		||||
 | 
			
		||||
			// we erased the sendout messages, the msg must not be NULL.
 | 
			
		||||
			srs_assert(msg);
 | 
			
		||||
			
 | 
			
		||||
			ret = client->send_message(msg);
 | 
			
		||||
			if (ret != ERROR_SUCCESS) {
 | 
			
		||||
			srs_assert(msg);
 | 
			
		||||
			msgs[i] = NULL;
 | 
			
		||||
			
 | 
			
		||||
			if ((ret = client->send_message(msg)) != ERROR_SUCCESS) {
 | 
			
		||||
				srs_error("forwarder send message to server failed. ret=%d", ret);
 | 
			
		||||
		
 | 
			
		||||
				// convert the index to count when error.
 | 
			
		||||
				i++;
 | 
			
		||||
				
 | 
			
		||||
				break;
 | 
			
		||||
				return ret;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// clear sendout mesages.
 | 
			
		||||
		if (i < count) {
 | 
			
		||||
			srs_warn("clear forwarded msg, total=%d, forwarded=%d, ret=%d", count, i, ret);
 | 
			
		||||
		} else {
 | 
			
		||||
			srs_info("clear forwarded msg, total=%d, forwarded=%d, ret=%d", count, i, ret);
 | 
			
		||||
		}
 | 
			
		||||
		msgs.erase(msgs.begin(), msgs.begin() + i);
 | 
			
		||||
		
 | 
			
		||||
		if (ret != ERROR_SUCCESS) {
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsForwarder::forward_cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	log_context->generate_id();
 | 
			
		||||
	srs_trace("forward cycle start");
 | 
			
		||||
	
 | 
			
		||||
	while (loop) {
 | 
			
		||||
		if ((ret = cycle()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_warn("forward cycle failed, ignored and retry, ret=%d", ret);
 | 
			
		||||
		} else {
 | 
			
		||||
			srs_info("forward cycle success, retry");
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (!loop) {
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		st_usleep(SRS_FORWARDER_SLEEP_MS * 1000);
 | 
			
		||||
 | 
			
		||||
		if ((ret = open_socket()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_warn("forward cycle reopen failed, ignored and retry, ret=%d", ret);
 | 
			
		||||
		} else {
 | 
			
		||||
			srs_info("forward cycle reopen success");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	srs_trace("forward cycle finished");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SrsForwarder::forward_thread(void* arg)
 | 
			
		||||
{
 | 
			
		||||
	SrsForwarder* obj = (SrsForwarder*)arg;
 | 
			
		||||
	srs_assert(obj != NULL);
 | 
			
		||||
	
 | 
			
		||||
	obj->loop = true;
 | 
			
		||||
	obj->forward_cycle();
 | 
			
		||||
	
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,19 +30,21 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <srs_core.hpp>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
#include <srs_core_thread.hpp>
 | 
			
		||||
 | 
			
		||||
class SrsSharedPtrMessage;
 | 
			
		||||
class SrsOnMetaDataPacket;
 | 
			
		||||
class SrsMessageQueue;
 | 
			
		||||
class SrsRtmpJitter;
 | 
			
		||||
class SrsRtmpClient;
 | 
			
		||||
class SrsRequest;
 | 
			
		||||
class SrsSource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* forward the stream to other servers.
 | 
			
		||||
*/
 | 
			
		||||
class SrsForwarder
 | 
			
		||||
class SrsForwarder : public ISrsThreadHandler
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	std::string app;
 | 
			
		||||
| 
						 | 
				
			
			@ -53,28 +55,30 @@ private:
 | 
			
		|||
	int port;
 | 
			
		||||
private:
 | 
			
		||||
	st_netfd_t stfd;
 | 
			
		||||
	st_thread_t tid;
 | 
			
		||||
	bool loop;
 | 
			
		||||
	SrsThread* pthread;
 | 
			
		||||
private:
 | 
			
		||||
	SrsSource* source;
 | 
			
		||||
	SrsRtmpClient* client;
 | 
			
		||||
	std::vector<SrsSharedPtrMessage*> msgs;
 | 
			
		||||
	SrsRtmpJitter* jitter;
 | 
			
		||||
	SrsMessageQueue* queue;
 | 
			
		||||
public:
 | 
			
		||||
	SrsForwarder();
 | 
			
		||||
	SrsForwarder(SrsSource* _source);
 | 
			
		||||
	virtual ~SrsForwarder();
 | 
			
		||||
public:
 | 
			
		||||
	virtual void set_queue_size(double queue_size);
 | 
			
		||||
public:
 | 
			
		||||
	virtual int on_publish(SrsRequest* req, std::string forward_server);
 | 
			
		||||
	virtual void on_unpublish();
 | 
			
		||||
	virtual int on_meta_data(SrsSharedPtrMessage* metadata);
 | 
			
		||||
	virtual int on_audio(SrsSharedPtrMessage* msg);
 | 
			
		||||
	virtual int on_video(SrsSharedPtrMessage* msg);
 | 
			
		||||
private:
 | 
			
		||||
	virtual int open_socket();
 | 
			
		||||
	virtual int connect_server();
 | 
			
		||||
private:
 | 
			
		||||
// interface ISrsThreadHandler.
 | 
			
		||||
public:
 | 
			
		||||
	virtual int cycle();
 | 
			
		||||
private:
 | 
			
		||||
	virtual void close_underlayer_socket();
 | 
			
		||||
	virtual int connect_server();
 | 
			
		||||
	virtual int forward();
 | 
			
		||||
	virtual void forward_cycle();
 | 
			
		||||
	static void* forward_thread(void* arg);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1109,10 +1109,11 @@ int SrsTSCache::cache_video(SrsCodec* codec, SrsCodecSample* sample)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsHls::SrsHls()
 | 
			
		||||
SrsHls::SrsHls(SrsSource* _source)
 | 
			
		||||
{
 | 
			
		||||
	hls_enabled = false;
 | 
			
		||||
	
 | 
			
		||||
	source = _source;
 | 
			
		||||
	codec = new SrsCodec();
 | 
			
		||||
	sample = new SrsCodecSample();
 | 
			
		||||
	jitter = new SrsRtmpJitter();
 | 
			
		||||
| 
						 | 
				
			
			@ -1148,7 +1149,6 @@ int SrsHls::on_publish(SrsRequest* req)
 | 
			
		|||
	std::string stream = req->stream;
 | 
			
		||||
	std::string app = req->app;
 | 
			
		||||
	
 | 
			
		||||
	// TODO: support reload.
 | 
			
		||||
	if (!config->get_hls_enabled(vhost)) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1156,30 +1156,11 @@ int SrsHls::on_publish(SrsRequest* req)
 | 
			
		|||
	// if enabled, open the muxer.
 | 
			
		||||
	hls_enabled = true;
 | 
			
		||||
	
 | 
			
		||||
	// TODO: subscribe the reload event.
 | 
			
		||||
	int hls_fragment = 0;
 | 
			
		||||
	int hls_window = 0;
 | 
			
		||||
	
 | 
			
		||||
	SrsConfDirective* conf = NULL;
 | 
			
		||||
	if ((conf = config->get_hls_fragment(vhost)) != NULL && !conf->arg0().empty()) {
 | 
			
		||||
		hls_fragment = ::atoi(conf->arg0().c_str());
 | 
			
		||||
	}
 | 
			
		||||
	if (hls_fragment <= 0) {
 | 
			
		||||
		hls_fragment = SRS_CONF_DEFAULT_HLS_FRAGMENT;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if ((conf = config->get_hls_window(vhost)) != NULL && !conf->arg0().empty()) {
 | 
			
		||||
		hls_window = ::atoi(conf->arg0().c_str());
 | 
			
		||||
	}
 | 
			
		||||
	if (hls_window <= 0) {
 | 
			
		||||
		hls_window = SRS_CONF_DEFAULT_HLS_WINDOW;
 | 
			
		||||
	}
 | 
			
		||||
	int hls_fragment = config->get_hls_fragment(vhost);
 | 
			
		||||
	int hls_window = config->get_hls_window(vhost);
 | 
			
		||||
	
 | 
			
		||||
	// get the hls path config
 | 
			
		||||
	std::string hls_path = SRS_CONF_DEFAULT_HLS_PATH;
 | 
			
		||||
	if ((conf = config->get_hls_path(vhost)) != NULL) {
 | 
			
		||||
		hls_path = conf->arg0();
 | 
			
		||||
	}
 | 
			
		||||
	std::string hls_path = config->get_hls_path(vhost);
 | 
			
		||||
	
 | 
			
		||||
	// open muxer
 | 
			
		||||
	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)
 | 
			
		|||
		srs_error("m3u8 muxer open segment failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// notice the source to get the cached sequence header.
 | 
			
		||||
	if ((ret = source->on_hls_start()) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("callback source hls start failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1215,16 +1202,16 @@ void SrsHls::on_unpublish()
 | 
			
		|||
	hls_enabled = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsHls::on_meta_data(SrsOnMetaDataPacket* metadata)
 | 
			
		||||
int SrsHls::on_meta_data(SrsAmf0Object* metadata)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	if (!metadata || !metadata->metadata) {
 | 
			
		||||
	if (!metadata) {
 | 
			
		||||
		srs_trace("no metadata persent, hls ignored it.");
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	SrsAmf0Object* obj = metadata->metadata;
 | 
			
		||||
	SrsAmf0Object* obj = metadata;
 | 
			
		||||
	if (obj->size() <= 0) {
 | 
			
		||||
		srs_trace("no metadata persent, hls ignored it.");
 | 
			
		||||
		return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -1273,7 +1260,6 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio)
 | 
			
		|||
	
 | 
			
		||||
	SrsAutoFree(SrsSharedPtrMessage, audio, false);
 | 
			
		||||
	
 | 
			
		||||
	// TODO: maybe donot need to demux the aac?
 | 
			
		||||
	if (!hls_enabled) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1293,14 +1279,13 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio)
 | 
			
		|||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	int64_t corrected_time = 0;
 | 
			
		||||
	if ((ret = jitter->correct(audio, 0, 0, &corrected_time)) != ERROR_SUCCESS) {
 | 
			
		||||
	if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("rtmp jitter correct audio failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// the pts calc from rtmp/flv header.
 | 
			
		||||
	int64_t pts = corrected_time * 90;
 | 
			
		||||
	int64_t pts = audio->header.timestamp * 90;
 | 
			
		||||
	
 | 
			
		||||
	if ((ret = ts_cache->write_audio(codec, muxer, pts, sample)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("ts cache write audio failed. ret=%d", ret);
 | 
			
		||||
| 
						 | 
				
			
			@ -1316,7 +1301,6 @@ int SrsHls::on_video(SrsSharedPtrMessage* video)
 | 
			
		|||
	
 | 
			
		||||
	SrsAutoFree(SrsSharedPtrMessage, video, false);
 | 
			
		||||
	
 | 
			
		||||
	// TODO: maybe donot need to demux the avc?
 | 
			
		||||
	if (!hls_enabled) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,24 +1321,23 @@ int SrsHls::on_video(SrsSharedPtrMessage* video)
 | 
			
		|||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	int64_t corrected_time = 0;
 | 
			
		||||
	if ((ret = jitter->correct(video, 0, 0, &corrected_time)) != ERROR_SUCCESS) {
 | 
			
		||||
	if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("rtmp jitter correct video failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	int64_t dts = corrected_time * 90;
 | 
			
		||||
	int64_t dts = video->header.timestamp * 90;
 | 
			
		||||
	if ((ret = ts_cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("ts cache write video failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	_mpegts();
 | 
			
		||||
	hls_mux();
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsHls::_mpegts()
 | 
			
		||||
void SrsHls::hls_mux()
 | 
			
		||||
{
 | 
			
		||||
	// reportable
 | 
			
		||||
	if (pithy_print->can_print()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,16 +34,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
class SrsOnMetaDataPacket;
 | 
			
		||||
class SrsSharedPtrMessage;
 | 
			
		||||
class SrsCodecSample;
 | 
			
		||||
class SrsCodecBuffer;
 | 
			
		||||
class SrsMpegtsFrame;
 | 
			
		||||
class SrsAmf0Object;
 | 
			
		||||
class SrsRtmpJitter;
 | 
			
		||||
class SrsTSMuxer;
 | 
			
		||||
class SrsCodec;
 | 
			
		||||
class SrsRequest;
 | 
			
		||||
class SrsPithyPrint;
 | 
			
		||||
class SrsSource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* jitter correct for audio,
 | 
			
		||||
| 
						 | 
				
			
			@ -207,21 +208,39 @@ private:
 | 
			
		|||
	SrsTSCache* ts_cache;
 | 
			
		||||
private:
 | 
			
		||||
	bool hls_enabled;
 | 
			
		||||
	SrsSource* source;
 | 
			
		||||
	SrsCodec* codec;
 | 
			
		||||
	SrsCodecSample* sample;
 | 
			
		||||
	SrsRtmpJitter* jitter;
 | 
			
		||||
	SrsPithyPrint* pithy_print;
 | 
			
		||||
public:
 | 
			
		||||
	SrsHls();
 | 
			
		||||
	SrsHls(SrsSource* _source);
 | 
			
		||||
	virtual ~SrsHls();
 | 
			
		||||
public:
 | 
			
		||||
	/**
 | 
			
		||||
	* publish stream event, continue to write the m3u8,
 | 
			
		||||
	* for the muxer object not destroyed.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int on_publish(SrsRequest* req);
 | 
			
		||||
	/**
 | 
			
		||||
	* the unpublish event, only close the muxer, donot destroy the 
 | 
			
		||||
	* muxer, for when we continue to publish, the m3u8 will continue.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual void on_unpublish();
 | 
			
		||||
	virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
 | 
			
		||||
	/**
 | 
			
		||||
	* get some information from metadata, it's optinal.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int on_meta_data(SrsAmf0Object* metadata);
 | 
			
		||||
	/**
 | 
			
		||||
	* mux the audio packets to ts.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int on_audio(SrsSharedPtrMessage* audio);
 | 
			
		||||
	/**
 | 
			
		||||
	* mux the video packets to ts.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int on_video(SrsSharedPtrMessage* video);
 | 
			
		||||
private:
 | 
			
		||||
	virtual void _mpegts();
 | 
			
		||||
	virtual void hls_mux();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -184,15 +184,7 @@ void SrsHttpClient::disconnect()
 | 
			
		|||
{
 | 
			
		||||
	connected = false;
 | 
			
		||||
	
 | 
			
		||||
	if (stfd) {
 | 
			
		||||
		int fd = st_netfd_fileno(stfd);
 | 
			
		||||
		st_netfd_close(stfd);
 | 
			
		||||
		stfd = NULL;
 | 
			
		||||
		
 | 
			
		||||
		// st does not close it sometimes, 
 | 
			
		||||
		// close it manually.
 | 
			
		||||
		::close(fd);
 | 
			
		||||
	}
 | 
			
		||||
	srs_close_stfd(stfd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsHttpClient::connect(SrsHttpUri* uri)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,6 @@ class SrsSocket;
 | 
			
		|||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
#include <http_parser.h>
 | 
			
		||||
 | 
			
		||||
#define SRS_HTTP_HEADER_BUFFER		1024
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,8 +29,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <string>
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
 | 
			
		||||
ILogContext::ILogContext()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,13 +32,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <srs_core_error.hpp>
 | 
			
		||||
 | 
			
		||||
#define SRS_STAGE_DEFAULT_INTERVAL_MS 1200
 | 
			
		||||
#define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300
 | 
			
		||||
#define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100
 | 
			
		||||
#define SRS_STAGE_FORWARDER_INTERVAL_MS 2000
 | 
			
		||||
#define SRS_STAGE_ENCODER_INTERVAL_MS 2000
 | 
			
		||||
#define SRS_STAGE_HLS_INTERVAL_MS 2000
 | 
			
		||||
 | 
			
		||||
struct SrsStageInfo : public SrsReloadHandler
 | 
			
		||||
struct SrsStageInfo : public ISrsReloadHandler
 | 
			
		||||
{
 | 
			
		||||
	int stage_id;
 | 
			
		||||
	int pithy_print_time_ms;
 | 
			
		||||
| 
						 | 
				
			
			@ -61,43 +56,23 @@ struct SrsStageInfo : public SrsReloadHandler
 | 
			
		|||
	{
 | 
			
		||||
		switch (stage_id) {
 | 
			
		||||
			case SRS_STAGE_PLAY_USER: {
 | 
			
		||||
				pithy_print_time_ms = SRS_STAGE_PLAY_USER_INTERVAL_MS;
 | 
			
		||||
				SrsConfDirective* conf = config->get_pithy_print_play();
 | 
			
		||||
				if (conf && !conf->arg0().empty()) {
 | 
			
		||||
					pithy_print_time_ms = ::atoi(conf->arg0().c_str());
 | 
			
		||||
				}
 | 
			
		||||
				pithy_print_time_ms = config->get_pithy_print_play();
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			case SRS_STAGE_PUBLISH_USER: {
 | 
			
		||||
				pithy_print_time_ms = SRS_STAGE_PUBLISH_USER_INTERVAL_MS;
 | 
			
		||||
				SrsConfDirective* conf = config->get_pithy_print_publish();
 | 
			
		||||
				if (conf && !conf->arg0().empty()) {
 | 
			
		||||
					pithy_print_time_ms = ::atoi(conf->arg0().c_str());
 | 
			
		||||
				}
 | 
			
		||||
				pithy_print_time_ms = config->get_pithy_print_publish();
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			case SRS_STAGE_FORWARDER: {
 | 
			
		||||
				pithy_print_time_ms = SRS_STAGE_FORWARDER_INTERVAL_MS;
 | 
			
		||||
				SrsConfDirective* conf = config->get_pithy_print_forwarder();
 | 
			
		||||
				if (conf && !conf->arg0().empty()) {
 | 
			
		||||
					pithy_print_time_ms = ::atoi(conf->arg0().c_str());
 | 
			
		||||
				}
 | 
			
		||||
				pithy_print_time_ms = config->get_pithy_print_forwarder();
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			case SRS_STAGE_ENCODER: {
 | 
			
		||||
				pithy_print_time_ms = SRS_STAGE_ENCODER_INTERVAL_MS;
 | 
			
		||||
				SrsConfDirective* conf = config->get_pithy_print_encoder();
 | 
			
		||||
				if (conf && !conf->arg0().empty()) {
 | 
			
		||||
					pithy_print_time_ms = ::atoi(conf->arg0().c_str());
 | 
			
		||||
				}
 | 
			
		||||
				pithy_print_time_ms = config->get_pithy_print_encoder();
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			case SRS_STAGE_HLS: {
 | 
			
		||||
				pithy_print_time_ms = SRS_STAGE_HLS_INTERVAL_MS;
 | 
			
		||||
				SrsConfDirective* conf = config->get_pithy_print_hls();
 | 
			
		||||
				if (conf && !conf->arg0().empty()) {
 | 
			
		||||
					pithy_print_time_ms = ::atoi(conf->arg0().c_str());
 | 
			
		||||
				}
 | 
			
		||||
				pithy_print_time_ms = config->get_pithy_print_hls();
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			default: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -307,6 +307,11 @@ void SrsProtocol::set_send_timeout(int64_t timeout_us)
 | 
			
		|||
	return skt->set_send_timeout(timeout_us);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t SrsProtocol::get_send_timeout()
 | 
			
		||||
{
 | 
			
		||||
	return skt->get_send_timeout();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t SrsProtocol::get_recv_bytes()
 | 
			
		||||
{
 | 
			
		||||
	return skt->get_recv_bytes();
 | 
			
		||||
| 
						 | 
				
			
			@ -349,7 +354,7 @@ int SrsProtocol::recv_message(SrsCommonMessage** pmsg)
 | 
			
		|||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (msg->size <= 0 || msg->header.payload_length <= 0) {
 | 
			
		||||
			srs_trace("ignore empty message(type=%d, size=%d, time=%d, sid=%d).",
 | 
			
		||||
			srs_trace("ignore empty message(type=%d, size=%d, time=%"PRId64", sid=%d).",
 | 
			
		||||
				msg->header.message_type, msg->header.payload_length,
 | 
			
		||||
				msg->header.timestamp, msg->header.stream_id);
 | 
			
		||||
			srs_freep(msg);
 | 
			
		||||
| 
						 | 
				
			
			@ -400,12 +405,13 @@ int SrsProtocol::send_message(ISrsMessage* msg)
 | 
			
		|||
			
 | 
			
		||||
		    // chunk message header, 11 bytes
 | 
			
		||||
		    // timestamp, 3bytes, big-endian
 | 
			
		||||
			if (msg->header.timestamp >= RTMP_EXTENDED_TIMESTAMP) {
 | 
			
		||||
			u_int32_t timestamp = (u_int32_t)msg->header.timestamp;
 | 
			
		||||
			if (timestamp >= RTMP_EXTENDED_TIMESTAMP) {
 | 
			
		||||
		        *pheader++ = 0xFF;
 | 
			
		||||
		        *pheader++ = 0xFF;
 | 
			
		||||
		        *pheader++ = 0xFF;
 | 
			
		||||
			} else {
 | 
			
		||||
		        pp = (char*)&msg->header.timestamp; 
 | 
			
		||||
		        pp = (char*)×tamp;
 | 
			
		||||
		        *pheader++ = pp[2];
 | 
			
		||||
		        *pheader++ = pp[1];
 | 
			
		||||
		        *pheader++ = pp[0];
 | 
			
		||||
| 
						 | 
				
			
			@ -428,8 +434,8 @@ int SrsProtocol::send_message(ISrsMessage* msg)
 | 
			
		|||
		    *pheader++ = pp[3];
 | 
			
		||||
		    
 | 
			
		||||
		    // chunk extended timestamp header, 0 or 4 bytes, big-endian
 | 
			
		||||
		    if(msg->header.timestamp >= RTMP_EXTENDED_TIMESTAMP){
 | 
			
		||||
		        pp = (char*)&msg->header.timestamp;
 | 
			
		||||
		    if(timestamp >= RTMP_EXTENDED_TIMESTAMP){
 | 
			
		||||
		        pp = (char*)×tamp;
 | 
			
		||||
		        *pheader++ = pp[3];
 | 
			
		||||
		        *pheader++ = pp[2];
 | 
			
		||||
		        *pheader++ = pp[1];
 | 
			
		||||
| 
						 | 
				
			
			@ -456,8 +462,9 @@ int SrsProtocol::send_message(ISrsMessage* msg)
 | 
			
		|||
		    //		must send the extended-timestamp to flash-player.
 | 
			
		||||
		    // @see: ngx_rtmp_prepare_message
 | 
			
		||||
		    // @see: http://blog.csdn.net/win_lin/article/details/13363699
 | 
			
		||||
		    if(msg->header.timestamp >= RTMP_EXTENDED_TIMESTAMP){
 | 
			
		||||
		        pp = (char*)&msg->header.timestamp; 
 | 
			
		||||
			u_int32_t timestamp = (u_int32_t)msg->header.timestamp;
 | 
			
		||||
		    if(timestamp >= RTMP_EXTENDED_TIMESTAMP){
 | 
			
		||||
		        pp = (char*)×tamp; 
 | 
			
		||||
		        *pheader++ = pp[3];
 | 
			
		||||
		        *pheader++ = pp[2];
 | 
			
		||||
		        *pheader++ = pp[1];
 | 
			
		||||
| 
						 | 
				
			
			@ -697,7 +704,7 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg)
 | 
			
		|||
		srs_verbose("cache new chunk stream: fmt=%d, cid=%d", fmt, cid);
 | 
			
		||||
	} else {
 | 
			
		||||
		chunk = chunk_streams[cid];
 | 
			
		||||
		srs_verbose("cached chunk stream: fmt=%d, cid=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)",
 | 
			
		||||
		srs_verbose("cached chunk stream: fmt=%d, cid=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)",
 | 
			
		||||
			chunk->fmt, chunk->cid, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type, chunk->header.payload_length,
 | 
			
		||||
			chunk->header.timestamp, chunk->header.stream_id);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -711,7 +718,7 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg)
 | 
			
		|||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	srs_verbose("read message header success. "
 | 
			
		||||
			"fmt=%d, mh_size=%d, ext_time=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", 
 | 
			
		||||
			"fmt=%d, mh_size=%d, ext_time=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)", 
 | 
			
		||||
			fmt, mh_size, chunk->extended_timestamp, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type, 
 | 
			
		||||
			chunk->header.payload_length, chunk->header.timestamp, chunk->header.stream_id);
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -733,14 +740,14 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg)
 | 
			
		|||
	
 | 
			
		||||
	// not got an entire RTMP message, try next chunk.
 | 
			
		||||
	if (!msg) {
 | 
			
		||||
		srs_verbose("get partial message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)",
 | 
			
		||||
		srs_verbose("get partial message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)",
 | 
			
		||||
				payload_size, (msg? msg->size : (chunk->msg? chunk->msg->size : 0)), chunk->header.message_type, chunk->header.payload_length,
 | 
			
		||||
				chunk->header.timestamp, chunk->header.stream_id);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	*pmsg = msg;
 | 
			
		||||
	srs_info("get entire message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)",
 | 
			
		||||
	srs_info("get entire message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)",
 | 
			
		||||
			payload_size, (msg? msg->size : (chunk->msg? chunk->msg->size : 0)), chunk->header.message_type, chunk->header.payload_length,
 | 
			
		||||
			chunk->header.timestamp, chunk->header.stream_id);
 | 
			
		||||
			
 | 
			
		||||
| 
						 | 
				
			
			@ -947,16 +954,16 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
 | 
			
		|||
                pp[1] = *p++;
 | 
			
		||||
                pp[2] = *p++;
 | 
			
		||||
                pp[3] = *p++;
 | 
			
		||||
				srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%d, payload=%d, type=%d, sid=%d", 
 | 
			
		||||
				srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%"PRId64", payload=%d, type=%d, sid=%d", 
 | 
			
		||||
					fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp, chunk->header.payload_length, 
 | 
			
		||||
					chunk->header.message_type, chunk->header.stream_id);
 | 
			
		||||
			} else {
 | 
			
		||||
				srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%d, payload=%d, type=%d", 
 | 
			
		||||
				srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%"PRId64", payload=%d, type=%d", 
 | 
			
		||||
					fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp, chunk->header.payload_length, 
 | 
			
		||||
					chunk->header.message_type);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%d", 
 | 
			
		||||
			srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%"PRId64"", 
 | 
			
		||||
				fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -981,7 +988,7 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
 | 
			
		|||
 | 
			
		||||
		// ffmpeg/librtmp may donot send this filed, need to detect the value.
 | 
			
		||||
		// @see also: http://blog.csdn.net/win_lin/article/details/13363699
 | 
			
		||||
		int32_t timestamp = 0x00;
 | 
			
		||||
		u_int32_t timestamp = 0x00;
 | 
			
		||||
        char* pp = (char*)×tamp;
 | 
			
		||||
        pp[3] = *p++;
 | 
			
		||||
        pp[2] = *p++;
 | 
			
		||||
| 
						 | 
				
			
			@ -990,14 +997,14 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
 | 
			
		|||
        
 | 
			
		||||
        // compare to the chunk timestamp, which is set by chunk message header
 | 
			
		||||
        // type 0,1 or 2.
 | 
			
		||||
        int32_t chunk_timestamp = chunk->header.timestamp;
 | 
			
		||||
        u_int32_t chunk_timestamp = chunk->header.timestamp;
 | 
			
		||||
        if (chunk_timestamp > RTMP_EXTENDED_TIMESTAMP && chunk_timestamp != timestamp) {
 | 
			
		||||
            mh_size -= 4;
 | 
			
		||||
            srs_verbose("ignore the 4bytes extended timestamp. mh_size=%d", mh_size);
 | 
			
		||||
        } else {
 | 
			
		||||
            chunk->header.timestamp = timestamp;
 | 
			
		||||
        }
 | 
			
		||||
		srs_verbose("header read ext_time completed. time=%d", chunk->header.timestamp);
 | 
			
		||||
		srs_verbose("header read ext_time completed. time=%"PRId64"", chunk->header.timestamp);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// valid message
 | 
			
		||||
| 
						 | 
				
			
			@ -1027,7 +1034,7 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh
 | 
			
		|||
		buffer->erase(bh_size + mh_size);
 | 
			
		||||
		
 | 
			
		||||
		srs_trace("get an empty RTMP "
 | 
			
		||||
				"message(type=%d, size=%d, time=%d, sid=%d)", chunk->header.message_type, 
 | 
			
		||||
				"message(type=%d, size=%d, time=%"PRId64", sid=%d)", chunk->header.message_type, 
 | 
			
		||||
				chunk->header.payload_length, chunk->header.timestamp, chunk->header.stream_id);
 | 
			
		||||
		
 | 
			
		||||
		*pmsg = chunk->msg;
 | 
			
		||||
| 
						 | 
				
			
			@ -1068,13 +1075,13 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh
 | 
			
		|||
	if (chunk->header.payload_length == chunk->msg->size) {
 | 
			
		||||
		*pmsg = chunk->msg;
 | 
			
		||||
		chunk->msg = NULL;
 | 
			
		||||
		srs_verbose("get entire RTMP message(type=%d, size=%d, time=%d, sid=%d)", 
 | 
			
		||||
		srs_verbose("get entire RTMP message(type=%d, size=%d, time=%"PRId64", sid=%d)", 
 | 
			
		||||
				chunk->header.message_type, chunk->header.payload_length, 
 | 
			
		||||
				chunk->header.timestamp, chunk->header.stream_id);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	srs_verbose("get partial RTMP message(type=%d, size=%d, time=%d, sid=%d), partial size=%d", 
 | 
			
		||||
	srs_verbose("get partial RTMP message(type=%d, size=%d, time=%"PRId64", sid=%d), partial size=%d", 
 | 
			
		||||
			chunk->header.message_type, chunk->header.payload_length, 
 | 
			
		||||
			chunk->header.timestamp, chunk->header.stream_id,
 | 
			
		||||
			chunk->msg->size);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,8 +33,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
 | 
			
		||||
#include <srs_core_log.hpp>
 | 
			
		||||
#include <srs_core_error.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -117,6 +115,7 @@ public:
 | 
			
		|||
	virtual void set_recv_timeout(int64_t timeout_us);
 | 
			
		||||
	virtual int64_t get_recv_timeout();
 | 
			
		||||
	virtual void set_send_timeout(int64_t timeout_us);
 | 
			
		||||
	virtual int64_t get_send_timeout();
 | 
			
		||||
	virtual int64_t get_recv_bytes();
 | 
			
		||||
	virtual int64_t get_send_bytes();
 | 
			
		||||
	virtual int get_recv_kbps();
 | 
			
		||||
| 
						 | 
				
			
			@ -205,8 +204,9 @@ struct SrsMessageHeader
 | 
			
		|||
	* Four-byte field that contains a timestamp of the message.
 | 
			
		||||
	* The 4 bytes are packed in the big-endian order.
 | 
			
		||||
	* @remark, used as calc timestamp when decode and encode time.
 | 
			
		||||
	* @remark, we use 64bits for large time for jitter detect and hls.
 | 
			
		||||
	*/
 | 
			
		||||
	u_int32_t timestamp;
 | 
			
		||||
	int64_t timestamp;
 | 
			
		||||
	
 | 
			
		||||
	SrsMessageHeader();
 | 
			
		||||
	virtual ~SrsMessageHeader();
 | 
			
		||||
| 
						 | 
				
			
			@ -1156,7 +1156,7 @@ int srs_rtmp_expect_message(SrsProtocol* protocol, SrsCommonMessage** pmsg, T**
 | 
			
		|||
		T* pkt = dynamic_cast<T*>(msg->get_packet());
 | 
			
		||||
		if (!pkt) {
 | 
			
		||||
			delete msg;
 | 
			
		||||
			srs_trace("drop message(type=%d, size=%d, time=%d, sid=%d).", 
 | 
			
		||||
			srs_trace("drop message(type=%d, size=%d, time=%"PRId64", sid=%d).", 
 | 
			
		||||
				msg->header.message_type, msg->header.payload_length,
 | 
			
		||||
				msg->header.timestamp, msg->header.stream_id);
 | 
			
		||||
			continue;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,22 +23,54 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
 | 
			
		||||
#include <srs_core_reload.hpp>
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
#include <srs_core_error.hpp>
 | 
			
		||||
 | 
			
		||||
SrsReloadHandler::SrsReloadHandler()
 | 
			
		||||
ISrsReloadHandler::ISrsReloadHandler()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsReloadHandler::~SrsReloadHandler()
 | 
			
		||||
ISrsReloadHandler::~ISrsReloadHandler()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsReloadHandler::on_reload_listen()
 | 
			
		||||
int ISrsReloadHandler::on_reload_listen()
 | 
			
		||||
{
 | 
			
		||||
	return ERROR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsReloadHandler::on_reload_pithy_print()
 | 
			
		||||
int ISrsReloadHandler::on_reload_pithy_print()
 | 
			
		||||
{
 | 
			
		||||
	return ERROR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ISrsReloadHandler::on_reload_vhost_removed(string /*vhost*/)
 | 
			
		||||
{
 | 
			
		||||
	return ERROR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ISrsReloadHandler::on_reload_gop_cache(string /*vhost*/)
 | 
			
		||||
{
 | 
			
		||||
	return ERROR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ISrsReloadHandler::on_reload_queue_length(string /*vhost*/)
 | 
			
		||||
{
 | 
			
		||||
	return ERROR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ISrsReloadHandler::on_reload_forward(string /*vhost*/)
 | 
			
		||||
{
 | 
			
		||||
	return ERROR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ISrsReloadHandler::on_reload_hls(string /*vhost*/)
 | 
			
		||||
{
 | 
			
		||||
	return ERROR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ISrsReloadHandler::on_reload_transcode(string /*vhost*/)
 | 
			
		||||
{
 | 
			
		||||
	return ERROR_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,17 +29,25 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
*/
 | 
			
		||||
#include <srs_core.hpp>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* the handler for config reload.
 | 
			
		||||
*/
 | 
			
		||||
class SrsReloadHandler
 | 
			
		||||
class ISrsReloadHandler
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	SrsReloadHandler();
 | 
			
		||||
	virtual ~SrsReloadHandler();
 | 
			
		||||
	ISrsReloadHandler();
 | 
			
		||||
	virtual ~ISrsReloadHandler();
 | 
			
		||||
public:
 | 
			
		||||
	virtual int on_reload_listen();
 | 
			
		||||
	virtual int on_reload_pithy_print();
 | 
			
		||||
	virtual int on_reload_vhost_removed(std::string vhost);
 | 
			
		||||
	virtual int on_reload_gop_cache(std::string vhost);
 | 
			
		||||
	virtual int on_reload_queue_length(std::string vhost);
 | 
			
		||||
	virtual int on_reload_forward(std::string vhost);
 | 
			
		||||
	virtual int on_reload_hls(std::string vhost);
 | 
			
		||||
	virtual int on_reload_transcode(std::string vhost);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <srs_core_handshake.hpp>
 | 
			
		||||
#include <srs_core_config.hpp>
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* the signature for packets to client.
 | 
			
		||||
*/
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +81,23 @@ SrsRequest::~SrsRequest()
 | 
			
		|||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsRequest* SrsRequest::copy()
 | 
			
		||||
{
 | 
			
		||||
	SrsRequest* cp = new SrsRequest();
 | 
			
		||||
	
 | 
			
		||||
	cp->app = app;
 | 
			
		||||
	cp->objectEncoding = objectEncoding;
 | 
			
		||||
	cp->pageUrl = pageUrl;
 | 
			
		||||
	cp->port = port;
 | 
			
		||||
	cp->schema = schema;
 | 
			
		||||
	cp->stream = stream;
 | 
			
		||||
	cp->swfUrl = swfUrl;
 | 
			
		||||
	cp->tcUrl = tcUrl;
 | 
			
		||||
	cp->vhost = vhost;
 | 
			
		||||
	
 | 
			
		||||
	return cp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsRequest::discovery_app()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
| 
						 | 
				
			
			@ -125,6 +144,8 @@ int SrsRequest::discovery_app()
 | 
			
		|||
	if (parsed_vhost) {
 | 
			
		||||
		vhost = parsed_vhost->arg0();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: discovery the params of vhost.
 | 
			
		||||
	
 | 
			
		||||
	srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s",
 | 
			
		||||
		schema.c_str(), vhost.c_str(), port.c_str(), app.c_str());
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +163,7 @@ int SrsRequest::discovery_app()
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string SrsRequest::get_stream_url()
 | 
			
		||||
string SrsRequest::get_stream_url()
 | 
			
		||||
{
 | 
			
		||||
	std::string url = "";
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +183,7 @@ void SrsRequest::strip()
 | 
			
		|||
	trim(stream, "/ \n\r\t");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string& SrsRequest::trim(std::string& str, std::string chs)
 | 
			
		||||
std::string& SrsRequest::trim(string& str, string chs)
 | 
			
		||||
{
 | 
			
		||||
	for (int i = 0; i < (int)chs.length(); i++) {
 | 
			
		||||
		char ch = chs.at(i);
 | 
			
		||||
| 
						 | 
				
			
			@ -245,6 +266,9 @@ int SrsRtmpClient::handshake()
 | 
			
		|||
	
 | 
			
		||||
    SrsSocket skt(stfd);
 | 
			
		||||
    
 | 
			
		||||
    skt.set_recv_timeout(protocol->get_recv_timeout());
 | 
			
		||||
    skt.set_send_timeout(protocol->get_send_timeout());
 | 
			
		||||
    
 | 
			
		||||
    SrsComplexHandshake complex_hs;
 | 
			
		||||
    SrsSimpleHandshake simple_hs;
 | 
			
		||||
    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)
 | 
			
		|||
	protocol->set_send_timeout(timeout_us);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t SrsRtmp::get_send_timeout()
 | 
			
		||||
{
 | 
			
		||||
	return protocol->get_send_timeout();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t SrsRtmp::get_recv_bytes()
 | 
			
		||||
{
 | 
			
		||||
	return protocol->get_recv_bytes();
 | 
			
		||||
| 
						 | 
				
			
			@ -472,6 +501,9 @@ int SrsRtmp::handshake()
 | 
			
		|||
	
 | 
			
		||||
    SrsSocket skt(stfd);
 | 
			
		||||
    
 | 
			
		||||
    skt.set_recv_timeout(protocol->get_recv_timeout());
 | 
			
		||||
    skt.set_send_timeout(protocol->get_send_timeout());
 | 
			
		||||
    
 | 
			
		||||
    SrsComplexHandshake complex_hs;
 | 
			
		||||
    SrsSimpleHandshake simple_hs;
 | 
			
		||||
    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)
 | 
			
		|||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsRtmp::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsClientType& type, std::string& stream_name)
 | 
			
		||||
int SrsRtmp::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsClientType& type, string& stream_name)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -1184,7 +1216,7 @@ int SrsRtmp::identify_create_stream_client(SrsCreateStreamPacket* req, int strea
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsRtmp::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsClientType& type, std::string& stream_name)
 | 
			
		||||
int SrsRtmp::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsClientType& type, string& stream_name)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -1208,7 +1240,7 @@ int SrsRtmp::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsClientType
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsRtmp::identify_flash_publish_client(SrsPublishPacket* req, SrsClientType& type, std::string& stream_name)
 | 
			
		||||
int SrsRtmp::identify_flash_publish_client(SrsPublishPacket* req, SrsClientType& type, string& stream_name)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,8 +33,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
 | 
			
		||||
class SrsProtocol;
 | 
			
		||||
class ISrsMessage;
 | 
			
		||||
class SrsCommonMessage;
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +67,13 @@ struct SrsRequest
 | 
			
		|||
	
 | 
			
		||||
	SrsRequest();
 | 
			
		||||
	virtual ~SrsRequest();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	* deep copy the request, for source to use it to support reload,
 | 
			
		||||
	* for when initialize the source, the request is valid,
 | 
			
		||||
	* when reload it, the request maybe invalid, so need to copy it.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual SrsRequest* copy();
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
	* disconvery vhost/app from tcUrl.
 | 
			
		||||
| 
						 | 
				
			
			@ -148,6 +153,7 @@ public:
 | 
			
		|||
	virtual void set_recv_timeout(int64_t timeout_us);
 | 
			
		||||
	virtual int64_t get_recv_timeout();
 | 
			
		||||
	virtual void set_send_timeout(int64_t timeout_us);
 | 
			
		||||
	virtual int64_t get_send_timeout();
 | 
			
		||||
	virtual int64_t get_recv_bytes();
 | 
			
		||||
	virtual int64_t get_send_bytes();
 | 
			
		||||
	virtual int get_recv_kbps();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,8 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
 | 
			
		||||
#include <srs_core_log.hpp>
 | 
			
		||||
#include <srs_core_error.hpp>
 | 
			
		||||
#include <srs_core_client.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -48,24 +46,16 @@ SrsListener::SrsListener(SrsServer* _server, SrsListenerType _type)
 | 
			
		|||
	port = 0;
 | 
			
		||||
	server = _server;
 | 
			
		||||
	type = _type;
 | 
			
		||||
	
 | 
			
		||||
	tid = NULL;
 | 
			
		||||
	loop = false;
 | 
			
		||||
 | 
			
		||||
	pthread = new SrsThread(this, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsListener::~SrsListener()
 | 
			
		||||
{
 | 
			
		||||
	if (stfd) {
 | 
			
		||||
		st_netfd_close(stfd);
 | 
			
		||||
		stfd = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	srs_close_stfd(stfd);
 | 
			
		||||
	
 | 
			
		||||
	if (tid) {
 | 
			
		||||
		loop = false;
 | 
			
		||||
		st_thread_interrupt(tid);
 | 
			
		||||
		st_thread_join(tid, NULL);
 | 
			
		||||
		tid = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	pthread->stop();
 | 
			
		||||
	srs_freep(pthread);
 | 
			
		||||
	
 | 
			
		||||
	// st does not close it sometimes, 
 | 
			
		||||
	// close it manually.
 | 
			
		||||
| 
						 | 
				
			
			@ -118,8 +108,7 @@ int SrsListener::listen(int _port)
 | 
			
		|||
    }
 | 
			
		||||
    srs_verbose("st open socket success. fd=%d", fd);
 | 
			
		||||
    
 | 
			
		||||
    if ((tid = st_thread_create(listen_thread, this, 1, 0)) == NULL) {
 | 
			
		||||
        ret = ERROR_ST_CREATE_LISTEN_THREAD;
 | 
			
		||||
    if ((ret = pthread->start()) != ERROR_SUCCESS) {
 | 
			
		||||
        srs_error("st_thread_create listen thread error. ret=%d", ret);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -130,41 +119,32 @@ int SrsListener::listen(int _port)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsListener::listen_cycle()
 | 
			
		||||
void SrsListener::on_enter_loop()
 | 
			
		||||
{
 | 
			
		||||
	srs_trace("listen cycle start, port=%d, type=%d, fd=%d", port, type, fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsListener::cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	log_context->generate_id();
 | 
			
		||||
	srs_trace("listen cycle start, port=%d, type=%d, fd=%d", port, type, fd);
 | 
			
		||||
    st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);
 | 
			
		||||
    
 | 
			
		||||
    if(client_stfd == NULL){
 | 
			
		||||
        // ignore error.
 | 
			
		||||
        srs_warn("ignore accept thread stoppped for accept client error");
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd));
 | 
			
		||||
	
 | 
			
		||||
	while (loop) {
 | 
			
		||||
	    st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);
 | 
			
		||||
	    
 | 
			
		||||
	    if(client_stfd == NULL){
 | 
			
		||||
	        // ignore error.
 | 
			
		||||
	        srs_warn("ignore accept thread stoppped for accept client error");
 | 
			
		||||
	        continue;
 | 
			
		||||
        }
 | 
			
		||||
	    srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd));
 | 
			
		||||
    	
 | 
			
		||||
    	if ((ret = server->accept_client(type, client_stfd)) != ERROR_SUCCESS) {
 | 
			
		||||
    		srs_warn("accept client error. ret=%d", ret);
 | 
			
		||||
			continue;
 | 
			
		||||
    	}
 | 
			
		||||
 | 
			
		||||
    	srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret);
 | 
			
		||||
	if ((ret = server->accept_client(type, client_stfd)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_warn("accept client error. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SrsListener::listen_thread(void* arg)
 | 
			
		||||
{
 | 
			
		||||
	SrsListener* obj = (SrsListener*)arg;
 | 
			
		||||
	srs_assert(obj != NULL);
 | 
			
		||||
	
 | 
			
		||||
	obj->loop = true;
 | 
			
		||||
	obj->listen_cycle();
 | 
			
		||||
	srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret);
 | 
			
		||||
	
 | 
			
		||||
	return NULL;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsServer::SrsServer()
 | 
			
		||||
| 
						 | 
				
			
			@ -312,8 +292,7 @@ int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd)
 | 
			
		|||
		srs_error("exceed the max connections, drop client: "
 | 
			
		||||
			"clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd);
 | 
			
		||||
			
 | 
			
		||||
		st_netfd_close(client_stfd);
 | 
			
		||||
		::close(fd);
 | 
			
		||||
		srs_close_stfd(client_stfd);
 | 
			
		||||
		
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,9 +32,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
 | 
			
		||||
#include <srs_core_reload.hpp>
 | 
			
		||||
#include <srs_core_thread.hpp>
 | 
			
		||||
 | 
			
		||||
class SrsServer;
 | 
			
		||||
class SrsConnection;
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +44,7 @@ enum SrsListenerType
 | 
			
		|||
	SrsListenerApi
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SrsListener
 | 
			
		||||
class SrsListener : public ISrsThreadHandler
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	SrsListenerType type;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,19 +53,19 @@ private:
 | 
			
		|||
	st_netfd_t stfd;
 | 
			
		||||
	int port;
 | 
			
		||||
	SrsServer* server;
 | 
			
		||||
	st_thread_t tid;
 | 
			
		||||
	bool loop;
 | 
			
		||||
	SrsThread* pthread;
 | 
			
		||||
public:
 | 
			
		||||
	SrsListener(SrsServer* _server, SrsListenerType _type);
 | 
			
		||||
	virtual ~SrsListener();
 | 
			
		||||
public:
 | 
			
		||||
	virtual int listen(int port);
 | 
			
		||||
private:
 | 
			
		||||
	virtual void listen_cycle();
 | 
			
		||||
	static void* listen_thread(void* arg);
 | 
			
		||||
// interface ISrsThreadHandler.
 | 
			
		||||
public:
 | 
			
		||||
	virtual void on_enter_loop();
 | 
			
		||||
	virtual int cycle();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SrsServer : public SrsReloadHandler
 | 
			
		||||
class SrsServer : public ISrsReloadHandler
 | 
			
		||||
{
 | 
			
		||||
	friend class SrsListener;
 | 
			
		||||
private:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,6 +52,11 @@ void SrsSocket::set_send_timeout(int64_t timeout_us)
 | 
			
		|||
	send_timeout = timeout_us;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t SrsSocket::get_send_timeout()
 | 
			
		||||
{
 | 
			
		||||
	return send_timeout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t SrsSocket::get_recv_bytes()
 | 
			
		||||
{
 | 
			
		||||
	return recv_bytes;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,8 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
 | 
			
		||||
#include <srs_core.hpp>
 | 
			
		||||
 | 
			
		||||
#include <st.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* the socket provides TCP socket over st,
 | 
			
		||||
* that is, the sync socket mechanism.
 | 
			
		||||
| 
						 | 
				
			
			@ -52,6 +50,7 @@ public:
 | 
			
		|||
	virtual void set_recv_timeout(int64_t timeout_us);
 | 
			
		||||
	virtual int64_t get_recv_timeout();
 | 
			
		||||
	virtual void set_send_timeout(int64_t timeout_us);
 | 
			
		||||
	virtual int64_t get_send_timeout();
 | 
			
		||||
	virtual int64_t get_recv_bytes();
 | 
			
		||||
	virtual int64_t get_send_bytes();
 | 
			
		||||
	virtual int get_recv_kbps();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <srs_core_source.hpp>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
#include <srs_core_log.hpp>
 | 
			
		||||
#include <srs_core_protocol.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -37,8 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <srs_core_rtmp.hpp>
 | 
			
		||||
 | 
			
		||||
#define CONST_MAX_JITTER_MS 		500
 | 
			
		||||
#define DEFAULT_FRAME_TIME_MS 		10
 | 
			
		||||
#define PAUSED_SHRINK_SIZE			250
 | 
			
		||||
#define DEFAULT_FRAME_TIME_MS 		40
 | 
			
		||||
 | 
			
		||||
SrsRtmpJitter::SrsRtmpJitter()
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -49,9 +49,15 @@ SrsRtmpJitter::~SrsRtmpJitter()
 | 
			
		|||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t* corrected_time)
 | 
			
		||||
int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	// set to 0 for metadata.
 | 
			
		||||
	if (!msg->header.is_video() && !msg->header.is_audio()) {
 | 
			
		||||
		msg->header.timestamp = 0;
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	int sample_rate = tba;
 | 
			
		||||
	int frame_rate = tbv;
 | 
			
		||||
| 
						 | 
				
			
			@ -66,16 +72,16 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t*
 | 
			
		|||
	* 3. last_pkt_correct_time: simply add the positive delta, 
 | 
			
		||||
	* 	and enforce the time monotonically.
 | 
			
		||||
	*/
 | 
			
		||||
	u_int32_t time = msg->header.timestamp;
 | 
			
		||||
	int32_t delta = time - last_pkt_time;
 | 
			
		||||
	int64_t time = msg->header.timestamp;
 | 
			
		||||
	int64_t delta = time - last_pkt_time;
 | 
			
		||||
 | 
			
		||||
	// if jitter detected, reset the delta.
 | 
			
		||||
	if (delta < 0 || delta > CONST_MAX_JITTER_MS) {
 | 
			
		||||
		// calc the right diff by audio sample rate
 | 
			
		||||
		if (msg->header.is_audio() && sample_rate > 0) {
 | 
			
		||||
			delta = (int32_t)(delta * 1000.0 / sample_rate);
 | 
			
		||||
			delta = (int64_t)(delta * 1000.0 / sample_rate);
 | 
			
		||||
		} else if (msg->header.is_video() && frame_rate > 0) {
 | 
			
		||||
			delta = (int32_t)(delta * 1.0 / frame_rate);
 | 
			
		||||
			delta = (int64_t)(delta * 1.0 / frame_rate);
 | 
			
		||||
		} else {
 | 
			
		||||
			delta = DEFAULT_FRAME_TIME_MS;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -85,20 +91,16 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t*
 | 
			
		|||
			delta = DEFAULT_FRAME_TIME_MS;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		srs_info("jitter detected, last_pts=%d, pts=%d, diff=%d, last_time=%d, time=%d, diff=%d",
 | 
			
		||||
		srs_info("jitter detected, last_pts=%"PRId64", pts=%"PRId64", diff=%"PRId64", last_time=%"PRId64", time=%"PRId64", diff=%"PRId64"",
 | 
			
		||||
			last_pkt_time, time, time - last_pkt_time, last_pkt_correct_time, last_pkt_correct_time + delta, delta);
 | 
			
		||||
	} else {
 | 
			
		||||
		srs_verbose("timestamp no jitter. time=%d, last_pkt=%d, correct_to=%d", 
 | 
			
		||||
		srs_verbose("timestamp no jitter. time=%"PRId64", last_pkt=%"PRId64", correct_to=%"PRId64"", 
 | 
			
		||||
			time, last_pkt_time, last_pkt_correct_time + delta);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	last_pkt_correct_time = srs_max(0, last_pkt_correct_time + delta);
 | 
			
		||||
	
 | 
			
		||||
	if (corrected_time) {
 | 
			
		||||
		*corrected_time = last_pkt_correct_time;
 | 
			
		||||
	}
 | 
			
		||||
	msg->header.timestamp = last_pkt_correct_time;
 | 
			
		||||
	
 | 
			
		||||
	last_pkt_time = time;
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -109,19 +111,152 @@ int SrsRtmpJitter::get_time()
 | 
			
		|||
	return (int)last_pkt_correct_time;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsMessageQueue::SrsMessageQueue()
 | 
			
		||||
{
 | 
			
		||||
	queue_size_ms = 0;
 | 
			
		||||
	av_start_time = av_end_time = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsMessageQueue::~SrsMessageQueue()
 | 
			
		||||
{
 | 
			
		||||
	clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsMessageQueue::set_queue_size(double queue_size)
 | 
			
		||||
{
 | 
			
		||||
	queue_size_ms = (int)(queue_size * 1000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if (msg->header.is_video() || msg->header.is_audio()) {
 | 
			
		||||
		if (av_start_time == -1) {
 | 
			
		||||
			av_start_time = msg->header.timestamp;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		av_end_time = msg->header.timestamp;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	msgs.push_back(msg);
 | 
			
		||||
 | 
			
		||||
	while (av_end_time - av_start_time > queue_size_ms) {
 | 
			
		||||
		shrink();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsMessageQueue::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if (msgs.empty()) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (max_count == 0) {
 | 
			
		||||
		count = (int)msgs.size();
 | 
			
		||||
	} else {
 | 
			
		||||
		count = srs_min(max_count, (int)msgs.size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (count <= 0) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	pmsgs = new SrsSharedPtrMessage*[count];
 | 
			
		||||
	
 | 
			
		||||
	for (int i = 0; i < count; i++) {
 | 
			
		||||
		pmsgs[i] = msgs[i];
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	SrsSharedPtrMessage* last = msgs[count - 1];
 | 
			
		||||
	av_start_time = last->header.timestamp;
 | 
			
		||||
	
 | 
			
		||||
	if (count == (int)msgs.size()) {
 | 
			
		||||
		msgs.clear();
 | 
			
		||||
	} else {
 | 
			
		||||
		msgs.erase(msgs.begin(), msgs.begin() + count);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsMessageQueue::shrink()
 | 
			
		||||
{
 | 
			
		||||
	int iframe_index = -1;
 | 
			
		||||
	
 | 
			
		||||
	// issue the first iframe.
 | 
			
		||||
	// skip the first frame, whatever the type of it,
 | 
			
		||||
	// for when we shrinked, the first is the iframe,
 | 
			
		||||
	// we will directly remove the gop next time.
 | 
			
		||||
	for (int i = 1; i < (int)msgs.size(); i++) {
 | 
			
		||||
		SrsSharedPtrMessage* msg = msgs[i];
 | 
			
		||||
		
 | 
			
		||||
		if (msg->header.is_video()) {
 | 
			
		||||
			if (SrsCodec::video_is_keyframe(msg->payload, msg->size)) {
 | 
			
		||||
				// the max frame index to remove.
 | 
			
		||||
				iframe_index = i;
 | 
			
		||||
				
 | 
			
		||||
				// set the start time, we will remove until this frame.
 | 
			
		||||
				av_start_time = msg->header.timestamp;
 | 
			
		||||
				
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// no iframe, clear the queue.
 | 
			
		||||
	if (iframe_index < 0) {
 | 
			
		||||
		clear();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	srs_trace("shrink the cache queue, size=%d, removed=%d, max=%.2f", 
 | 
			
		||||
		(int)msgs.size(), iframe_index, queue_size_ms / 1000.0);
 | 
			
		||||
	
 | 
			
		||||
	// remove the first gop from the front
 | 
			
		||||
	for (int i = 0; i < iframe_index; i++) {
 | 
			
		||||
		SrsSharedPtrMessage* msg = msgs[i];
 | 
			
		||||
		srs_freep(msg);
 | 
			
		||||
	}
 | 
			
		||||
	msgs.erase(msgs.begin(), msgs.begin() + iframe_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsMessageQueue::clear()
 | 
			
		||||
{
 | 
			
		||||
	std::vector<SrsSharedPtrMessage*>::iterator it;
 | 
			
		||||
 | 
			
		||||
	for (it = msgs.begin(); it != msgs.end(); ++it) {
 | 
			
		||||
		SrsSharedPtrMessage* msg = *it;
 | 
			
		||||
		srs_freep(msg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msgs.clear();
 | 
			
		||||
	
 | 
			
		||||
	av_start_time = av_end_time = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsConsumer::SrsConsumer(SrsSource* _source)
 | 
			
		||||
{
 | 
			
		||||
	source = _source;
 | 
			
		||||
	paused = false;
 | 
			
		||||
	jitter = new SrsRtmpJitter();
 | 
			
		||||
	queue = new SrsMessageQueue();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsConsumer::~SrsConsumer()
 | 
			
		||||
{
 | 
			
		||||
	clear();
 | 
			
		||||
	
 | 
			
		||||
	source->on_consumer_destroy(this);
 | 
			
		||||
	srs_freep(jitter);
 | 
			
		||||
	srs_freep(queue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsConsumer::set_queue_size(double queue_size)
 | 
			
		||||
{
 | 
			
		||||
	queue->set_queue_size(queue_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsConsumer::get_time()
 | 
			
		||||
| 
						 | 
				
			
			@ -138,46 +273,21 @@ int SrsConsumer::enqueue(SrsSharedPtrMessage* msg, int tba, int tbv)
 | 
			
		|||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// TODO: check the queue size and drop packets if overflow.
 | 
			
		||||
	msgs.push_back(msg);
 | 
			
		||||
	if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if (msgs.empty()) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// paused, return nothing.
 | 
			
		||||
	if (paused) {
 | 
			
		||||
		if ((int)msgs.size() >= PAUSED_SHRINK_SIZE) {
 | 
			
		||||
			shrink();
 | 
			
		||||
		}
 | 
			
		||||
		return ret;
 | 
			
		||||
		return ERROR_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (max_count == 0) {
 | 
			
		||||
		count = (int)msgs.size();
 | 
			
		||||
	} else {
 | 
			
		||||
		count = srs_min(max_count, (int)msgs.size());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	pmsgs = new SrsSharedPtrMessage*[count];
 | 
			
		||||
	
 | 
			
		||||
	for (int i = 0; i < count; i++) {
 | 
			
		||||
		pmsgs[i] = msgs[i];
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (count == (int)msgs.size()) {
 | 
			
		||||
		msgs.clear();
 | 
			
		||||
	} else {
 | 
			
		||||
		msgs.erase(msgs.begin(), msgs.begin() + count);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
	return queue->get_packets(max_count, pmsgs, count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsConsumer::on_play_client_pause(bool is_pause)
 | 
			
		||||
| 
						 | 
				
			
			@ -190,68 +300,6 @@ int SrsConsumer::on_play_client_pause(bool is_pause)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsConsumer::shrink()
 | 
			
		||||
{
 | 
			
		||||
	int i = 0;
 | 
			
		||||
	std::vector<SrsSharedPtrMessage*>::iterator it;
 | 
			
		||||
	
 | 
			
		||||
	// issue the last video iframe.
 | 
			
		||||
	bool has_video = false;
 | 
			
		||||
	int frame_to_remove = 0;
 | 
			
		||||
	std::vector<SrsSharedPtrMessage*>::iterator iframe = msgs.end();
 | 
			
		||||
	for (i = 0, it = msgs.begin(); it != msgs.end(); ++it, i++) {
 | 
			
		||||
		SrsSharedPtrMessage* msg = *it;
 | 
			
		||||
		if (msg->header.is_video()) {
 | 
			
		||||
			has_video = true;
 | 
			
		||||
			if (SrsCodec::video_is_keyframe(msg->payload, msg->size)) {
 | 
			
		||||
				iframe = it;
 | 
			
		||||
				frame_to_remove = i + 1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// last iframe is the first elem, ignore it.
 | 
			
		||||
	if (iframe == msgs.begin()) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// recalc the frame to remove
 | 
			
		||||
	if (iframe == msgs.end()) {
 | 
			
		||||
		frame_to_remove = 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (!has_video) {
 | 
			
		||||
		frame_to_remove = (int)msgs.size();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	srs_trace("shrink the cache queue, has_video=%d, has_iframe=%d, size=%d, removed=%d", 
 | 
			
		||||
		has_video, iframe != msgs.end(), (int)msgs.size(), frame_to_remove);
 | 
			
		||||
	
 | 
			
		||||
	// if no video, remove all audio.
 | 
			
		||||
	if (!has_video) {
 | 
			
		||||
		clear();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// if exists video Iframe, remove the frames before it.
 | 
			
		||||
	if (iframe != msgs.end()) {
 | 
			
		||||
		for (it = msgs.begin(); it != iframe; ++it) {
 | 
			
		||||
			SrsSharedPtrMessage* msg = *it;
 | 
			
		||||
			srs_freep(msg);
 | 
			
		||||
		}
 | 
			
		||||
		msgs.erase(msgs.begin(), iframe);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsConsumer::clear()
 | 
			
		||||
{
 | 
			
		||||
	std::vector<SrsSharedPtrMessage*>::iterator it;
 | 
			
		||||
	for (it = msgs.begin(); it != msgs.end(); ++it) {
 | 
			
		||||
		SrsSharedPtrMessage* msg = *it;
 | 
			
		||||
		srs_freep(msg);
 | 
			
		||||
	}
 | 
			
		||||
	msgs.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsGopCache::SrsGopCache()
 | 
			
		||||
{
 | 
			
		||||
	cached_video_count = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -344,22 +392,25 @@ int SrsGopCache::dump(SrsConsumer* consumer, int tba, int tbv)
 | 
			
		|||
 | 
			
		||||
std::map<std::string, SrsSource*> SrsSource::pool;
 | 
			
		||||
 | 
			
		||||
SrsSource* SrsSource::find(const std::string &stream_url)
 | 
			
		||||
SrsSource* SrsSource::find(SrsRequest* req)
 | 
			
		||||
{
 | 
			
		||||
	string stream_url = req->get_stream_url();
 | 
			
		||||
	string vhost = req->vhost;
 | 
			
		||||
	
 | 
			
		||||
	if (pool.find(stream_url) == pool.end()) {
 | 
			
		||||
		pool[stream_url] = new SrsSource(stream_url);
 | 
			
		||||
		srs_verbose("create new source for url=%s", stream_url.c_str());
 | 
			
		||||
		pool[stream_url] = new SrsSource(req);
 | 
			
		||||
		srs_verbose("create new source for url=%s, vhost=%s", stream_url.c_str(), vhost.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return pool[stream_url];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsSource::SrsSource(std::string _stream_url)
 | 
			
		||||
SrsSource::SrsSource(SrsRequest* _req)
 | 
			
		||||
{
 | 
			
		||||
	stream_url = _stream_url;
 | 
			
		||||
	req = _req->copy();
 | 
			
		||||
	
 | 
			
		||||
#ifdef SRS_HLS
 | 
			
		||||
	hls = new SrsHls();
 | 
			
		||||
	hls = new SrsHls(this);
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef SRS_FFMPEG
 | 
			
		||||
	encoder = new SrsEncoder();
 | 
			
		||||
| 
						 | 
				
			
			@ -371,10 +422,14 @@ SrsSource::SrsSource(std::string _stream_url)
 | 
			
		|||
	_can_publish = true;
 | 
			
		||||
	
 | 
			
		||||
	gop_cache = new SrsGopCache();
 | 
			
		||||
	
 | 
			
		||||
	config->subscribe(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsSource::~SrsSource()
 | 
			
		||||
{
 | 
			
		||||
	config->unsubscribe(this);
 | 
			
		||||
	
 | 
			
		||||
	if (true) {
 | 
			
		||||
		std::vector<SrsConsumer*>::iterator it;
 | 
			
		||||
		for (it = consumers.begin(); it != consumers.end(); ++it) {
 | 
			
		||||
| 
						 | 
				
			
			@ -405,6 +460,167 @@ SrsSource::~SrsSource()
 | 
			
		|||
#ifdef SRS_FFMPEG
 | 
			
		||||
	srs_freep(encoder);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	srs_freep(req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsSource::on_reload_gop_cache(string vhost)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if (req->vhost != vhost) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// gop cache changed.
 | 
			
		||||
	bool enabled_cache = config->get_gop_cache(vhost);
 | 
			
		||||
	
 | 
			
		||||
	srs_trace("vhost %s gop_cache changed to %d, source url=%s", 
 | 
			
		||||
		vhost.c_str(), enabled_cache, req->get_stream_url().c_str());
 | 
			
		||||
	
 | 
			
		||||
	set_cache(enabled_cache);
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsSource::on_reload_queue_length(string vhost)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if (req->vhost != vhost) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	double queue_size = config->get_queue_length(req->vhost);
 | 
			
		||||
	
 | 
			
		||||
	if (true) {
 | 
			
		||||
		std::vector<SrsConsumer*>::iterator it;
 | 
			
		||||
		
 | 
			
		||||
		for (it = consumers.begin(); it != consumers.end(); ++it) {
 | 
			
		||||
			SrsConsumer* consumer = *it;
 | 
			
		||||
			consumer->set_queue_size(queue_size);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		srs_trace("consumers reload queue size success.");
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (true) {
 | 
			
		||||
		std::vector<SrsForwarder*>::iterator it;
 | 
			
		||||
		
 | 
			
		||||
		for (it = forwarders.begin(); it != forwarders.end(); ++it) {
 | 
			
		||||
			SrsForwarder* forwarder = *it;
 | 
			
		||||
			forwarder->set_queue_size(queue_size);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		srs_trace("forwarders reload queue size success.");
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsSource::on_reload_forward(string vhost)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if (req->vhost != vhost) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// forwarders
 | 
			
		||||
	destroy_forwarders();
 | 
			
		||||
	if ((ret = create_forwarders()) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("create forwarders failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	srs_trace("vhost %s forwarders reload success", vhost.c_str());
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsSource::on_reload_hls(string vhost)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if (req->vhost != vhost) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
#ifdef SRS_HLS
 | 
			
		||||
	hls->on_unpublish();
 | 
			
		||||
	if ((ret = hls->on_publish(req)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("hls publish failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	srs_trace("vhost %s hls reload success", vhost.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsSource::on_reload_transcode(string vhost)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if (req->vhost != vhost) {
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
#ifdef SRS_FFMPEG
 | 
			
		||||
	encoder->on_unpublish();
 | 
			
		||||
	if ((ret = encoder->on_publish(req)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("start encoder failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	srs_trace("vhost %s transcode reload success", vhost.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsSource::on_forwarder_start(SrsForwarder* forwarder)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
		
 | 
			
		||||
	// feed the forwarder the metadata/sequence header,
 | 
			
		||||
	// when reload to enable the forwarder.
 | 
			
		||||
	if (cache_metadata && (ret = forwarder->on_meta_data(cache_metadata->copy())) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("forwarder process onMetaData message failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if (cache_sh_video && (ret = forwarder->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("forwarder process video sequence header message failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if (cache_sh_audio && (ret = forwarder->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("forwarder process audio sequence header message failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsSource::on_hls_start()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
#ifdef SRS_HLS
 | 
			
		||||
		
 | 
			
		||||
	// feed the hls the metadata/sequence header,
 | 
			
		||||
	// when reload to enable the hls.
 | 
			
		||||
	// TODO: maybe need to decode the metadata?
 | 
			
		||||
	if (cache_sh_video && (ret = hls->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("hls process video sequence header message failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if (cache_sh_audio && (ret = hls->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("hls process audio sequence header message failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
#endif
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SrsSource::can_publish()
 | 
			
		||||
| 
						 | 
				
			
			@ -417,7 +633,7 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata
 | 
			
		|||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
#ifdef SRS_HLS
 | 
			
		||||
	if ((ret = hls->on_meta_data(metadata)) != ERROR_SUCCESS) {
 | 
			
		||||
	if (metadata && (ret = hls->on_meta_data(metadata->metadata)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("hls process onMetaData message failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -425,6 +641,8 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata
 | 
			
		|||
	
 | 
			
		||||
	metadata->metadata->set("server", new SrsAmf0String(
 | 
			
		||||
		RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")"));
 | 
			
		||||
	metadata->metadata->set("contributor", 
 | 
			
		||||
		new SrsAmf0String(RTMP_SIG_SRS_CONTRIBUTOR));
 | 
			
		||||
	
 | 
			
		||||
	SrsAmf0Any* prop = NULL;
 | 
			
		||||
	if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) {
 | 
			
		||||
| 
						 | 
				
			
			@ -620,7 +838,7 @@ int SrsSource::on_video(SrsCommonMessage* video)
 | 
			
		|||
 | 
			
		||||
	// cache the last gop packets
 | 
			
		||||
	if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("shrink gop cache failed. ret=%d", ret);
 | 
			
		||||
		srs_error("gop cache msg failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	srs_verbose("cache gop success.");
 | 
			
		||||
| 
						 | 
				
			
			@ -628,39 +846,33 @@ int SrsSource::on_video(SrsCommonMessage* video)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsSource::on_publish(SrsRequest* req)
 | 
			
		||||
int SrsSource::on_publish(SrsRequest* _req)
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	// update the request object.
 | 
			
		||||
	srs_freep(req);
 | 
			
		||||
	req = _req->copy();
 | 
			
		||||
	srs_assert(req);
 | 
			
		||||
	
 | 
			
		||||
	_can_publish = false;
 | 
			
		||||
 | 
			
		||||
	// TODO: support reload.
 | 
			
		||||
	
 | 
			
		||||
	// create forwarders
 | 
			
		||||
	SrsConfDirective* conf = config->get_forward(req->vhost);
 | 
			
		||||
	for (int i = 0; conf && i < (int)conf->args.size(); i++) {
 | 
			
		||||
		std::string forward_server = conf->args.at(i);
 | 
			
		||||
		
 | 
			
		||||
		SrsForwarder* forwarder = new SrsForwarder();
 | 
			
		||||
		forwarders.push_back(forwarder);
 | 
			
		||||
		
 | 
			
		||||
		if ((ret = forwarder->on_publish(req, forward_server)) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_error("start forwarder failed. "
 | 
			
		||||
				"vhost=%s, app=%s, stream=%s, forward-to=%s",
 | 
			
		||||
				req->vhost.c_str(), req->app.c_str(), req->stream.c_str(),
 | 
			
		||||
				forward_server.c_str());
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	if ((ret = create_forwarders()) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("create forwarders failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
#ifdef SRS_FFMPEG
 | 
			
		||||
	if ((ret = encoder->on_publish(req)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("start encoder failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	
 | 
			
		||||
#ifdef SRS_HLS
 | 
			
		||||
	if ((ret = hls->on_publish(req)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("start hls failed. ret=%d", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -670,19 +882,14 @@ int SrsSource::on_publish(SrsRequest* req)
 | 
			
		|||
 | 
			
		||||
void SrsSource::on_unpublish()
 | 
			
		||||
{
 | 
			
		||||
	// close all forwarders
 | 
			
		||||
	std::vector<SrsForwarder*>::iterator it;
 | 
			
		||||
	for (it = forwarders.begin(); it != forwarders.end(); ++it) {
 | 
			
		||||
		SrsForwarder* forwarder = *it;
 | 
			
		||||
		forwarder->on_unpublish();
 | 
			
		||||
		srs_freep(forwarder);
 | 
			
		||||
	}
 | 
			
		||||
	forwarders.clear();
 | 
			
		||||
	// destroy all forwarders
 | 
			
		||||
	destroy_forwarders();
 | 
			
		||||
 | 
			
		||||
#ifdef SRS_FFMPEG
 | 
			
		||||
	encoder->on_unpublish();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	// TODO: HLS should continue previous sequence and stream.
 | 
			
		||||
#ifdef SRS_HLS
 | 
			
		||||
	hls->on_unpublish();
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -706,6 +913,9 @@ void SrsSource::on_unpublish()
 | 
			
		|||
	
 | 
			
		||||
	consumer = new SrsConsumer(this);
 | 
			
		||||
	consumers.push_back(consumer);
 | 
			
		||||
	
 | 
			
		||||
	double queue_size = config->get_queue_length(req->vhost);
 | 
			
		||||
	consumer->set_queue_size(queue_size);
 | 
			
		||||
 | 
			
		||||
	if (cache_metadata && (ret = consumer->enqueue(cache_metadata->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
 | 
			
		||||
		srs_error("dispatch metadata failed. ret=%d", ret);
 | 
			
		||||
| 
						 | 
				
			
			@ -729,6 +939,8 @@ void SrsSource::on_unpublish()
 | 
			
		|||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	srs_trace("create consumer, queue_size=%.2f, tba=%d, tbv=%d", queue_size, sample_rate, frame_rate);
 | 
			
		||||
	
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -747,3 +959,40 @@ void SrsSource::set_cache(bool enabled)
 | 
			
		|||
	gop_cache->set(enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsSource::create_forwarders()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	SrsConfDirective* conf = config->get_forward(req->vhost);
 | 
			
		||||
	for (int i = 0; conf && i < (int)conf->args.size(); i++) {
 | 
			
		||||
		std::string forward_server = conf->args.at(i);
 | 
			
		||||
		
 | 
			
		||||
		SrsForwarder* forwarder = new SrsForwarder(this);
 | 
			
		||||
		forwarders.push_back(forwarder);
 | 
			
		||||
	
 | 
			
		||||
		double queue_size = config->get_queue_length(req->vhost);
 | 
			
		||||
		forwarder->set_queue_size(queue_size);
 | 
			
		||||
		
 | 
			
		||||
		if ((ret = forwarder->on_publish(req, forward_server)) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_error("start forwarder failed. "
 | 
			
		||||
				"vhost=%s, app=%s, stream=%s, forward-to=%s",
 | 
			
		||||
				req->vhost.c_str(), req->app.c_str(), req->stream.c_str(),
 | 
			
		||||
				forward_server.c_str());
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsSource::destroy_forwarders()
 | 
			
		||||
{
 | 
			
		||||
	std::vector<SrsForwarder*>::iterator it;
 | 
			
		||||
	for (it = forwarders.begin(); it != forwarders.end(); ++it) {
 | 
			
		||||
		SrsForwarder* forwarder = *it;
 | 
			
		||||
		forwarder->on_unpublish();
 | 
			
		||||
		srs_freep(forwarder);
 | 
			
		||||
	}
 | 
			
		||||
	forwarders.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										100
									
								
								trunk/src/core/srs_core_source.hpp
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										100
									
								
								trunk/src/core/srs_core_source.hpp
									
										
									
									
									
										
										
										Normal file → Executable file
									
								
							| 
						 | 
				
			
			@ -34,6 +34,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		|||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include <srs_core_reload.hpp>
 | 
			
		||||
 | 
			
		||||
class SrsSource;
 | 
			
		||||
class SrsCommonMessage;
 | 
			
		||||
class SrsOnMetaDataPacket;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,24 +56,64 @@ class SrsEncoder;
 | 
			
		|||
class SrsRtmpJitter
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	u_int32_t last_pkt_time;
 | 
			
		||||
	u_int32_t last_pkt_correct_time;
 | 
			
		||||
	int64_t last_pkt_time;
 | 
			
		||||
	int64_t last_pkt_correct_time;
 | 
			
		||||
public:
 | 
			
		||||
	SrsRtmpJitter();
 | 
			
		||||
	virtual ~SrsRtmpJitter();
 | 
			
		||||
public:
 | 
			
		||||
	/**
 | 
			
		||||
	* detect the time jitter and correct it.
 | 
			
		||||
	* @param corrected_time output the 64bits time.
 | 
			
		||||
	* 		ignore if NULL.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t* corrected_time = NULL);
 | 
			
		||||
	virtual int correct(SrsSharedPtrMessage* msg, int tba, int tbv);
 | 
			
		||||
	/**
 | 
			
		||||
	* get current client time, the last packet time.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int get_time();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* the message queue for the consumer(client), forwarder.
 | 
			
		||||
* we limit the size in seconds, drop old messages(the whole gop) if full.
 | 
			
		||||
*/
 | 
			
		||||
class SrsMessageQueue
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	int64_t av_start_time;
 | 
			
		||||
	int64_t av_end_time;
 | 
			
		||||
	int queue_size_ms;
 | 
			
		||||
	std::vector<SrsSharedPtrMessage*> msgs;
 | 
			
		||||
public:
 | 
			
		||||
	SrsMessageQueue();
 | 
			
		||||
	virtual ~SrsMessageQueue();
 | 
			
		||||
public:
 | 
			
		||||
	/**
 | 
			
		||||
	* set the queue size
 | 
			
		||||
	* @param queue_size the queue size in seconds.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual void set_queue_size(double queue_size);
 | 
			
		||||
public:
 | 
			
		||||
	/**
 | 
			
		||||
	* enqueue the message, the timestamp always monotonically.
 | 
			
		||||
	* @param msg, the msg to enqueue, user never free it whatever the return code.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int enqueue(SrsSharedPtrMessage* msg);
 | 
			
		||||
	/**
 | 
			
		||||
	* get packets in consumer queue.
 | 
			
		||||
	* @pmsgs SrsMessages*[], output the prt array.
 | 
			
		||||
	* @count the count in array.
 | 
			
		||||
	* @max_count the max count to dequeue, 0 to dequeue all.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count);
 | 
			
		||||
private:
 | 
			
		||||
	/**
 | 
			
		||||
	* remove a gop from the front.
 | 
			
		||||
	* if no iframe found, clear it.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual void shrink();
 | 
			
		||||
	virtual void clear();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* the consumer for SrsSource, that is a play client.
 | 
			
		||||
*/
 | 
			
		||||
| 
						 | 
				
			
			@ -80,11 +122,13 @@ class SrsConsumer
 | 
			
		|||
private:
 | 
			
		||||
	SrsRtmpJitter* jitter;
 | 
			
		||||
	SrsSource* source;
 | 
			
		||||
	std::vector<SrsSharedPtrMessage*> msgs;
 | 
			
		||||
	SrsMessageQueue* queue;
 | 
			
		||||
	bool paused;
 | 
			
		||||
public:
 | 
			
		||||
	SrsConsumer(SrsSource* _source);
 | 
			
		||||
	virtual ~SrsConsumer();
 | 
			
		||||
public:
 | 
			
		||||
	virtual void set_queue_size(double queue_size);
 | 
			
		||||
public:
 | 
			
		||||
	/**
 | 
			
		||||
	* get current client time, the last packet time.
 | 
			
		||||
| 
						 | 
				
			
			@ -109,13 +153,6 @@ public:
 | 
			
		|||
	* when client send the pause message.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int on_play_client_pause(bool is_pause);
 | 
			
		||||
private:
 | 
			
		||||
	/**
 | 
			
		||||
	* when paused, shrink the cache queue,
 | 
			
		||||
	* remove to cache only one gop.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual void shrink();
 | 
			
		||||
	virtual void clear();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -158,20 +195,21 @@ public:
 | 
			
		|||
/**
 | 
			
		||||
* live streaming source.
 | 
			
		||||
*/
 | 
			
		||||
class SrsSource
 | 
			
		||||
class SrsSource : public ISrsReloadHandler
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	static std::map<std::string, SrsSource*> pool;
 | 
			
		||||
public:
 | 
			
		||||
	/**
 | 
			
		||||
	* find stream by vhost/app/stream.
 | 
			
		||||
	* @stream_url the stream url, for example, myserver.xxx.com/app/stream
 | 
			
		||||
	* @param req the client request.
 | 
			
		||||
	* @return the matched source, never be NULL.
 | 
			
		||||
	* @remark stream_url should without port and schema.
 | 
			
		||||
	*/
 | 
			
		||||
	static SrsSource* find(const std::string& stream_url);
 | 
			
		||||
	static SrsSource* find(SrsRequest* req);
 | 
			
		||||
private:
 | 
			
		||||
	std::string stream_url;
 | 
			
		||||
	// deep copy of client request.
 | 
			
		||||
	SrsRequest* req;
 | 
			
		||||
	// to delivery stream to clients.
 | 
			
		||||
	std::vector<SrsConsumer*> consumers;
 | 
			
		||||
	// hls handler.
 | 
			
		||||
| 
						 | 
				
			
			@ -206,19 +244,43 @@ private:
 | 
			
		|||
	// the cached audio sequence header.
 | 
			
		||||
	SrsSharedPtrMessage* cache_sh_audio;
 | 
			
		||||
public:
 | 
			
		||||
	SrsSource(std::string _stream_url);
 | 
			
		||||
	/**
 | 
			
		||||
	* @param _req the client request object, 
 | 
			
		||||
	* 	this object will deep copy it for reload.
 | 
			
		||||
	*/
 | 
			
		||||
	SrsSource(SrsRequest* _req);
 | 
			
		||||
	virtual ~SrsSource();
 | 
			
		||||
// interface ISrsReloadHandler
 | 
			
		||||
public:
 | 
			
		||||
	virtual int on_reload_gop_cache(std::string vhost);
 | 
			
		||||
	virtual int on_reload_queue_length(std::string vhost);
 | 
			
		||||
	virtual int on_reload_forward(std::string vhost);
 | 
			
		||||
	virtual int on_reload_hls(std::string vhost);
 | 
			
		||||
	virtual int on_reload_transcode(std::string vhost);
 | 
			
		||||
public:
 | 
			
		||||
	// for the SrsForwarder to callback to request the sequence headers.
 | 
			
		||||
	virtual int on_forwarder_start(SrsForwarder* forwarder);
 | 
			
		||||
	// for the SrsHls to callback to request the sequence headers.
 | 
			
		||||
	virtual int on_hls_start();
 | 
			
		||||
public:
 | 
			
		||||
	virtual bool can_publish();
 | 
			
		||||
	virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
 | 
			
		||||
	virtual int on_audio(SrsCommonMessage* audio);
 | 
			
		||||
	virtual int on_video(SrsCommonMessage* video);
 | 
			
		||||
	virtual int on_publish(SrsRequest* req);
 | 
			
		||||
	/**
 | 
			
		||||
	* publish stream event notify.
 | 
			
		||||
	* @param _req the request from client, the source will deep copy it,
 | 
			
		||||
	* 		for when reload the request of client maybe invalid.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int on_publish(SrsRequest* _req);
 | 
			
		||||
	virtual void on_unpublish();
 | 
			
		||||
public:
 | 
			
		||||
	virtual int create_consumer(SrsConsumer*& consumer);
 | 
			
		||||
	virtual void on_consumer_destroy(SrsConsumer* consumer);
 | 
			
		||||
	virtual void set_cache(bool enabled);
 | 
			
		||||
private:
 | 
			
		||||
	virtual int create_forwarders();
 | 
			
		||||
	virtual void destroy_forwarders();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										156
									
								
								trunk/src/core/srs_core_thread.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								trunk/src/core/srs_core_thread.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,156 @@
 | 
			
		|||
/*
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2013 winlin
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
this software and associated documentation files (the "Software"), to deal in
 | 
			
		||||
the Software without restriction, including without limitation the rights to
 | 
			
		||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 | 
			
		||||
the Software, and to permit persons to whom the Software is furnished to do so,
 | 
			
		||||
subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 | 
			
		||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 | 
			
		||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
			
		||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <srs_core_thread.hpp>
 | 
			
		||||
 | 
			
		||||
#include <srs_core_error.hpp>
 | 
			
		||||
#include <srs_core_log.hpp>
 | 
			
		||||
 | 
			
		||||
ISrsThreadHandler::ISrsThreadHandler()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ISrsThreadHandler::~ISrsThreadHandler()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ISrsThreadHandler::on_enter_loop()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ISrsThreadHandler::on_before_cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ISrsThreadHandler::on_end_cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ISrsThreadHandler::on_leave_loop()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_ms)
 | 
			
		||||
{
 | 
			
		||||
	handler = thread_handler;
 | 
			
		||||
	cycle_interval_milliseconds = interval_ms;
 | 
			
		||||
	
 | 
			
		||||
	tid = NULL;
 | 
			
		||||
	loop = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SrsThread::~SrsThread()
 | 
			
		||||
{
 | 
			
		||||
	stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SrsThread::start()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
    if(tid) {
 | 
			
		||||
        srs_info("thread already running.");
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if((tid = st_thread_create(thread_fun, this, 1, 0)) == NULL){
 | 
			
		||||
		ret = ERROR_ST_CREATE_CYCLE_THREAD;
 | 
			
		||||
        srs_error("st_thread_create failed. ret=%d", ret);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsThread::stop()
 | 
			
		||||
{
 | 
			
		||||
	if (tid) {
 | 
			
		||||
		loop = false;
 | 
			
		||||
		
 | 
			
		||||
		// the interrupt will cause the socket to read/write error,
 | 
			
		||||
		// which will terminate the cycle thread.
 | 
			
		||||
		st_thread_interrupt(tid);
 | 
			
		||||
		
 | 
			
		||||
		// wait the thread to exit.
 | 
			
		||||
		st_thread_join(tid, NULL);
 | 
			
		||||
		
 | 
			
		||||
		tid = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SrsThread::thread_cycle()
 | 
			
		||||
{
 | 
			
		||||
	int ret = ERROR_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	srs_assert(handler);
 | 
			
		||||
	
 | 
			
		||||
	log_context->generate_id();
 | 
			
		||||
	srs_trace("thread cycle start");
 | 
			
		||||
 | 
			
		||||
	handler->on_end_cycle();
 | 
			
		||||
	
 | 
			
		||||
	loop = true;
 | 
			
		||||
	while (loop) {
 | 
			
		||||
		if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_warn("thread on before cycle failed, ignored and retry, ret=%d", ret);
 | 
			
		||||
			goto failed;
 | 
			
		||||
		}
 | 
			
		||||
		srs_info("thread on before cycle success");
 | 
			
		||||
		
 | 
			
		||||
		if ((ret = handler->cycle()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_warn("thread cycle failed, ignored and retry, ret=%d", ret);
 | 
			
		||||
			goto failed;
 | 
			
		||||
		}
 | 
			
		||||
		srs_info("thread cycle success");
 | 
			
		||||
		
 | 
			
		||||
		if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) {
 | 
			
		||||
			srs_warn("thread on end cycle failed, ignored and retry, ret=%d", ret);
 | 
			
		||||
			goto failed;
 | 
			
		||||
		}
 | 
			
		||||
		srs_info("thread on end cycle success");
 | 
			
		||||
 | 
			
		||||
failed:
 | 
			
		||||
		if (!loop) {
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		st_usleep(cycle_interval_milliseconds * 1000);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	handler->on_leave_loop();
 | 
			
		||||
	srs_trace("thread cycle finished");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SrsThread::thread_fun(void* arg)
 | 
			
		||||
{
 | 
			
		||||
	SrsThread* obj = (SrsThread*)arg;
 | 
			
		||||
	srs_assert(obj);
 | 
			
		||||
	
 | 
			
		||||
	obj->thread_cycle();
 | 
			
		||||
	
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								trunk/src/core/srs_core_thread.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								trunk/src/core/srs_core_thread.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,98 @@
 | 
			
		|||
/*
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2013 winlin
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
this software and associated documentation files (the "Software"), to deal in
 | 
			
		||||
the Software without restriction, including without limitation the rights to
 | 
			
		||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 | 
			
		||||
the Software, and to permit persons to whom the Software is furnished to do so,
 | 
			
		||||
subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 | 
			
		||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 | 
			
		||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
			
		||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef SRS_CORE_THREAD_HPP
 | 
			
		||||
#define SRS_CORE_THREAD_HPP
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#include <srs_core_thread.hpp>
 | 
			
		||||
*/
 | 
			
		||||
#include <srs_core.hpp>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* the handler for the thread, callback interface.
 | 
			
		||||
* the thread model defines as:
 | 
			
		||||
* 	handler->on_enter_loop()
 | 
			
		||||
* 	while loop:
 | 
			
		||||
*		handler->on_before_cycle()
 | 
			
		||||
*		handler->cycle()
 | 
			
		||||
*		handler->on_end_cycle()
 | 
			
		||||
*		if !loop then break for user stop thread.
 | 
			
		||||
*		sleep(CycleIntervalMilliseconds)
 | 
			
		||||
* 	handler->on_leave_loop()
 | 
			
		||||
* when stop, the thread will interrupt the st_thread,
 | 
			
		||||
* which will cause the socket to return error and 
 | 
			
		||||
* terminate the cycle thread.
 | 
			
		||||
*/
 | 
			
		||||
class ISrsThreadHandler
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	ISrsThreadHandler();
 | 
			
		||||
	virtual ~ISrsThreadHandler();
 | 
			
		||||
public:
 | 
			
		||||
	virtual void on_enter_loop();
 | 
			
		||||
	virtual int on_before_cycle();
 | 
			
		||||
	virtual int cycle() = 0;
 | 
			
		||||
	virtual int on_end_cycle();
 | 
			
		||||
	virtual void on_leave_loop();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* provides servies from st_thread_t,
 | 
			
		||||
* for common thread usage.
 | 
			
		||||
*/
 | 
			
		||||
class SrsThread
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	st_thread_t tid;
 | 
			
		||||
	bool loop;
 | 
			
		||||
private:
 | 
			
		||||
	ISrsThreadHandler* handler;
 | 
			
		||||
	int64_t cycle_interval_milliseconds;
 | 
			
		||||
public:
 | 
			
		||||
	/**
 | 
			
		||||
	* initialize the thread.
 | 
			
		||||
	* @param thread_handler, the cycle handler for the thread.
 | 
			
		||||
	* @param interval_ms, the sleep interval when cycle finished.
 | 
			
		||||
	*/
 | 
			
		||||
	SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_ms);
 | 
			
		||||
	virtual ~SrsThread();
 | 
			
		||||
public:
 | 
			
		||||
	/**
 | 
			
		||||
	* start the thread, invoke the cycle of handler util
 | 
			
		||||
	* user stop the thread.
 | 
			
		||||
	* @remark ignore any error of cycle of handler.
 | 
			
		||||
	* @remark user can start multiple times, ignore if already started.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual int start();
 | 
			
		||||
	/**
 | 
			
		||||
	* stop the thread, wait for the thread to terminate.
 | 
			
		||||
	* @remark user can stop multiple times, ignore if already stopped.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual void stop();
 | 
			
		||||
private:
 | 
			
		||||
	virtual void thread_cycle();
 | 
			
		||||
	static void* thread_fun(void* arg);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1,60 +1,62 @@
 | 
			
		|||
file
 | 
			
		||||
	main readonly separator,
 | 
			
		||||
	..\main\srs_main_server.cpp,
 | 
			
		||||
	auto readonly separator,
 | 
			
		||||
	..\..\objs\srs_auto_headers.hpp,
 | 
			
		||||
	core readonly separator,
 | 
			
		||||
	..\core\srs_core.hpp,
 | 
			
		||||
	..\core\srs_core.cpp,
 | 
			
		||||
	..\core\srs_core_error.hpp,
 | 
			
		||||
	..\core\srs_core_error.cpp,
 | 
			
		||||
	..\core\srs_core_autofree.hpp,
 | 
			
		||||
	..\core\srs_core_autofree.cpp,
 | 
			
		||||
	..\core\srs_core_server.hpp,
 | 
			
		||||
	..\core\srs_core_server.cpp,
 | 
			
		||||
	..\core\srs_core_reload.hpp,
 | 
			
		||||
	..\core\srs_core_reload.cpp,
 | 
			
		||||
	..\core\srs_core_config.hpp,
 | 
			
		||||
	..\core\srs_core_config.cpp,
 | 
			
		||||
	..\core\srs_core_refer.hpp,
 | 
			
		||||
	..\core\srs_core_refer.cpp,
 | 
			
		||||
	..\core\srs_core_conn.hpp,
 | 
			
		||||
	..\core\srs_core_conn.cpp,
 | 
			
		||||
	..\core\srs_core_client.hpp,
 | 
			
		||||
	..\core\srs_core_client.cpp,
 | 
			
		||||
        ..\core\srs_core_http.hpp,
 | 
			
		||||
        ..\core\srs_core_http.cpp,
 | 
			
		||||
	..\core\srs_core_source.hpp,
 | 
			
		||||
	..\core\srs_core_source.cpp,
 | 
			
		||||
	..\core\srs_core_forward.hpp,
 | 
			
		||||
	..\core\srs_core_forward.cpp,
 | 
			
		||||
	..\core\srs_core_encoder.hpp,
 | 
			
		||||
	..\core\srs_core_encoder.cpp,
 | 
			
		||||
	..\core\srs_core_hls.hpp,
 | 
			
		||||
	..\core\srs_core_hls.cpp,
 | 
			
		||||
	..\core\srs_core_codec.hpp,
 | 
			
		||||
	..\core\srs_core_codec.cpp,
 | 
			
		||||
	..\core\srs_core_rtmp.hpp,
 | 
			
		||||
	..\core\srs_core_rtmp.cpp,
 | 
			
		||||
	..\core\srs_core_handshake.hpp,
 | 
			
		||||
	..\core\srs_core_handshake.cpp,
 | 
			
		||||
	..\core\srs_core_protocol.hpp,
 | 
			
		||||
	..\core\srs_core_protocol.cpp,
 | 
			
		||||
	..\core\srs_core_amf0.hpp,
 | 
			
		||||
	..\core\srs_core_amf0.cpp,
 | 
			
		||||
	..\core\srs_core_stream.hpp,
 | 
			
		||||
	..\core\srs_core_stream.cpp,
 | 
			
		||||
	..\core\srs_core_socket.hpp,
 | 
			
		||||
	..\core\srs_core_socket.cpp,
 | 
			
		||||
	..\core\srs_core_buffer.hpp,
 | 
			
		||||
	..\core\srs_core_buffer.cpp,
 | 
			
		||||
	..\core\srs_core_pithy_print.hpp,
 | 
			
		||||
	..\core\srs_core_pithy_print.cpp,
 | 
			
		||||
	..\core\srs_core_log.hpp,
 | 
			
		||||
	..\core\srs_core_log.cpp,
 | 
			
		||||
	research readonly separator,
 | 
			
		||||
	..\..\research\ts_info.cc;
 | 
			
		||||
    main readonly separator,
 | 
			
		||||
    ..\main\srs_main_server.cpp,
 | 
			
		||||
    auto readonly separator,
 | 
			
		||||
    ..\..\objs\srs_auto_headers.hpp,
 | 
			
		||||
    core readonly separator,
 | 
			
		||||
    ..\core\srs_core.hpp,
 | 
			
		||||
    ..\core\srs_core.cpp,
 | 
			
		||||
    ..\core\srs_core_amf0.hpp,
 | 
			
		||||
    ..\core\srs_core_amf0.cpp,
 | 
			
		||||
    ..\core\srs_core_autofree.hpp,
 | 
			
		||||
    ..\core\srs_core_autofree.cpp,
 | 
			
		||||
    ..\core\srs_core_buffer.hpp,
 | 
			
		||||
    ..\core\srs_core_buffer.cpp,
 | 
			
		||||
    ..\core\srs_core_client.hpp,
 | 
			
		||||
    ..\core\srs_core_client.cpp,
 | 
			
		||||
    ..\core\srs_core_codec.hpp,
 | 
			
		||||
    ..\core\srs_core_codec.cpp,
 | 
			
		||||
    ..\core\srs_core_config.hpp,
 | 
			
		||||
    ..\core\srs_core_config.cpp,
 | 
			
		||||
    ..\core\srs_core_conn.hpp,
 | 
			
		||||
    ..\core\srs_core_conn.cpp,
 | 
			
		||||
    ..\core\srs_core_encoder.hpp,
 | 
			
		||||
    ..\core\srs_core_encoder.cpp,
 | 
			
		||||
    ..\core\srs_core_error.hpp,
 | 
			
		||||
    ..\core\srs_core_error.cpp,
 | 
			
		||||
    ..\core\srs_core_forward.hpp,
 | 
			
		||||
    ..\core\srs_core_forward.cpp,
 | 
			
		||||
    ..\core\srs_core_handshake.hpp,
 | 
			
		||||
    ..\core\srs_core_handshake.cpp,
 | 
			
		||||
    ..\core\srs_core_hls.hpp,
 | 
			
		||||
    ..\core\srs_core_hls.cpp,
 | 
			
		||||
    ..\core\srs_core_http.hpp,
 | 
			
		||||
    ..\core\srs_core_http.cpp,
 | 
			
		||||
    ..\core\srs_core_log.hpp,
 | 
			
		||||
    ..\core\srs_core_log.cpp,
 | 
			
		||||
    ..\core\srs_core_pithy_print.hpp,
 | 
			
		||||
    ..\core\srs_core_pithy_print.cpp,
 | 
			
		||||
    ..\core\srs_core_protocol.hpp,
 | 
			
		||||
    ..\core\srs_core_protocol.cpp,
 | 
			
		||||
    ..\core\srs_core_refer.hpp,
 | 
			
		||||
    ..\core\srs_core_refer.cpp,
 | 
			
		||||
    ..\core\srs_core_reload.hpp,
 | 
			
		||||
    ..\core\srs_core_reload.cpp,
 | 
			
		||||
    ..\core\srs_core_rtmp.hpp,
 | 
			
		||||
    ..\core\srs_core_rtmp.cpp,
 | 
			
		||||
    ..\core\srs_core_thread.hpp,
 | 
			
		||||
    ..\core\srs_core_thread.cpp,
 | 
			
		||||
    ..\core\srs_core_server.hpp,
 | 
			
		||||
    ..\core\srs_core_server.cpp,
 | 
			
		||||
    ..\core\srs_core_stream.hpp,
 | 
			
		||||
    ..\core\srs_core_stream.cpp,
 | 
			
		||||
    ..\core\srs_core_socket.hpp,
 | 
			
		||||
    ..\core\srs_core_socket.cpp,
 | 
			
		||||
    ..\core\srs_core_source.hpp,
 | 
			
		||||
    ..\core\srs_core_source.cpp,
 | 
			
		||||
    research readonly separator,
 | 
			
		||||
    ..\..\research\ts_info.cc;
 | 
			
		||||
 | 
			
		||||
mainconfig
 | 
			
		||||
	"" = "MAIN";
 | 
			
		||||
    "" = "MAIN";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue