diff --git a/README.md b/README.md index 9204d415c..6159a5205 100755 --- a/README.md +++ b/README.md @@ -9,21 +9,41 @@ see also: [https://github.com/winlinvip/simple-rtmp-server](https://github.com/w see also: [http://winlinvip.github.io/simple-rtmp-server](http://winlinvip.github.io/simple-rtmp-server) ### Contributors -winlin(winterserver): [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin) +winlin([winterserver](#)): [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin)
+wenjie([wenjiegit](https://github.com/wenjiegit/simple-rtmp-server)): [http://blog.chinaunix.net/uid/25006789.html](http://blog.chinaunix.net/uid/25006789.html)
+who is the contributors:
+1. contribute important features to srs.
+2. the name of all contributors will send in the response of NetConnection.connect and metadata. -### Usage -step 1: build srs
+### Usage(simple) +step -1: get srs
+
+git clone https://github.com/winlinvip/simple-rtmp-server &&
+cd simple-rtmp-server/trunk
+
+step 0: build srs system.
+
+bash scripts/build.sh
+
+step 1: start srs all demo features.
-tar xf simple-rtmp-server-*.*.tar.gz
-cd simple-rtmp-server-*.*/trunk
-./configure --with-ssl --with-hls --with-ffmpeg --with-http
-make
+bash scripts/run.sh
 
-or get the latest code:
+step 2: srs live show: [http://your-server-ip](http://your-server-ip)
+step 3: stop srs demo
-git clone  https://github.com/winlinvip/simple-rtmp-server
+bash scripts/stop.sh
+
+ +### Usage(detail) +step 0: get srs
+
+git clone https://github.com/winlinvip/simple-rtmp-server &&
 cd simple-rtmp-server/trunk
-./configure --with-ssl --with-hls --with-ffmpeg --with-http
+
+step 1: build srs
+
+./configure --with-ssl --with-hls --with-ffmpeg --with-http && make
 
step 2: start srs
@@ -41,11 +61,11 @@ sudo ./objs/nginx/sbin/nginx
 
 python ./research/api-server/server.py 8085
 
-step 6: publish live stream
+step 6: publish demo live stream
-FMS URL: rtmp://127.0.0.1/live
+FMS URL: rtmp://127.0.0.1/live?vhost=demo.srs.com
 Stream:  livestream
-For example, use ffmpeg to publish:
+FFMPEG to publish the default demo stream:
     for((;;)); do \
         ./objs/ffmpeg/bin/ffmpeg -re -i ./doc/source.200kbps.768x320.flv \
         -vcodec copy -acodec copy \
@@ -53,7 +73,19 @@ For example, use ffmpeg to publish:
         sleep 1; \
     done
 
-step 7: add server ip to client hosts as demo.
+step 7: publish players live stream
+
+FMS URL: rtmp://127.0.0.1/live?vhost=players
+Stream:  livestream
+FFMPEG to publish the players demo stream:
+    for((;;)); do \
+        ./objs/ffmpeg/bin/ffmpeg -re -i ./doc/source.200kbps.768x320.flv \
+        -vcodec copy -acodec copy \
+        -f flv -y rtmp://127.0.0.1/live?vhost=players/livestream; \
+        sleep 1; \
+    done
+
+step 8: add server ip to client hosts as demo.
 # edit the folowing file:
 # linux: /etc/hosts
@@ -61,35 +93,35 @@ For example, use ffmpeg to publish:
 # where server ip is 192.168.2.111
 192.168.2.111 demo.srs.com
 
-step 8: play live stream.
+step 9: play live stream.
-players: [http://demo.srs.com/players](http://demo.srs.com/players)
+players: http://demo.srs.com/players
 rtmp url: rtmp://demo.srs.com/live/livestream
 m3u8 url: http://demo.srs.com/live/livestream.m3u8
 for android: http://demo.srs.com/live/livestream.html
 
-step 9(optinal): play live stream auto transcoded
+step 10(optinal): play live stream auto transcoded
 rtmp url: rtmp://demo.srs.com/live/livestream_ld
 m3u8 url: http://demo.srs.com/live/livestream_ld.m3u8
-for android: [http://demo.srs.com/live/livestream_ld.html](http://demo.srs.com/live/livestream_ld.html)
+for android: http://demo.srs.com/live/livestream_ld.html
 rtmp url: rtmp://demo.srs.com/live/livestream_sd
 m3u8 url: http://demo.srs.com/live/livestream_sd.m3u8
-for android: [http://demo.srs.com/live/livestream_sd.html](http://demo.srs.com/live/livestream_sd.html)
+for android: http://demo.srs.com/live/livestream_sd.html
 
-step 10(optinal): play live stream auto forwarded, the hls dir change to /forward
+step 11(optinal): play live stream auto forwarded, the hls dir change to /forward
 rtmp url: rtmp://demo.srs.com:19350/live/livestream
 m3u8 url: http://demo.srs.com/forward/live/livestream.m3u8
-for android: [http://demo.srs.com/forward/live/livestream.html](http://demo.srs.com/forward/live/livestream.html)
+for android: http://demo.srs.com/forward/live/livestream.html
 rtmp url: rtmp://demo.srs.com:19350/live/livestream_ld
 m3u8 url: http://demo.srs.com/forward/live/livestream_ld.m3u8
-for android: [http://demo.srs.com/forward/live/livestream_ld.html](http://demo.srs.com/forward/live/livestream_ld.html)
+for android: http://demo.srs.com/forward/live/livestream_ld.html
 rtmp url: rtmp://demo.srs.com:19350/live/livestream_sd
 m3u8 url: http://demo.srs.com/forward/live/livestream_sd.m3u8
-for android: [http://demo.srs.com/forward/live/livestream_sd.html](http://demo.srs.com/forward/live/livestream_sd.html)
+for android: http://demo.srs.com/forward/live/livestream_sd.html
 
-step 11(optinal): modify the config and reload it (all features support reload)
+step 12(optinal): modify the config and reload it (all features support reload)
 killall -1 srs
 
@@ -125,8 +157,36 @@ Stream Architecture: | Flash, | +-> Fowarder ---------+-> RTMP Server | | XSPLIT, | +-> Transcoder -------+-> RTMP Server | | ...) | +-> DVR --------------+-> FILE | +| | +-> BandwidthTest-----+-> Flash/StLoad | +-----------+-------------------------+----------------+
+Bandwidth Test Workflow: +
+   +------------+                    +----------+
+   |  Client    |                    |  Server  |
+   +-----+------+                    +-----+----+
+         |                                 |
+         |   connect vhost------------->   |
+         |   <-----------result(success)   |
+         |                                 |
+         |   <----------call(start play)   |
+         |   result(playing)---------->    |
+         |   <-------------data(playing)   |
+         |   <-----------call(stop play)   |
+         |   result(stopped)---------->    |
+         |                                 |
+         |   <-------call(start publish)   |
+         |   result(publishing)------->    |
+         |   data(publishing)--------->    |
+         |   <--------call(stop publish)   |
+         |   result(stopped)(1)------->    |
+         |                                 |
+         |   <--------------------report   |
+         |   final(2)----------------->    |
+         |           <END>                 |
+         
+@see: class SrsBandwidth comments.
+
### System Requirements Supported operating systems and hardware: @@ -154,15 +214,17 @@ Supported operating systems and hardware: 18. support ffmpeg filters(logo/overlay/crop), x264 params.
19. support audio transcode only, speex/mp3 to aac
20. support http callback api hooks(for authentication and injection).
-21. [plan] support network based cli and json result.
-22. [plan] support bandwidth test api and flash client.
-23. [plan] support adobe flash refer/token/swf verification.
-24. [plan] support adobe amf3 codec.
-25. [plan] support dvr(record live to vod file)
-26. [plan] support FMS edge protocol
-27. [plan] support encryption: RTMPE/RTMPS, HLS DRM
-28. [plan] support RTMPT, http to tranverse firewalls
-29. [plan] support file source, transcoding file to live stream
+21. support bandwidth test api and flash client.
+22. player, publisher(encoder), and demo pages(jquery+bootstrap).
+23. demo video meeting or chat(srs+cherrypy+jquery+bootstrap).
+24. [plan] support network based cli and json result.
+25. [plan] support adobe flash refer/token/swf verification.
+26. [plan] support adobe amf3 codec.
+27. [plan] support dvr(record live to vod file)
+28. [plan] support FMS edge protocol
+29. [plan] support encryption: RTMPE/RTMPS, HLS DRM
+30. [plan] support RTMPT, http to tranverse firewalls
+31. [plan] support file source, transcoding file to live stream
### Performance 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB. @@ -213,6 +275,10 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw * nginx v1.5.0: 139524 lines
### History +* v0.9, 2013-12-22, demo video meeting or chat(srs+cherrypy+jquery+bootstrap). +* v0.9, 2013-12-22, merge from wenjie, support banwidth test. +* v0.9, 2013-12-22, merge from wenjie: support set chunk size at vhost level +* v0.9, 2013-12-21, add [players](http://demo.srs.com/players) for play and publish. * 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. diff --git a/trunk/3rdparty/bootstrap.2.3.2.zip b/trunk/3rdparty/bootstrap.2.3.2.zip new file mode 100644 index 000000000..47536ba28 Binary files /dev/null and b/trunk/3rdparty/bootstrap.2.3.2.zip differ diff --git a/trunk/3rdparty/jquery-1.10.2.zip b/trunk/3rdparty/jquery-1.10.2.zip new file mode 100644 index 000000000..fdf2378f3 Binary files /dev/null and b/trunk/3rdparty/jquery-1.10.2.zip differ diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index b122c6c44..18996067c 100755 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -28,10 +28,14 @@ vhost __defaultVhost__ { # for which cannot identify the required vhost. # for default demo. vhost demo.srs.com { + chunk_size 4096; enabled on; gop_cache on; queue_length 30; forward 127.0.0.1:19350; + bandcheck { + enabled off; + } hls { enabled on; hls_path ./objs/nginx/html; @@ -140,6 +144,14 @@ vhost players_pub { hls_window 30; } } +# rtmp only, no hls, for chat(low latecy) +vhost players_pub_rtmp { + gop_cache off; + hls { + enabled off; + } +} + # for development vhost dev { chunk_size 65000; @@ -201,16 +213,38 @@ vhost dev { } } +# vhost for bandwidth check +# generally, the bandcheck vhost must be: bandcheck.srs.com, +# or need to modify the vhost of client. vhost bandcheck.srs.com { - chunk_size 65000; - enabled on; - # vhost for band width check - bandcheck{ - enabled on; - key test kate; - interval 5; - limit_kbps 4000; - } + enabled on; + chunk_size 65000; + # bandwidth check config. + bandcheck { + # whether support bandwidth check, + # default: off. + enabled on; + # the key for server to valid, + # if invalid key, server disconnect and abort the bandwidth check. + key 35c9b402c12a7246868752e2878f7e0e; + # the interval in seconds for bandwidth check, + # server donot allow new test request. + # default: 30 + interval 30; + # the max available check bandwidth in kbps. + # to avoid attack of bandwidth check. + # default: 1000 + limit_kbps 4000; + } +} + +# set the chunk size of vhost. +vhost chunksize.vhost.com { + # the default chunk size is 128, max is 65536, + # some client does not support chunk size change, + # vhost chunk size will override the global value. + # default: global chunk size. + chunk_size 128; } # the http hook callback vhost, srs will invoke the hooks for specified events. @@ -304,6 +338,7 @@ vhost hooks.callback.vhost.com { on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions; } } + # the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction vhost mirror.transcode.vhost.com { transcode { @@ -683,6 +718,7 @@ vhost stream.transcode.vhost.com { } } } + # the vhost which forward publish streams. vhost same.vhost.forward.vhost.com { # forward all publish stream to the specified server. @@ -698,6 +734,7 @@ vhost same.vhost.forward.vhost.com { vhost change.vhost.forward.vhost.com { forward 127.0.0.1:1936?vhost=forward2.vhost.com 127.0.0.1:1937?vhost=forward3.vhost.com; } + # the vhost disabled. vhost removed.vhost.com { # whether the vhost is enabled. @@ -705,6 +742,7 @@ vhost removed.vhost.com { # default: on enabled off; } + # the vhost with hls specified. vhost with-hls.vhost.com { hls { @@ -741,6 +779,7 @@ vhost no-hls.vhost.com { enabled off; } } + # the vhost for min delay, donot cache any stream. vhost min.delay.com { # whether cache the last gop. @@ -758,6 +797,7 @@ vhost min.delay.com { # default: 30 queue_length 10; } + # the vhost for antisuck. vhost refer.anti_suck.com { # the common refer for play and publish. @@ -776,6 +816,7 @@ vhost refer.anti_suck.com { # default: not specified. refer_play github.com github.io; } + # config for the pithy print, # which always print constant message specified by interval, # whatever the clients in concurrency. diff --git a/trunk/configure b/trunk/configure index 698ee8f73..ba8b1b4fa 100755 --- a/trunk/configure +++ b/trunk/configure @@ -116,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_thread") + "srs_core_http" "srs_core_thread" "srs_core_bandwidth") MODULE_DIR="src/core" . auto/modules.sh CORE_OBJS="${MODULE_OBJS[@]}" diff --git a/trunk/research/api-server/server.py b/trunk/research/api-server/server.py index 617668c45..5e860145f 100755 --- a/trunk/research/api-server/server.py +++ b/trunk/research/api-server/server.py @@ -36,7 +36,7 @@ reload(sys) exec("sys.setdefaultencoding('utf-8')") assert sys.getdefaultencoding().lower() == "utf-8" -import json, datetime, cherrypy +import os, json, time, datetime, cherrypy, threading # simple log functions. def trace(msg): @@ -320,6 +320,123 @@ class RESTSessions(object): return code +global_chat_id = os.getpid(); +''' +the chat streams, public chat room. +''' +class RESTChats(object): + exposed = True + global_id = 100 + + def __init__(self): + # object fields: + # id: an int value indicates the id of user. + # username: a str indicates the user name. + # url: a str indicates the url of user stream. + # agent: a str indicates the agent of user. + # join_date: a number indicates the join timestamp in seconds. + # join_date_str: a str specifies the formated friendly time. + # heatbeat: a number indicates the heartbeat timestamp in seconds. + # vcodec: a dict indicates the video codec info. + # acodec: a dict indicates the audio codec info. + self.__chats = []; + self.__chat_lock = threading.Lock(); + + # dead time in seconds, if exceed, remove the chat. + self.__dead_time = 30; + + def GET(self): + enable_crossdomain() + + try: + self.__chat_lock.acquire(); + + chats = []; + copy = self.__chats[:]; + for chat in copy: + if time.time() - chat["heartbeat"] > self.__dead_time: + self.__chats.remove(chat); + continue; + + chats.append({ + "id": chat["id"], + "username": chat["username"], + "url": chat["url"], + "join_date_str": chat["join_date_str"], + "heartbeat": chat["heartbeat"], + }); + finally: + self.__chat_lock.release(); + + return json.dumps({"code":0, "data": {"now": time.time(), "chats": chats}}) + + def POST(self): + enable_crossdomain() + + req = cherrypy.request.body.read() + chat = json.loads(req) + + global global_chat_id; + chat["id"] = global_chat_id + global_chat_id += 1 + + chat["join_date"] = time.time(); + chat["heartbeat"] = time.time(); + chat["join_date_str"] = time.strftime("%Y-%m-%d %H:%M:%S"); + + try: + self.__chat_lock.acquire(); + + self.__chats.append(chat) + finally: + self.__chat_lock.release(); + + trace("create chat success, id=%s"%(chat["id"])) + + return json.dumps({"code":0, "data": chat["id"]}) + + def DELETE(self, id): + enable_crossdomain() + + try: + self.__chat_lock.acquire(); + + for chat in self.__chats: + if str(id) != str(chat["id"]): + continue + + self.__chats.remove(chat) + trace("delete chat success, id=%s"%(id)) + + return json.dumps({"code":0, "data": None}) + finally: + self.__chat_lock.release(); + + raise cherrypy.HTTPError(405, "Not allowed.") + + def PUT(self, id): + enable_crossdomain() + + try: + self.__chat_lock.acquire(); + + for chat in self.__chats: + if str(id) != str(chat["id"]): + continue + + chat["heartbeat"] = time.time(); + trace("heartbeat chat success, id=%s"%(id)) + + return json.dumps({"code":0, "data": None}) + finally: + self.__chat_lock.release(); + + raise cherrypy.HTTPError(405, "Not allowed.") + + + def OPTIONS(self, id=None): + enable_crossdomain() + # HTTP RESTful path. class Root(object): def __init__(self): @@ -335,6 +452,7 @@ class V1(object): self.clients = RESTClients() self.streams = RESTStreams() self.sessions = RESTSessions() + self.chats = RESTChats() ''' main code start. diff --git a/trunk/research/players/index.html b/trunk/research/players/index.html index 97148ee90..cbffc8852 100755 --- a/trunk/research/players/index.html +++ b/trunk/research/players/index.html @@ -31,6 +31,7 @@