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 @@