winlin

refine the demo pages, move scripts after body.

@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 <script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script> 6 <script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>
7 <script type="text/javascript" src="players/js/srs.page.js"></script> 7 <script type="text/javascript" src="players/js/srs.page.js"></script>
8 <script type="text/javascript" src="players/js/srs.utility.js"></script> 8 <script type="text/javascript" src="players/js/srs.utility.js"></script>
  9 + <script type="text/javascript" src="players/js/winlin.utility.js"></script>
9 </head> 10 </head>
10 <body> 11 <body>
11 <script type="text/javascript"> 12 <script type="text/javascript">
@@ -4,35 +4,11 @@ @@ -4,35 +4,11 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/srs.page.js"></script>  
11 - <script type="text/javascript" src="js/srs.utility.js"></script>  
12 <style> 7 <style>
13 body{ 8 body{
14 padding-top: 55px; 9 padding-top: 55px;
15 } 10 }
16 </style> 11 </style>
17 - <script type="text/javascript">  
18 - $(function(){  
19 - update_nav();  
20 -  
21 - var query = parse_query_string();  
22 - var url = "srs_chat.html?vhost=" + srs_get_player_vhost();  
23 -  
24 - for (var key in query.user_query) {  
25 - if (key == "vhost") {  
26 - continue;  
27 - }  
28 - url += "&" + key + "=" + query[key];  
29 - }  
30 -  
31 - setTimeout(function(){  
32 - window.location.href = url;  
33 - }, 100);  
34 - });  
35 - </script>  
36 </head> 12 </head>
37 <body> 13 <body>
38 <div class="navbar navbar-fixed-top"> 14 <div class="navbar navbar-fixed-top">
@@ -59,5 +35,30 @@ @@ -59,5 +35,30 @@
59 <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p> 35 <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p>
60 </footer> 36 </footer>
61 </div> 37 </div>
  38 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  39 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  40 +<script type="text/javascript" src="js/swfobject.js"></script>
  41 +<script type="text/javascript" src="js/srs.page.js"></script>
  42 +<script type="text/javascript" src="js/srs.utility.js"></script>
  43 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  44 +<script type="text/javascript">
  45 + $(function(){
  46 + update_nav();
  47 +
  48 + var query = parse_query_string();
  49 + var url = "srs_chat.html?vhost=" + srs_get_player_vhost();
  50 +
  51 + for (var key in query.user_query) {
  52 + if (key == "vhost") {
  53 + continue;
  54 + }
  55 + url += "&" + key + "=" + query[key];
  56 + }
  57 +
  58 + setTimeout(function(){
  59 + window.location.href = url;
  60 + }, 100);
  61 + });
  62 +</script>
62 </body> 63 </body>
63 64
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 ////////////////////////////////////////////////////////////////////////////////// 3 //////////////////////////////////////////////////////////////////////////////////
4 4
5 // to query the swf anti cache. 5 // to query the swf anti cache.
6 -function srs_get_version_code() { return "1.23"; } 6 +function srs_get_version_code() { return "1.25"; }
7 7
8 /** 8 /**
9 * player specified size. 9 * player specified size.
@@ -135,9 +135,15 @@ function build_default_hls_url() { @@ -135,9 +135,15 @@ function build_default_hls_url() {
135 * @param hls_url the div id contains the hls stream url to play 135 * @param hls_url the div id contains the hls stream url to play
136 * @param modal_player the div id contains the modal player 136 * @param modal_player the div id contains the modal player
137 */ 137 */
  138 +function srs_init_rtmp(rtmp_url, modal_player) {
  139 + srs_init(rtmp_url, null, modal_player);
  140 +}
  141 +function srs_init_hls(hls_url, modal_player) {
  142 + srs_init(null, hls_url, modal_player);
  143 +}
138 function srs_init(rtmp_url, hls_url, modal_player) { 144 function srs_init(rtmp_url, hls_url, modal_player) {
139 update_nav(); 145 update_nav();
140 - 146 +
141 if (rtmp_url) { 147 if (rtmp_url) {
142 $(rtmp_url).val(build_default_rtmp_url()); 148 $(rtmp_url).val(build_default_rtmp_url());
143 } 149 }
1 /** 1 /**
2 -* padding the output.  
3 -* padding(3, 5, '0') is 00003  
4 -* padding(3, 5, 'x') is xxxx3  
5 -* @see http://blog.csdn.net/win_lin/article/details/12065413  
6 -*/  
7 -function padding(number, length, prefix) {  
8 - if(String(number).length >= length){  
9 - return String(number);  
10 - }  
11 - return padding(prefix+number, length, prefix);  
12 -}  
13 -  
14 -/**  
15 -* parse the query string to object.  
16 -* parse the url location object as: host(hostname:http_port), pathname(dir/filename)  
17 -* for example, url http://192.168.1.168:1980/ui/players.html?vhost=player.vhost.com&app=test&stream=livestream  
18 -* parsed to object:  
19 -{  
20 - host : "192.168.1.168:1980",  
21 - hostname : "192.168.1.168",  
22 - http_port : 1980,  
23 - pathname : "/ui/players.html",  
24 - dir : "/ui",  
25 - filename : "/players.html",  
26 -  
27 - vhost : "player.vhost.com",  
28 - app : "test",  
29 - stream : "livestream"  
30 -}  
31 -*/  
32 -function parse_query_string(){  
33 - var obj = {};  
34 -  
35 - // add the uri object.  
36 - // parse the host(hostname:http_port), pathname(dir/filename)  
37 - obj.host = window.location.host;  
38 - obj.hostname = window.location.hostname;  
39 - obj.http_port = (window.location.port == "")? 80:window.location.port;  
40 - obj.pathname = window.location.pathname;  
41 - if (obj.pathname.lastIndexOf("/") <= 0) {  
42 - obj.dir = "/";  
43 - obj.filename = "";  
44 - } else {  
45 - obj.dir = obj.pathname.substr(0, obj.pathname.lastIndexOf("/"));  
46 - obj.filename = obj.pathname.substr(obj.pathname.lastIndexOf("/"));  
47 - }  
48 -  
49 - // pure user query object.  
50 - obj.user_query = {};  
51 -  
52 - // parse the query string.  
53 - var query_string = String(window.location.search).replace(" ", "").split("?")[1];  
54 - if(query_string == undefined){  
55 - return obj;  
56 - }  
57 -  
58 - var queries = query_string.split("&");  
59 - $(queries).each(function(){  
60 - var query = this.split("=");  
61 - obj[query[0]] = query[1];  
62 - obj.user_query[query[0]] = query[1];  
63 - });  
64 -  
65 - return obj;  
66 -}  
67 -  
68 -/**  
69 * parse the rtmp url, 2 * parse the rtmp url,
70 * for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream 3 * for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
71 * @return object {server, port, vhost, app, stream} 4 * @return object {server, port, vhost, app, stream}
72 */ 5 */
73 function srs_parse_rtmp_url(rtmp_url) { 6 function srs_parse_rtmp_url(rtmp_url) {
74 - // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri  
75 - var a = document.createElement("a");  
76 - a.href = rtmp_url.replace("rtmp://", "http://");  
77 -  
78 - var vhost = a.hostname;  
79 - var port = (a.port == "")? "1935":a.port;  
80 - var app = a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1);  
81 - var stream = a.pathname.substr(a.pathname.lastIndexOf("/") + 1);  
82 -  
83 - // parse the vhost in the params of app, that srs supports.  
84 - app = app.replace("...vhost...", "?vhost=");  
85 - if (app.indexOf("?") >= 0) {  
86 - var params = app.substr(app.indexOf("?"));  
87 - app = app.substr(0, app.indexOf("?"));  
88 -  
89 - if (params.indexOf("vhost=") > 0) {  
90 - vhost = params.substr(params.indexOf("vhost=") + "vhost=".length);  
91 - if (vhost.indexOf("&") > 0) {  
92 - vhost = vhost.substr(0, vhost.indexOf("&"));  
93 - }  
94 - }  
95 - }  
96 -  
97 - var ret = {  
98 - server: a.hostname, port: port,  
99 - vhost: vhost, app: app, stream: stream  
100 - };  
101 -  
102 - return ret;  
103 -}  
104 -  
105 -/**  
106 -* get the agent.  
107 -* @return an object specifies some browser.  
108 -* for example, get_browser_agents().MSIE  
109 -*/  
110 -function get_browser_agents() {  
111 - var agent = navigator.userAgent;  
112 -  
113 - /**  
114 - WindowsPC platform, Win7:  
115 - chrome 31.0.1650.63:  
116 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36  
117 - (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36  
118 - firefox 23.0.1:  
119 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101  
120 - Firefox/23.0  
121 - safari 5.1.7(7534.57.2):  
122 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2  
123 - (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2  
124 - opera 15.0.1147.153:  
125 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36  
126 - (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36  
127 - OPR/15.0.1147.153  
128 - 360 6.2.1.272:  
129 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;  
130 - Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;  
131 - .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;  
132 - .NET4.0E)  
133 - IE 10.0.9200.16750(update: 10.0.12):  
134 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;  
135 - Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;  
136 - .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;  
137 - .NET4.0E)  
138 - */  
139 -  
140 - return {  
141 - // platform  
142 - Android: agent.indexOf("Android") != -1,  
143 - Windows: agent.indexOf("Windows") != -1,  
144 - iPhone: agent.indexOf("iPhone") != -1,  
145 - // Windows Browsers  
146 - Chrome: agent.indexOf("Chrome") != -1,  
147 - Firefox: agent.indexOf("Firefox") != -1,  
148 - QQBrowser: agent.indexOf("QQBrowser") != -1,  
149 - MSIE: agent.indexOf("MSIE") != -1,  
150 - // Android Browsers  
151 - Opera: agent.indexOf("Presto") != -1,  
152 - MQQBrowser: agent.indexOf("MQQBrowser") != -1  
153 - }; 7 + return parse_rtmp_url(rtmp_url);
154 } 8 }
  1 +// winlin.utility.js
  2 +
  3 +/**
  4 + * common utilities
  5 + * depends: jquery1.10
  6 + * https://code.csdn.net/snippets/147103
  7 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  8 + * v 1.0.10
  9 + */
  10 +
  11 +/**
  12 + * padding the output.
  13 + * padding(3, 5, '0') is 00003
  14 + * padding(3, 5, 'x') is xxxx3
  15 + * @see http://blog.csdn.net/win_lin/article/details/12065413
  16 + */
  17 +function padding(number, length, prefix) {
  18 + if(String(number).length >= length){
  19 + return String(number);
  20 + }
  21 + return padding(prefix+number, length, prefix);
  22 +}
  23 +
  24 +/**
  25 + * extends system array, to remove all specified elem.
  26 + * @param arr the array to remove elem from.
  27 + * @param elem the elem to remove.
  28 + * @remark all elem will be removed.
  29 + * for example,
  30 + * arr = [10, 15, 20, 30, 20, 40]
  31 + * system_array_remove(arr, 10) // arr=[15, 20, 30, 20, 40]
  32 + * system_array_remove(arr, 20) // arr=[15, 30, 40]
  33 + */
  34 +function system_array_remove(arr, elem) {
  35 + if (!arr) {
  36 + return;
  37 + }
  38 +
  39 + var removed = true;
  40 + var i = 0;
  41 + while (removed) {
  42 + removed = false;
  43 + for (; i < arr.length; i++) {
  44 + if (elem == arr[i]) {
  45 + arr.splice(i, 1);
  46 + removed = true;
  47 + break;
  48 + }
  49 + }
  50 + }
  51 +}
  52 +
  53 +/**
  54 + * whether the array contains specified element.
  55 + * @param arr the array to find.
  56 + * @param elem_or_function the element value or compare function.
  57 + * @returns true contains elem; otherwise false.
  58 + * for example,
  59 + * arr = [10, 15, 20, 30, 20, 40]
  60 + * system_array_contains(arr, 10) // true
  61 + * system_array_contains(arr, 11) // false
  62 + * system_array_contains(arr, function(elem){return elem == 30;}); // true
  63 + * system_array_contains(arr, function(elem){return elem == 60;}); // false
  64 + */
  65 +function system_array_contains(arr, elem_or_function) {
  66 + return system_array_get(arr, elem_or_function) != null;
  67 +}
  68 +
  69 +/**
  70 + * get the specified element from array
  71 + * @param arr the array to find.
  72 + * @param elem_or_function the element value or compare function.
  73 + * @returns the matched elem; otherwise null.
  74 + * for example,
  75 + * arr = [10, 15, 20, 30, 20, 40]
  76 + * system_array_get(arr, 10) // 10
  77 + * system_array_get(arr, 11) // null
  78 + * system_array_get(arr, function(elem){return elem == 30;}); // 30
  79 + * system_array_get(arr, function(elem){return elem == 60;}); // null
  80 + */
  81 +function system_array_get(arr, elem_or_function) {
  82 + for (var i = 0; i < arr.length; i++) {
  83 + if (typeof elem_or_function == "function") {
  84 + if (elem_or_function(arr[i])) {
  85 + return arr[i];
  86 + }
  87 + } else {
  88 + if (elem_or_function == arr[i]) {
  89 + return arr[i];
  90 + }
  91 + }
  92 + }
  93 + return null;
  94 +}
  95 +
  96 +/**
  97 + * to iterate on array.
  98 + * @param arr the array to iterate on.
  99 + * @param pfn the function to apply on it
  100 + * for example,
  101 + * arr = [10, 15, 20, 30, 20, 40]
  102 + * system_array_foreach(arr, function(elem, index){
  103 + * console.log('index=' + index + ',elem=' + elem);
  104 + * });
  105 + */
  106 +function system_array_foreach(arr, pfn) {
  107 + for (var i = 0; i < arr.length; i++) {
  108 + if (pfn) {
  109 + pfn(arr[i], i)
  110 + }
  111 + }
  112 +}
  113 +
  114 +/**
  115 + * array sort asc, for example:
  116 + * [a, b] in [10, 11, 9]
  117 + * then sort to: [9, 10, 11]
  118 + * Usage, for example:
  119 + obj.data.data.sort(function(a, b){
  120 + return array_sort_asc(a.metadata.meta_id, b.metadata.meta_id);
  121 + });
  122 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  123 + * @remark, if need desc, use -1*array_sort_asc(a,b)
  124 + */
  125 +function array_sort_asc(elem_a, elem_b) {
  126 + if (elem_a > elem_b) {
  127 + return 1;
  128 + }
  129 + return (elem_a < elem_b)? -1 : 0;
  130 +}
  131 +function array_sort_desc(elem_a, elem_b) {
  132 + return -1 * array_sort_asc(elem_a, elem_b);
  133 +}
  134 +function system_array_sort_asc(elem_a, elem_b) {
  135 + return array_sort_asc(elem_a, elem_b);
  136 +}
  137 +function system_array_sort_desc(elem_a, elem_b) {
  138 + return -1 * array_sort_asc(elem_a, elem_b);
  139 +}
  140 +
  141 +/**
  142 + * parse the query string to object.
  143 + * parse the url location object as: host(hostname:http_port), pathname(dir/filename)
  144 + * for example, url http://192.168.1.168:1980/ui/players.html?vhost=player.vhost.com&app=test&stream=livestream
  145 + * parsed to object:
  146 + {
  147 + host : "192.168.1.168:1980",
  148 + hostname : "192.168.1.168",
  149 + http_port : 1980,
  150 + pathname : "/ui/players.html",
  151 + dir : "/ui",
  152 + filename : "/players.html",
  153 +
  154 + vhost : "player.vhost.com",
  155 + app : "test",
  156 + stream : "livestream"
  157 + }
  158 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  159 + */
  160 +function parse_query_string(){
  161 + var obj = {};
  162 +
  163 + // add the uri object.
  164 + // parse the host(hostname:http_port), pathname(dir/filename)
  165 + obj.host = window.location.host;
  166 + obj.hostname = window.location.hostname;
  167 + obj.http_port = (window.location.port == "")? 80:window.location.port;
  168 + obj.pathname = window.location.pathname;
  169 + if (obj.pathname.lastIndexOf("/") <= 0) {
  170 + obj.dir = "/";
  171 + obj.filename = "";
  172 + } else {
  173 + obj.dir = obj.pathname.substr(0, obj.pathname.lastIndexOf("/"));
  174 + obj.filename = obj.pathname.substr(obj.pathname.lastIndexOf("/"));
  175 + }
  176 +
  177 + // pure user query object.
  178 + obj.user_query = {};
  179 +
  180 + // parse the query string.
  181 + var query_string = String(window.location.search).replace(" ", "").split("?")[1];
  182 + if(query_string == undefined){
  183 + query_string = String(window.location.hash).replace(" ", "").split("#")[1];
  184 + if(query_string == undefined){
  185 + return obj;
  186 + }
  187 + }
  188 +
  189 + var queries = query_string.split("&");
  190 + $(queries).each(function(){
  191 + var query = this.split("=");
  192 + obj[query[0]] = query[1];
  193 + obj.user_query[query[0]] = query[1];
  194 + });
  195 +
  196 + return obj;
  197 +}
  198 +
  199 +/**
  200 + * parse the rtmp url,
  201 + * for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
  202 + * @return object {server, port, vhost, app, stream}
  203 + * for exmaple, rtmp_url is rtmp://demo.srs.com:1935/live...vhost...players/livestream
  204 + * parsed to object:
  205 + {
  206 + server: "demo.srs.com",
  207 + port: 1935,
  208 + vhost: "players",
  209 + app: "live",
  210 + stream: "livestream"
  211 + }
  212 + */
  213 +function parse_rtmp_url(rtmp_url) {
  214 + // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
  215 + var a = document.createElement("a");
  216 + a.href = rtmp_url.replace("rtmp://", "http://");
  217 +
  218 + var vhost = a.hostname;
  219 + var port = (a.port == "")? "1935":a.port;
  220 + var app = a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1);
  221 + var stream = a.pathname.substr(a.pathname.lastIndexOf("/") + 1);
  222 +
  223 + // parse the vhost in the params of app, that srs supports.
  224 + app = app.replace("...vhost...", "?vhost=");
  225 + if (app.indexOf("?") >= 0) {
  226 + var params = app.substr(app.indexOf("?"));
  227 + app = app.substr(0, app.indexOf("?"));
  228 +
  229 + if (params.indexOf("vhost=") > 0) {
  230 + vhost = params.substr(params.indexOf("vhost=") + "vhost=".length);
  231 + if (vhost.indexOf("&") > 0) {
  232 + vhost = vhost.substr(0, vhost.indexOf("&"));
  233 + }
  234 + }
  235 + }
  236 +
  237 + var ret = {
  238 + server: a.hostname, port: port,
  239 + vhost: vhost, app: app, stream: stream
  240 + };
  241 +
  242 + return ret;
  243 +}
  244 +
  245 +/**
  246 + * get the agent.
  247 + * @return an object specifies some browser.
  248 + * for example, get_browser_agents().MSIE
  249 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  250 + */
  251 +function get_browser_agents() {
  252 + var agent = navigator.userAgent;
  253 +
  254 + /**
  255 + WindowsPC platform, Win7:
  256 + chrome 31.0.1650.63:
  257 + Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
  258 + (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
  259 + firefox 23.0.1:
  260 + Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101
  261 + Firefox/23.0
  262 + safari 5.1.7(7534.57.2):
  263 + Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2
  264 + (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2
  265 + opera 15.0.1147.153:
  266 + Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
  267 + (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
  268 + OPR/15.0.1147.153
  269 + 360 6.2.1.272:
  270 + Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
  271 + Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
  272 + .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
  273 + .NET4.0E)
  274 + IE 10.0.9200.16750(update: 10.0.12):
  275 + Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
  276 + Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
  277 + .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
  278 + .NET4.0E)
  279 + */
  280 +
  281 + return {
  282 + // platform
  283 + Android: agent.indexOf("Android") != -1,
  284 + Windows: agent.indexOf("Windows") != -1,
  285 + iPhone: agent.indexOf("iPhone") != -1,
  286 + // Windows Browsers
  287 + Chrome: agent.indexOf("Chrome") != -1,
  288 + Firefox: agent.indexOf("Firefox") != -1,
  289 + QQBrowser: agent.indexOf("QQBrowser") != -1,
  290 + MSIE: agent.indexOf("MSIE") != -1,
  291 + // Android Browsers
  292 + Opera: agent.indexOf("Presto") != -1,
  293 + MQQBrowser: agent.indexOf("MQQBrowser") != -1
  294 + };
  295 +}
  296 +
  297 +/**
  298 + * format relative seconds to HH:MM:SS,
  299 + * for example, 210s formated to 00:03:30
  300 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  301 + * @usage relative_seconds_to_HHMMSS(210)
  302 + */
  303 +function relative_seconds_to_HHMMSS(seconds){
  304 + var date = new Date();
  305 + date.setTime(Number(seconds) * 1000);
  306 +
  307 + var ret = padding(date.getUTCHours(), 2, '0')
  308 + + ":" + padding(date.getUTCMinutes(), 2, '0')
  309 + + ":" + padding(date.getUTCSeconds(), 2, '0');
  310 +
  311 + return ret;
  312 +}
  313 +
  314 +/**
  315 + * format absolute seconds to HH:MM:SS,
  316 + * for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 10:01:20
  317 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  318 + * @usage absolute_seconds_to_HHMMSS(new Date().getTime() / 1000)
  319 + */
  320 +function absolute_seconds_to_HHMMSS(seconds){
  321 + var date = new Date();
  322 + date.setTime(Number(seconds) * 1000);
  323 +
  324 + var ret = padding(date.getHours(), 2, '0')
  325 + + ":" + padding(date.getMinutes(), 2, '0')
  326 + + ":" + padding(date.getSeconds(), 2, '0');
  327 +
  328 + return ret;
  329 +}
  330 +
  331 +/**
  332 + * format absolute seconds to YYYY-mm-dd,
  333 + * for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 2014-01-08
  334 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  335 + * @usage absolute_seconds_to_YYYYmmdd(new Date().getTime() / 1000)
  336 + */
  337 +function absolute_seconds_to_YYYYmmdd(seconds) {
  338 + var date = new Date();
  339 + date.setTime(Number(seconds) * 1000);
  340 +
  341 + var ret = date.getFullYear()
  342 + + "-" + padding(date.getMonth() + 1, 2, '0')
  343 + + "-" + padding(date.getDate(), 2, '0');
  344 +
  345 + return ret;
  346 +}
  347 +
  348 +/**
  349 + * parse the date in str to Date object.
  350 + * @param str the date in str, format as "YYYY-mm-dd", for example, 2014-12-11
  351 + * @returns a date object.
  352 + * @usage YYYYmmdd_parse("2014-12-11")
  353 + */
  354 +function YYYYmmdd_parse(str) {
  355 + var date = new Date();
  356 + date.setTime(Date.parse(str));
  357 + return date;
  358 +}
  359 +
  360 +/**
  361 + * async refresh function call. to avoid multiple call.
  362 + * @remark AsyncRefresh is for jquery to refresh the speicified pfn in a page;
  363 + * if angularjs, use AsyncRefresh2 to change pfn, cancel previous request for angularjs use singleton object.
  364 + * @param refresh_interval the default refresh interval ms.
  365 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  366 + * the pfn can be implements as following:
  367 + var async_refresh = new AsyncRefresh(pfn, 3000);
  368 + function pfn() {
  369 + if (!async_refresh.refresh_is_enabled()) {
  370 + async_refresh.request(100);
  371 + return;
  372 + }
  373 + $.ajax({
  374 + type: 'GET', async: true, url: 'xxxxx',
  375 + complete: function(){
  376 + if (!async_refresh.refresh_is_enabled()) {
  377 + async_refresh.request(0);
  378 + } else {
  379 + async_refresh.request(async_refresh.refresh_interval);
  380 + }
  381 + },
  382 + success: function(res){
  383 + // if donot allow refresh, directly return.
  384 + if (!async_refresh.refresh_is_enabled()) {
  385 + return;
  386 + }
  387 +
  388 + // render the res.
  389 + }
  390 + });
  391 + }
  392 + */
  393 +function AsyncRefresh(pfn, refresh_interval) {
  394 + this.refresh_interval = refresh_interval;
  395 +
  396 + this.__handler = null;
  397 + this.__pfn = pfn;
  398 +
  399 + this.__enabled = true;
  400 +}
  401 +/**
  402 + * disable the refresher, the pfn must check the refresh state.
  403 + */
  404 +AsyncRefresh.prototype.refresh_disable = function() {
  405 + this.__enabled = false;
  406 +}
  407 +AsyncRefresh.prototype.refresh_enable = function() {
  408 + this.__enabled = true;
  409 +}
  410 +AsyncRefresh.prototype.refresh_is_enabled = function() {
  411 + return this.__enabled;
  412 +}
  413 +/**
  414 + * start new async request
  415 + * @param timeout the timeout in ms.
  416 + * user can use the refresh_interval of the AsyncRefresh object,
  417 + * which initialized in constructor.
  418 + */
  419 +AsyncRefresh.prototype.request = function(timeout) {
  420 + if (this.__handler) {
  421 + clearTimeout(this.__handler);
  422 + }
  423 +
  424 + this.__handler = setTimeout(this.__pfn, timeout);
  425 +}
  426 +
  427 +/**
  428 + * async refresh v2, support cancellable refresh, and change the refresh pfn.
  429 + * @remakr for angularjs. if user only need jquery, maybe AsyncRefresh is better.
  430 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  431 + * Usage:
  432 + bsmControllers.controller('CServers', ['$scope', 'MServer', function($scope, MServer){
  433 + async_refresh2.refresh_change(function(){
  434 + // 获取服务器列表
  435 + MServer.servers_load({}, function(data){
  436 + $scope.servers = data.data.servers;
  437 + async_refresh2.request();
  438 + });
  439 + }, 3000);
  440 +
  441 + async_refresh2.request(0);
  442 + }]);
  443 + bsmControllers.controller('CStreams', ['$scope', 'MStream', function($scope, MStream){
  444 + async_refresh2.refresh_change(function(){
  445 + // 获取流列表
  446 + MStream.streams_load({}, function(data){
  447 + $scope.streams = data.data.streams;
  448 + async_refresh2.request();
  449 + });
  450 + }, 3000);
  451 +
  452 + async_refresh2.request(0);
  453 + }]);
  454 + */
  455 +function AsyncRefresh2() {
  456 + /**
  457 + * the function callback before call the pfn.
  458 + * the protype is function():bool, which return true to invoke, false to abort the call.
  459 + * null to ignore this callback.
  460 + *
  461 + * for example, user can abort the refresh by find the class popover:
  462 + * async_refresh2.on_before_call_pfn = function() {
  463 + * if ($(".popover").length > 0) {
  464 + * async_refresh2.request();
  465 + * return false;
  466 + * }
  467 + * return true;
  468 + * };
  469 + */
  470 + this.on_before_call_pfn = null;
  471 +
  472 + // use a anonymous function to call, and check the enabled when actually invoke.
  473 + this.__call = {
  474 + pfn: null,
  475 + timeout: 0,
  476 + __enabled: false,
  477 + __handler: null
  478 + };
  479 +}
  480 +// singleton
  481 +var async_refresh2 = new AsyncRefresh2();
  482 +/**
  483 + * initialize or refresh change. cancel previous request, setup new request.
  484 + * @param pfn a function():void to request after timeout. null to disable refresher.
  485 + * @param timeout the timeout in ms, to call pfn. null to disable refresher.
  486 + */
  487 +AsyncRefresh2.prototype.initialize = function(pfn, timeout) {
  488 + this.refresh_change(pfn, timeout);
  489 +}
  490 +/**
  491 + * stop refresh, the refresh pfn is set to null.
  492 + */
  493 +AsyncRefresh2.prototype.stop = function() {
  494 + this.refresh_change(null, null);
  495 +}
  496 +/**
  497 + * change refresh pfn, the old pfn will set to disabled.
  498 + */
  499 +AsyncRefresh2.prototype.refresh_change = function(pfn, timeout) {
  500 + // cancel the previous call.
  501 + if (this.__call.__handler) {
  502 + clearTimeout(this.__handler);
  503 + }
  504 + this.__call.__enabled = false;
  505 +
  506 + // setup new call.
  507 + this.__call = {
  508 + pfn: pfn,
  509 + timeout: timeout,
  510 + __enabled: true,
  511 + __handler: null
  512 + };
  513 +}
  514 +/**
  515 + * start new request, we never auto start the request,
  516 + * user must start new request when previous completed.
  517 + * @param timeout [optional] if not specified, use the timeout in initialize or refresh_change.
  518 + */
  519 +AsyncRefresh2.prototype.request = function(timeout) {
  520 + var self = this;
  521 + var this_call = this.__call;
  522 +
  523 + // clear previous timeout.
  524 + if (this_call.__handler) {
  525 + clearTimeout(this_call.__handler);
  526 + }
  527 +
  528 + // override the timeout
  529 + if (timeout == undefined) {
  530 + timeout = this_call.timeout;
  531 + }
  532 +
  533 + // if user disabled refresher.
  534 + if (this_call.pfn == null || timeout == null) {
  535 + return;
  536 + }
  537 +
  538 + this_call.__handler = setTimeout(function(){
  539 + // cancelled by refresh_change, ignore.
  540 + if (!this_call.__enabled) {
  541 + return;
  542 + }
  543 +
  544 + // callback if the handler installled.
  545 + if (self.on_before_call_pfn) {
  546 + if (!self.on_before_call_pfn()) {
  547 + return;
  548 + }
  549 + }
  550 +
  551 + // do the actual call.
  552 + this_call.pfn();
  553 + }, timeout);
  554 +}
  555 +
  556 +// other components.
  557 +/**
  558 + * jquery/bootstrap pager.
  559 + * depends: jquery1.10, boostrap2
  560 + * https://code.csdn.net/snippets/146160
  561 + * @see: http://blog.csdn.net/win_lin/article/details/17628631
  562 + */
@@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
11 <script type="text/javascript" src="js/srs.player.js"></script> 11 <script type="text/javascript" src="js/srs.player.js"></script>
12 <script type="text/javascript" src="js/srs.publisher.js"></script> 12 <script type="text/javascript" src="js/srs.publisher.js"></script>
13 <script type="text/javascript" src="js/srs.utility.js"></script> 13 <script type="text/javascript" src="js/srs.utility.js"></script>
  14 + <script type="text/javascript" src="js/winlin.utility.js"></script>
14 <style> 15 <style>
15 body{ 16 body{
16 padding-top: 55px; 17 padding-top: 55px;
@@ -5,9 +5,10 @@ @@ -5,9 +5,10 @@
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 </head> 6 </head>
7 <body> 7 <body>
8 - <script type="text/javascript">  
9 - setTimeout(function(){  
10 - window.location.href = "players/index.html" + window.location.search;  
11 - }, 500);  
12 - </script>  
13 -</body>  
  8 +</body>
  9 +<script type="text/javascript">
  10 + setTimeout(function(){
  11 + window.location.href = "players/index.html" + window.location.search;
  12 + }, 500);
  13 +</script>
  14 +</html>
@@ -4,14 +4,6 @@ @@ -4,14 +4,6 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/srs.page.js"></script>  
11 - <script type="text/javascript" src="js/srs.log.js"></script>  
12 - <script type="text/javascript" src="js/srs.player.js"></script>  
13 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
14 - <script type="text/javascript" src="js/srs.utility.js"></script>  
15 <style> 7 <style>
16 body{ 8 body{
17 padding-top: 55px; 9 padding-top: 55px;
@@ -21,58 +13,6 @@ @@ -21,58 +13,6 @@
21 margin-left: -350px; 13 margin-left: -350px;
22 } 14 }
23 </style> 15 </style>
24 - <script type="text/javascript">  
25 - function osmf_play(url) {  
26 - $("#div_container").remove();  
27 -  
28 - var div_container = $("<div/>");  
29 - $(div_container).attr("id", "div_container");  
30 - $("#player").append(div_container);  
31 -  
32 - var player = $("<div/>");  
33 - $(player).attr("id", "player_id");  
34 - $(div_container).append(player);  
35 -  
36 - var flashvars = {};  
37 - flashvars.src = url;  
38 - flashvars.streamType = "live"; // live or recorded  
39 - flashvars.autoPlay = true;  
40 - flashvars.controlBarAutoHide = false;  
41 - flashvars.scaleMode = "stretch";  
42 - flashvars.bufferTime = 0.8;  
43 -  
44 - var params = {};  
45 - params.allowFullScreen = true;  
46 -  
47 - var attributes = {};  
48 -  
49 - swfobject.embedSWF(  
50 - "js/StrobeMediaPlayback.swf", "player_id",  
51 - srs_get_player_width(), srs_get_player_height(),  
52 - "11.1", "js/AdobeFlashPlayerInstall.swf",  
53 - flashvars, params, attributes  
54 - );  
55 - }  
56 - $(function(){  
57 - // get the vhost and port to set the default url.  
58 - // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo  
59 - // url set to: rtmp://demo:1935/live/livestream  
60 - srs_init("#txt_url", null, "#main_modal");  
61 -  
62 - $("#main_modal").on("hide", function(){  
63 - osmf_play("http://localhost");  
64 - $("#div_container").remove();  
65 - });  
66 - $("#main_modal").on("show", function(){  
67 - var url = $("#txt_url").val();  
68 - osmf_play(url);  
69 - });  
70 -  
71 - $("#btn_play").click(function(){  
72 - $("#main_modal").modal({show:true, keyboard:false});  
73 - });  
74 - });  
75 - </script>  
76 </head> 16 </head>
77 <body> 17 <body>
78 <div class="navbar navbar-fixed-top"> 18 <div class="navbar navbar-fixed-top">
@@ -120,3 +60,65 @@ @@ -120,3 +60,65 @@
120 </footer> 60 </footer>
121 </div> 61 </div>
122 </body> 62 </body>
  63 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  64 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  65 +<script type="text/javascript" src="js/swfobject.js"></script>
  66 +<script type="text/javascript" src="js/srs.page.js"></script>
  67 +<script type="text/javascript" src="js/srs.log.js"></script>
  68 +<script type="text/javascript" src="js/srs.player.js"></script>
  69 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  70 +<script type="text/javascript" src="js/srs.utility.js"></script>
  71 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  72 +<script type="text/javascript">
  73 + function osmf_play(url) {
  74 + $("#div_container").remove();
  75 +
  76 + var div_container = $("<div/>");
  77 + $(div_container).attr("id", "div_container");
  78 + $("#player").append(div_container);
  79 +
  80 + var player = $("<div/>");
  81 + $(player).attr("id", "player_id");
  82 + $(div_container).append(player);
  83 +
  84 + var flashvars = {};
  85 + flashvars.src = url;
  86 + flashvars.streamType = "live"; // live or recorded
  87 + flashvars.autoPlay = true;
  88 + flashvars.controlBarAutoHide = false;
  89 + flashvars.scaleMode = "stretch";
  90 + flashvars.bufferTime = 0.8;
  91 +
  92 + var params = {};
  93 + params.allowFullScreen = true;
  94 +
  95 + var attributes = {};
  96 +
  97 + swfobject.embedSWF(
  98 + "js/StrobeMediaPlayback.swf", "player_id",
  99 + srs_get_player_width(), srs_get_player_height(),
  100 + "11.1", "js/AdobeFlashPlayerInstall.swf",
  101 + flashvars, params, attributes
  102 + );
  103 + }
  104 + $(function(){
  105 + // get the vhost and port to set the default url.
  106 + // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
  107 + // url set to: rtmp://demo:1935/live/livestream
  108 + srs_init_rtmp("#txt_url", "#main_modal");
  109 +
  110 + $("#main_modal").on("hide", function(){
  111 + osmf_play("http://localhost");
  112 + $("#div_container").remove();
  113 + });
  114 + $("#main_modal").on("show", function(){
  115 + var url = $("#txt_url").val();
  116 + osmf_play(url);
  117 + });
  118 +
  119 + $("#btn_play").click(function(){
  120 + $("#main_modal").modal({show:true, keyboard:false});
  121 + });
  122 + });
  123 +</script>
  124 +</html>
@@ -3,14 +3,16 @@ @@ -3,14 +3,16 @@
3 <head> 3 <head>
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 - <script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>  
7 - <script type="text/javascript" src="players/js/srs.page.js"></script>  
8 - <script type="text/javascript" src="players/js/srs.utility.js"></script>  
9 </head> 6 </head>
10 <body> 7 <body>
11 - <script type="text/javascript">  
12 - setTimeout(function(){  
13 - window.location.href = "players/index.html" + window.location.search;  
14 - }, 500);  
15 - </script>  
16 </body> 8 </body>
  9 +<script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>
  10 +<script type="text/javascript" src="players/js/srs.page.js"></script>
  11 +<script type="text/javascript" src="players/js/srs.utility.js"></script>
  12 +<script type="text/javascript" src="players/js/winlin.utility.js"></script>
  13 +<script type="text/javascript">
  14 + setTimeout(function(){
  15 + window.location.href = "players/index.html" + window.location.search;
  16 + }, 500);
  17 +</script>
  18 +</html>
@@ -4,15 +4,6 @@ @@ -4,15 +4,6 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/srs.page.js"></script>  
11 - <script type="text/javascript" src="js/srs.log.js"></script>  
12 - <script type="text/javascript" src="js/srs.player.js"></script>  
13 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
14 - <script type="text/javascript" src="js/srs.utility.js"></script>  
15 - <script type="text/javascript" src="srs_bwt/src/srs.bandwidth.js"></script>  
16 <style> 7 <style>
17 body{ 8 body{
18 padding-top: 55px; 9 padding-top: 55px;
@@ -22,62 +13,6 @@ @@ -22,62 +13,6 @@
22 margin-left: -350px; 13 margin-left: -350px;
23 } 14 }
24 </style> 15 </style>
25 - <script type="text/javascript">  
26 - var bandwidth = null;  
27 -  
28 - $(function(){  
29 - srs_init_bwt("#txt_url");  
30 -  
31 - $("#btn_play").click(on_click_play);  
32 - $("#main_modal").on("show", on_start_bandwidth_test);  
33 - $("#main_modal").on("hide", on_stop_bandwidth_test);  
34 - });  
35 -  
36 - function on_click_play() {  
37 - $("#check_status").text("");  
38 - $("#check_info").text("");  
39 - $("#progress_bar").width("0%");  
40 - $("#main_modal").modal({show:true, keyboard:false});  
41 - }  
42 - function on_start_bandwidth_test() {  
43 - $("#div_container").remove();  
44 - $("#progress_bar").removeClass("bar-danger");  
45 -  
46 - var div_container = $("<div/>");  
47 - $(div_container).attr("id", "div_container");  
48 - $("#player").append(div_container);  
49 -  
50 - var player = $("<div/>");  
51 - $(player).attr("id", "player_id");  
52 - $(div_container).append(player);  
53 -  
54 - var url = $("#txt_url").val();  
55 -  
56 - bandwidth = new SrsBandwidth("player_id", 100, 1);  
57 - bandwidth.on_bandwidth_ready = function() {  
58 - this.check_bandwidth(url);  
59 - }  
60 - bandwidth.on_update_progress = function(percent) {  
61 - $("#progress_bar").width(percent + "%");  
62 - }  
63 - bandwidth.on_update_status = function(status) {  
64 - $("#check_status").text(status);  
65 - }  
66 - bandwidth.on_srs_info = function(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip) {  
67 - $("#check_info").text(  
68 - "server:" + srs_server + ", primary:" + srs_primary + ", authors:" + srs_authors +  
69 - ", srs_id:" + srs_id + ", srs_pid:" + srs_pid + ", ip:" + srs_server_ip  
70 - );  
71 - }  
72 - bandwidth.on_error = function(code) {  
73 - $("#progress_bar").addClass("bar-danger");  
74 - }  
75 - bandwidth.render(url);  
76 - }  
77 - function on_stop_bandwidth_test() {  
78 - bandwidth.stop();  
79 - }  
80 - </script>  
81 </head> 16 </head>
82 <body> 17 <body>
83 <div class="navbar navbar-fixed-top"> 18 <div class="navbar navbar-fixed-top">
@@ -139,4 +74,70 @@ @@ -139,4 +74,70 @@
139 </div> 74 </div>
140 </div> 75 </div>
141 </body> 76 </body>
  77 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  78 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  79 +<script type="text/javascript" src="js/swfobject.js"></script>
  80 +<script type="text/javascript" src="js/srs.page.js"></script>
  81 +<script type="text/javascript" src="js/srs.log.js"></script>
  82 +<script type="text/javascript" src="js/srs.player.js"></script>
  83 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  84 +<script type="text/javascript" src="js/srs.utility.js"></script>
  85 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  86 +<script type="text/javascript" src="srs_bwt/src/srs.bandwidth.js"></script>
  87 +<script type="text/javascript">
  88 + var bandwidth = null;
  89 +
  90 + $(function(){
  91 + srs_init_bwt("#txt_url");
  92 +
  93 + $("#btn_play").click(on_click_play);
  94 + $("#main_modal").on("show", on_start_bandwidth_test);
  95 + $("#main_modal").on("hide", on_stop_bandwidth_test);
  96 + });
  97 +
  98 + function on_click_play() {
  99 + $("#check_status").text("");
  100 + $("#check_info").text("");
  101 + $("#progress_bar").width("0%");
  102 + $("#main_modal").modal({show:true, keyboard:false});
  103 + }
  104 + function on_start_bandwidth_test() {
  105 + $("#div_container").remove();
  106 + $("#progress_bar").removeClass("bar-danger");
142 107
  108 + var div_container = $("<div/>");
  109 + $(div_container).attr("id", "div_container");
  110 + $("#player").append(div_container);
  111 +
  112 + var player = $("<div/>");
  113 + $(player).attr("id", "player_id");
  114 + $(div_container).append(player);
  115 +
  116 + var url = $("#txt_url").val();
  117 +
  118 + bandwidth = new SrsBandwidth("player_id", 100, 1);
  119 + bandwidth.on_bandwidth_ready = function() {
  120 + this.check_bandwidth(url);
  121 + }
  122 + bandwidth.on_update_progress = function(percent) {
  123 + $("#progress_bar").width(percent + "%");
  124 + }
  125 + bandwidth.on_update_status = function(status) {
  126 + $("#check_status").text(status);
  127 + }
  128 + bandwidth.on_srs_info = function(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip) {
  129 + $("#check_info").text(
  130 + "server:" + srs_server + ", primary:" + srs_primary + ", authors:" + srs_authors +
  131 + ", srs_id:" + srs_id + ", srs_pid:" + srs_pid + ", ip:" + srs_server_ip
  132 + );
  133 + }
  134 + bandwidth.on_error = function(code) {
  135 + $("#progress_bar").addClass("bar-danger");
  136 + }
  137 + bandwidth.render(url);
  138 + }
  139 + function on_stop_bandwidth_test() {
  140 + bandwidth.stop();
  141 + }
  142 +</script>
  143 +</html>
@@ -4,15 +4,6 @@ @@ -4,15 +4,6 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/json2.js"></script>  
11 - <script type="text/javascript" src="js/srs.page.js"></script>  
12 - <script type="text/javascript" src="js/srs.log.js"></script>  
13 - <script type="text/javascript" src="js/srs.player.js"></script>  
14 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
15 - <script type="text/javascript" src="js/srs.utility.js"></script>  
16 <style> 7 <style>
17 body{ 8 body{
18 padding-top: 55px; 9 padding-top: 55px;
@@ -21,532 +12,6 @@ @@ -21,532 +12,6 @@
21 width: 310px; 12 width: 310px;
22 } 13 }
23 </style> 14 </style>
24 - <script type="text/javascript">  
25 - var srs_publisher = null;  
26 - var realtime_player = null;  
27 - var api_server = null;  
28 - var self_chat = null;  
29 - var global_chat_user_id = 200;  
30 - var previous_chats = [];  
31 - var no_play = false;  
32 -  
33 - var query = parse_query_string();  
34 - $(function(){  
35 - // get the vhost and port to set the default url.  
36 - // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo  
37 - // url set to: rtmp://demo:1935/live/livestream  
38 - srs_init_publish("#txt_url");  
39 -  
40 - // support 5x3+1 users  
41 - for (var i = 0; i < 5; i++) {  
42 - var tr = $("<tr></tr>").hide();  
43 - $("#lst_chats").append(tr);  
44 -  
45 - for (var j = 0; j < 3; j++) {  
46 - tr.append($("<td></td>").attr("id", "td_" + ((i+1) * 8 + j)));  
47 - }  
48 - }  
49 - // remove border of row.  
50 - $("#lst_chats").find("td").css("border", "none").css("padding", "2px")  
51 - .css("padding-left", "0px").css("width", "327px");  
52 -  
53 - if (query.agent == "true") {  
54 - document.write(navigator.userAgent);  
55 - return;  
56 - }  
57 -  
58 - $("#realtime_player_url").tooltip({  
59 - title: "右键复制RTMP地址"  
60 - });  
61 -  
62 - // if no play specified, donot show the player, for debug the publisher.  
63 - if (query.no_play == "true") {  
64 - no_play = true;  
65 - }  
66 -  
67 - $("#btn_video_settings").click(function(){  
68 - $("#video_modal").modal({show:true});  
69 - });  
70 - $("#btn_audio_settings").click(function(){  
71 - $("#audio_modal").modal({show:true});  
72 - });  
73 - $("#btn_join").click(on_user_publish);  
74 -  
75 - // for publish, we use randome stream name.  
76 - $("#txt_url").val($("#txt_url").val() + "." + new Date().getTime());  
77 -  
78 - // start the publisher.  
79 - srs_publisher = new SrsPublisher("local_publisher", 280, 180);  
80 - srs_publisher.on_publisher_ready = function(cameras, microphones) {  
81 - srs_chat_initialize_page(  
82 - cameras, microphones,  
83 - "#sl_cameras", "#sl_microphones",  
84 - "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",  
85 - "#sl_fps", "#sl_bitrate",  
86 - "#sl_acodec"  
87 - );  
88 - };  
89 - srs_publisher.on_publisher_error = function(code, desc) {  
90 - if (!on_publish_stop()) {  
91 - return;  
92 - }  
93 -  
94 - error(code, desc + "请重试。");  
95 - };  
96 - srs_publisher.on_publisher_warn = function(code, desc) {  
97 - warn(code, desc);  
98 - };  
99 - srs_publisher.start();  
100 -  
101 - update_play_url();  
102 -  
103 - if (!no_play) {  
104 - // start the realtime player.  
105 - realtime_player = new SrsPlayer("realtime_player", 280, 180);  
106 - realtime_player.on_player_ready = function() {  
107 - this.set_bt(0.5);  
108 - };  
109 - realtime_player.on_player_metadata = function(metadata) {  
110 - this.set_dar(0, 0);  
111 - this.set_fs("screen", 100);  
112 -  
113 - info("推流到服务器成功。请戴耳机聊天,否则音箱的声音会进入麦克风造成回声。");  
114 - }  
115 - realtime_player.start();  
116 - }  
117 -  
118 - $("#txt_name").focus();  
119 -  
120 - api_server = "http://" + query.hostname + ":" + srs_get_api_server_port() + "/api/v1/chats";  
121 - refresh();  
122 - });  
123 -  
124 - function on_publish_stop() {  
125 - if (!srs_can_republish()) {  
126 - $("#btn_join").attr("disabled", true);  
127 - error(0, "您使用的浏览器很弱,请关闭页面后重新打开页面(刷新也不管用)。<br/>推荐使用Chrome/Firefox/Safari/Opera浏览器,支持重试");  
128 -  
129 - srs_log_disabled = true;  
130 - return false;  
131 - }  
132 -  
133 - return true;  
134 - }  
135 -  
136 - function update_play_url() {  
137 - var url = $("#txt_url").val();  
138 -  
139 - $("#realtime_player_url").attr("href", url).attr("target", "_blank");  
140 - }  
141 -  
142 - function refresh() {  
143 - if (!self_chat) {  
144 - setTimeout(refresh, 1000);  
145 - return;  
146 - }  
147 -  
148 - $.ajax({  
149 - type : "GET",  
150 - async : true,  
151 - url : api_server,  
152 - contentType: "text/html",  
153 - data : "",  
154 - dataType : "json",  
155 - complete : function() {  
156 - },  
157 - error : function(ret) {  
158 - setTimeout(refresh, 5000);  
159 - warn(101, "查询会议室失败:" + JSON.stringify(ret));  
160 - },  
161 - success : function(ret) {  
162 - if(0 != ret["code"]) {  
163 - warn(102, "查询会议室失败: " + JSON.stringify(ret));  
164 - setTimeout(refresh, 5000);  
165 - return;  
166 - }  
167 -  
168 - var chats = ret["data"]["chats"];  
169 - var server_time = ret["now"];  
170 -  
171 - on_get_chats(chats);  
172 - setTimeout(refresh, 5000);  
173 - }  
174 - });  
175 - }  
176 - function on_get_chats(chats) {  
177 - if (!self_chat) {  
178 - return;  
179 - }  
180 -  
181 - // get self, check self is valid?  
182 - var _self_chat = null;  
183 - for (var i = 0; i < chats.length; i++) {  
184 - var chat = chats[i];  
185 - if (self_chat && self_chat.id == chat.id) {  
186 - _self_chat = chat;  
187 - break;  
188 - }  
189 - }  
190 - // rejoin if invalid.  
191 - if (!_self_chat) {  
192 - on_user_exit_chat(function(){  
193 - on_user_join_chat(function(){  
194 - info("重新加入会议室成功");  
195 - });  
196 - });  
197 - return;  
198 - }  
199 -  
200 - render_chat_room(chats);  
201 -  
202 - if (!self_chat) {  
203 - return;  
204 - }  
205 -  
206 - // update self heartbeat.  
207 - var url = api_server + "/" + self_chat.id;  
208 -  
209 - var chat = {};  
210 - chat.localtime = new Date().getTime();  
211 -  
212 - // publish to api server to requires an id.  
213 - $.ajax({  
214 - type : "PUT",  
215 - async : true,  
216 - url : url,  
217 - contentType: "text/html",  
218 - data : JSON.stringify(chat),  
219 - dataType : "json",  
220 - complete : function() {  
221 - },  
222 - error : function(ret) {  
223 - warn(105, "更新会议室信息失败:" + JSON.stringify(ret));  
224 - },  
225 - success : function(ret) {  
226 - if(0 != ret["code"]) {  
227 - warn(106, "更新会议室信息失败:: " + JSON.stringify(ret));  
228 - return;  
229 - }  
230 - }  
231 - });  
232 - }  
233 - function render_chat_room(original_chats) {  
234 - if (!self_chat) {  
235 - return;  
236 - }  
237 -  
238 - var chats = [];  
239 - for (var i = 0; i < original_chats.length; i++) {  
240 - var chat = original_chats[i];  
241 -  
242 - // ignore the self.  
243 - if (self_chat && self_chat.id == chat.id) {  
244 - continue;  
245 - }  
246 -  
247 - chats.push(chat);  
248 - }  
249 -  
250 - // new added chat  
251 - for (var i = 0; i < chats.length; i++) {  
252 - var chat = chats[i];  
253 -  
254 - // if previous exists, ignore, only add new here.  
255 - var previous_chat = get_previous_chat_user(previous_chats, chat.id);  
256 - if (previous_chat) {  
257 - // update reference.  
258 - chat.ui = previous_chat.ui;  
259 - chat.parent = previous_chat.parent;  
260 - chat.player = previous_chat.player;  
261 - if (chat.player) {  
262 - chat.player.private_object = chat;  
263 - }  
264 - continue;  
265 - }  
266 - }  
267 -  
268 - // removed chat  
269 - for (var i = 0; i < previous_chats.length; i++) {  
270 - var chat = previous_chats[i];  
271 -  
272 - var new_chat = get_previous_chat_user(chats, chat.id);  
273 - if (new_chat) {  
274 - continue;  
275 - }  
276 -  
277 - if (chat.player) {  
278 - chat.player.stop();  
279 - }  
280 - $("#div_" + chat.id).remove();  
281 - }  
282 -  
283 - // hide empty rows.  
284 - $("#lst_chats").find("tr").each(function(){  
285 - var empty = true;  
286 -  
287 - $(this).find("td").each(function(){  
288 - if ($(this).html() != "") {  
289 - empty = false;  
290 - return false; // abort each  
291 - }  
292 - return true;  
293 - });  
294 -  
295 - if (empty) {  
296 - $(this).hide();  
297 - }  
298 - });  
299 -  
300 - // render the chat  
301 - for (var i = 0; i < chats.length; i++) {  
302 - var chat = chats[i];  
303 -  
304 - // if redered, ignore.  
305 - if (chat.parent) {  
306 - continue;  
307 - }  
308 -  
309 - // generate the ui of chat  
310 - if (!chat.ui) {  
311 - global_chat_user_id++;  
312 -  
313 - // username: a str indicates the user name.  
314 - // url: a str indicates the url of user stream.  
315 - // join_date: a str indicates the join timestamp in seconds.  
316 - // join_date_str: friendly formated time.  
317 - var obj = $("<div/>").html($("#template").html());  
318 - if (true) {  
319 - // save current ui object to the chat.  
320 - chat.ui = obj;  
321 -  
322 - $(obj).attr("chat_id", chat.id);  
323 - $(obj).attr("id", "div_" + chat.id); // for specifed chat: $("#div_" + chat_id)  
324 - $(obj).attr("class", "div_chat"); // for all chats: $(".div_chat")  
325 - $(obj).find("#chat_player").attr("id", "rp_" + chat.id); // for specifed player: $("#rp_" + chat_id)  
326 - $(obj).find("#chat_player_raw").attr("id", "rp_raw_" + chat.id); // for specifed player: $("#rp_raw_" + chat_id)  
327 - $(obj).find("#user_name").text(chat.username);  
328 - $(obj).find("#user_player_url").attr("href", chat.url);  
329 - $(obj).find("#join_date").text(chat.join_date_str.split(" ")[1]);  
330 - $(obj).find("#collapseM").attr("id", "collapse_" + global_chat_user_id);  
331 - $(obj).find("#headerN").attr("href", "#collapse_" + global_chat_user_id);  
332 - }  
333 - }  
334 -  
335 - // find a idle td to render the chat.  
336 - var parent = null;  
337 - $("#lst_chats").find("td").each(function(){  
338 - if ($(this).html() != "") {  
339 - return true;  
340 - }  
341 -  
342 - parent = $(this);  
343 - return false; // abort each  
344 - });  
345 -  
346 - if (!parent) {  
347 - warn("没有可用的位置展示流。");  
348 - break;  
349 - }  
350 - $(parent).append(chat.ui);  
351 - $(parent).parent().show();  
352 -  
353 - // when ui elements appent to the page,  
354 - // create the player, or flash will failed.  
355 - if (!chat.parent) {  
356 - chat.parent = $(parent);  
357 -  
358 - if (!no_play) {  
359 - // start the realtime player.  
360 - var _player = new SrsPlayer("rp_raw_" + chat.id, 240, 180, chat);  
361 - _player.on_player_ready = function() {  
362 - this.set_bt(0.5);  
363 - this.play();  
364 - };  
365 - _player.on_player_metadata = function(metadata) {  
366 - this.set_dar(0, 0);  
367 - this.set_fs("screen", 100);  
368 - }  
369 - _player.start(chat.url);  
370 -  
371 - chat.player = _player;  
372 - } else {  
373 - chat.player = null;  
374 - }  
375 -  
376 - $(obj).find("#collapse_main").on('hidden', function(){  
377 - var id = $(this).parent().attr("chat_id");  
378 - var chat = get_previous_chat_user(previous_chats, id);  
379 - if (!chat || !chat.player) {  
380 - return;  
381 - }  
382 - chat.player.stop();  
383 - });  
384 - $(obj).find("#collapse_main").on('shown', function(){  
385 - var id = $(this).parent().attr("chat_id");  
386 - var chat = get_previous_chat_user(previous_chats, id);  
387 - if (!chat || !chat.player) {  
388 - return;  
389 - }  
390 - chat.player.play();  
391 - });  
392 - }  
393 - }  
394 -  
395 - previous_chats = chats;  
396 - }  
397 - function get_previous_chat_user(arr, id) {  
398 - for (var i = 0; i < arr.length; i++) {  
399 - var chat = arr[i];  
400 - if (id == chat.id) {  
401 - return chat;  
402 - }  
403 - }  
404 - return null;  
405 - }  
406 -  
407 - function on_user_publish() {  
408 - if ($("#txt_name").val() == "") {  
409 - $("#txt_name").focus().parent().parent().addClass("error");  
410 - warn(100, "请输入您的名字");  
411 - return;  
412 - }  
413 -  
414 - $("#txt_name").parent().parent().removeClass("error");  
415 -  
416 - // join chat.  
417 - if (!self_chat) {  
418 - on_user_join_chat();  
419 - } else {  
420 - on_user_exit_chat();  
421 - }  
422 - }  
423 - function on_user_exit_chat(complete_pfn) {  
424 - srs_publisher.stop();  
425 - $("#btn_join").text("加入会议");  
426 -  
427 - if (realtime_player) {  
428 - realtime_player.stop();  
429 - }  
430 -  
431 - if (!self_chat) {  
432 - return;  
433 - }  
434 -  
435 - // removed chat  
436 - for (var i = 0; i < previous_chats.length; i++) {  
437 - var chat = previous_chats[i];  
438 -  
439 - if (chat.player) {  
440 - chat.player.stop();  
441 - }  
442 - $("#div_" + chat.id).remove();  
443 - }  
444 - previous_chats = [];  
445 -  
446 - var url = api_server + "/" + self_chat.id;  
447 - // whatever, cleanup local chat.  
448 - self_chat = null;  
449 -  
450 - $("#btn_join").attr("disabled", true);  
451 -  
452 - // publish to api server to requires an id.  
453 - $.ajax({  
454 - type : "DELETE",  
455 - async : true,  
456 - url : url,  
457 - contentType: "text/html",  
458 - data : "",  
459 - dataType : "json",  
460 - complete : function() {  
461 - if (!on_publish_stop()) {  
462 - return;  
463 - }  
464 -  
465 - $("#btn_join").attr("disabled", false);  
466 - if (complete_pfn) {  
467 - complete_pfn();  
468 - }  
469 - },  
470 - error : function(ret) {  
471 - warn(103, "退出会议室失败");  
472 - },  
473 - success : function(ret) {  
474 - if(0 != ret["code"]) {  
475 - warn(104, "退出会议室失败");  
476 - return;  
477 - }  
478 - info("退出会议室成功");  
479 - }  
480 - });  
481 - }  
482 - function on_user_join_chat(complete_pfn) {  
483 - if (self_chat) {  
484 - return;  
485 - }  
486 -  
487 - var url = $("#txt_url").val();  
488 - var vcodec = {};  
489 - var acodec = {};  
490 - srs_publiser_get_codec(  
491 - vcodec, acodec,  
492 - "#sl_cameras", "#sl_microphones",  
493 - "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",  
494 - "#sl_fps", "#sl_bitrate",  
495 - "#sl_acodec"  
496 - );  
497 -  
498 - var chat = {};  
499 - chat.id = -1;  
500 - chat.username = $("#txt_name").val();  
501 - chat.agent = navigator.userAgent;  
502 - chat.url = url;  
503 - chat.vcodec = vcodec;  
504 - chat.acodec = acodec;  
505 -  
506 - $("#btn_join").attr("disabled", true);  
507 -  
508 - // publish to api server to requires an id.  
509 - $.ajax({  
510 - type : "POST",  
511 - async : true,  
512 - url : api_server,  
513 - contentType: "text/html",  
514 - data : JSON.stringify(chat),  
515 - dataType : "json",  
516 - complete : function() {  
517 - $("#btn_join").attr("disabled", false);  
518 - if (complete_pfn) {  
519 - complete_pfn();  
520 - }  
521 - },  
522 - error : function(ret) {  
523 - warn(105, "创建会议室失败:" + JSON.stringify(ret));  
524 - },  
525 - success : function(ret) {  
526 - if(0 != ret["code"]) {  
527 - warn(106, "创建会议室失败: " + JSON.stringify(ret));  
528 - return;  
529 - }  
530 -  
531 - chat.id = ret["data"];  
532 -  
533 - // success, start publish.  
534 - self_chat = chat;  
535 -  
536 - $("#btn_join").text("退出会议");  
537 -  
538 - info("开始推流到服务器。请戴耳机聊天,否则音箱的声音会进入麦克风造成回声。");  
539 - srs_publisher.publish(url, vcodec, acodec);  
540 -  
541 - if (realtime_player) {  
542 - // directly play the url for the realtime player.  
543 - realtime_player.stop();  
544 - realtime_player.play(url, 0);  
545 - }  
546 - }  
547 - });  
548 - }  
549 - </script>  
550 </head> 15 </head>
551 <body> 16 <body>
552 <div class="navbar navbar-fixed-top"> 17 <div class="navbar navbar-fixed-top">
@@ -785,4 +250,541 @@ @@ -785,4 +250,541 @@
785 </footer> 250 </footer>
786 </div> 251 </div>
787 </body> 252 </body>
  253 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  254 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  255 +<script type="text/javascript" src="js/swfobject.js"></script>
  256 +<script type="text/javascript" src="js/json2.js"></script>
  257 +<script type="text/javascript" src="js/srs.page.js"></script>
  258 +<script type="text/javascript" src="js/srs.log.js"></script>
  259 +<script type="text/javascript" src="js/srs.player.js"></script>
  260 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  261 +<script type="text/javascript" src="js/srs.utility.js"></script>
  262 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  263 +<script type="text/javascript">
  264 + var srs_publisher = null;
  265 + var realtime_player = null;
  266 + var api_server = null;
  267 + var self_chat = null;
  268 + var global_chat_user_id = 200;
  269 + var previous_chats = [];
  270 + var no_play = false;
  271 +
  272 + var query = parse_query_string();
  273 + $(function(){
  274 + // get the vhost and port to set the default url.
  275 + // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
  276 + // url set to: rtmp://demo:1935/live/livestream
  277 + srs_init_publish("#txt_url");
  278 +
  279 + // support 5x3+1 users
  280 + for (var i = 0; i < 5; i++) {
  281 + var tr = $("<tr></tr>").hide();
  282 + $("#lst_chats").append(tr);
  283 +
  284 + for (var j = 0; j < 3; j++) {
  285 + tr.append($("<td></td>").attr("id", "td_" + ((i+1) * 8 + j)));
  286 + }
  287 + }
  288 + // remove border of row.
  289 + $("#lst_chats").find("td").css("border", "none").css("padding", "2px")
  290 + .css("padding-left", "0px").css("width", "327px");
  291 +
  292 + if (query.agent == "true") {
  293 + document.write(navigator.userAgent);
  294 + return;
  295 + }
  296 +
  297 + $("#realtime_player_url").tooltip({
  298 + title: "右键复制RTMP地址"
  299 + });
  300 +
  301 + // if no play specified, donot show the player, for debug the publisher.
  302 + if (query.no_play == "true") {
  303 + no_play = true;
  304 + }
  305 +
  306 + $("#btn_video_settings").click(function(){
  307 + $("#video_modal").modal({show:true});
  308 + });
  309 + $("#btn_audio_settings").click(function(){
  310 + $("#audio_modal").modal({show:true});
  311 + });
  312 + $("#btn_join").click(on_user_publish);
  313 +
  314 + // for publish, we use randome stream name.
  315 + $("#txt_url").val($("#txt_url").val() + "." + new Date().getTime());
  316 +
  317 + // start the publisher.
  318 + srs_publisher = new SrsPublisher("local_publisher", 280, 180);
  319 + srs_publisher.on_publisher_ready = function(cameras, microphones) {
  320 + srs_chat_initialize_page(
  321 + cameras, microphones,
  322 + "#sl_cameras", "#sl_microphones",
  323 + "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",
  324 + "#sl_fps", "#sl_bitrate",
  325 + "#sl_acodec"
  326 + );
  327 + };
  328 + srs_publisher.on_publisher_error = function(code, desc) {
  329 + if (!on_publish_stop()) {
  330 + return;
  331 + }
  332 +
  333 + error(code, desc + "请重试。");
  334 + };
  335 + srs_publisher.on_publisher_warn = function(code, desc) {
  336 + warn(code, desc);
  337 + };
  338 + srs_publisher.start();
  339 +
  340 + update_play_url();
  341 +
  342 + if (!no_play) {
  343 + // start the realtime player.
  344 + realtime_player = new SrsPlayer("realtime_player", 280, 180);
  345 + realtime_player.on_player_ready = function() {
  346 + this.set_bt(0.5);
  347 + };
  348 + realtime_player.on_player_metadata = function(metadata) {
  349 + this.set_dar(0, 0);
  350 + this.set_fs("screen", 100);
  351 +
  352 + info("推流到服务器成功。请戴耳机聊天,否则音箱的声音会进入麦克风造成回声。");
  353 + }
  354 + realtime_player.start();
  355 + }
  356 +
  357 + $("#txt_name").focus();
  358 +
  359 + api_server = "http://" + query.hostname + ":" + srs_get_api_server_port() + "/api/v1/chats";
  360 + refresh();
  361 + });
  362 +
  363 + function on_publish_stop() {
  364 + if (!srs_can_republish()) {
  365 + $("#btn_join").attr("disabled", true);
  366 + error(0, "您使用的浏览器很弱,请关闭页面后重新打开页面(刷新也不管用)。<br/>推荐使用Chrome/Firefox/Safari/Opera浏览器,支持重试");
  367 +
  368 + srs_log_disabled = true;
  369 + return false;
  370 + }
  371 +
  372 + return true;
  373 + }
  374 +
  375 + function update_play_url() {
  376 + var url = $("#txt_url").val();
  377 +
  378 + $("#realtime_player_url").attr("href", url).attr("target", "_blank");
  379 + }
  380 +
  381 + function refresh() {
  382 + if (!self_chat) {
  383 + setTimeout(refresh, 1000);
  384 + return;
  385 + }
  386 +
  387 + $.ajax({
  388 + type : "GET",
  389 + async : true,
  390 + url : api_server,
  391 + contentType: "text/html",
  392 + data : "",
  393 + dataType : "json",
  394 + complete : function() {
  395 + },
  396 + error : function(ret) {
  397 + setTimeout(refresh, 5000);
  398 + warn(101, "查询会议室失败:" + JSON.stringify(ret));
  399 + },
  400 + success : function(ret) {
  401 + if(0 != ret["code"]) {
  402 + warn(102, "查询会议室失败: " + JSON.stringify(ret));
  403 + setTimeout(refresh, 5000);
  404 + return;
  405 + }
  406 +
  407 + var chats = ret["data"]["chats"];
  408 + var server_time = ret["now"];
  409 +
  410 + on_get_chats(chats);
  411 + setTimeout(refresh, 5000);
  412 + }
  413 + });
  414 + }
  415 + function on_get_chats(chats) {
  416 + if (!self_chat) {
  417 + return;
  418 + }
  419 +
  420 + // get self, check self is valid?
  421 + var _self_chat = null;
  422 + for (var i = 0; i < chats.length; i++) {
  423 + var chat = chats[i];
  424 + if (self_chat && self_chat.id == chat.id) {
  425 + _self_chat = chat;
  426 + break;
  427 + }
  428 + }
  429 + // rejoin if invalid.
  430 + if (!_self_chat) {
  431 + on_user_exit_chat(function(){
  432 + on_user_join_chat(function(){
  433 + info("重新加入会议室成功");
  434 + });
  435 + });
  436 + return;
  437 + }
  438 +
  439 + render_chat_room(chats);
  440 +
  441 + if (!self_chat) {
  442 + return;
  443 + }
  444 +
  445 + // update self heartbeat.
  446 + var url = api_server + "/" + self_chat.id;
  447 +
  448 + var chat = {};
  449 + chat.localtime = new Date().getTime();
  450 +
  451 + // publish to api server to requires an id.
  452 + $.ajax({
  453 + type : "PUT",
  454 + async : true,
  455 + url : url,
  456 + contentType: "text/html",
  457 + data : JSON.stringify(chat),
  458 + dataType : "json",
  459 + complete : function() {
  460 + },
  461 + error : function(ret) {
  462 + warn(105, "更新会议室信息失败:" + JSON.stringify(ret));
  463 + },
  464 + success : function(ret) {
  465 + if(0 != ret["code"]) {
  466 + warn(106, "更新会议室信息失败:: " + JSON.stringify(ret));
  467 + return;
  468 + }
  469 + }
  470 + });
  471 + }
  472 + function render_chat_room(original_chats) {
  473 + if (!self_chat) {
  474 + return;
  475 + }
  476 +
  477 + var chats = [];
  478 + for (var i = 0; i < original_chats.length; i++) {
  479 + var chat = original_chats[i];
  480 +
  481 + // ignore the self.
  482 + if (self_chat && self_chat.id == chat.id) {
  483 + continue;
  484 + }
  485 +
  486 + chats.push(chat);
  487 + }
  488 +
  489 + // new added chat
  490 + for (var i = 0; i < chats.length; i++) {
  491 + var chat = chats[i];
  492 +
  493 + // if previous exists, ignore, only add new here.
  494 + var previous_chat = get_previous_chat_user(previous_chats, chat.id);
  495 + if (previous_chat) {
  496 + // update reference.
  497 + chat.ui = previous_chat.ui;
  498 + chat.parent = previous_chat.parent;
  499 + chat.player = previous_chat.player;
  500 + if (chat.player) {
  501 + chat.player.private_object = chat;
  502 + }
  503 + continue;
  504 + }
  505 + }
  506 +
  507 + // removed chat
  508 + for (var i = 0; i < previous_chats.length; i++) {
  509 + var chat = previous_chats[i];
  510 +
  511 + var new_chat = get_previous_chat_user(chats, chat.id);
  512 + if (new_chat) {
  513 + continue;
  514 + }
  515 +
  516 + if (chat.player) {
  517 + chat.player.stop();
  518 + }
  519 + $("#div_" + chat.id).remove();
  520 + }
  521 +
  522 + // hide empty rows.
  523 + $("#lst_chats").find("tr").each(function(){
  524 + var empty = true;
  525 +
  526 + $(this).find("td").each(function(){
  527 + if ($(this).html() != "") {
  528 + empty = false;
  529 + return false; // abort each
  530 + }
  531 + return true;
  532 + });
  533 +
  534 + if (empty) {
  535 + $(this).hide();
  536 + }
  537 + });
  538 +
  539 + // render the chat
  540 + for (var i = 0; i < chats.length; i++) {
  541 + var chat = chats[i];
  542 +
  543 + // if redered, ignore.
  544 + if (chat.parent) {
  545 + continue;
  546 + }
  547 +
  548 + // generate the ui of chat
  549 + if (!chat.ui) {
  550 + global_chat_user_id++;
  551 +
  552 + // username: a str indicates the user name.
  553 + // url: a str indicates the url of user stream.
  554 + // join_date: a str indicates the join timestamp in seconds.
  555 + // join_date_str: friendly formated time.
  556 + var obj = $("<div/>").html($("#template").html());
  557 + if (true) {
  558 + // save current ui object to the chat.
  559 + chat.ui = obj;
  560 +
  561 + $(obj).attr("chat_id", chat.id);
  562 + $(obj).attr("id", "div_" + chat.id); // for specifed chat: $("#div_" + chat_id)
  563 + $(obj).attr("class", "div_chat"); // for all chats: $(".div_chat")
  564 + $(obj).find("#chat_player").attr("id", "rp_" + chat.id); // for specifed player: $("#rp_" + chat_id)
  565 + $(obj).find("#chat_player_raw").attr("id", "rp_raw_" + chat.id); // for specifed player: $("#rp_raw_" + chat_id)
  566 + $(obj).find("#user_name").text(chat.username);
  567 + $(obj).find("#user_player_url").attr("href", chat.url);
  568 + $(obj).find("#join_date").text(chat.join_date_str.split(" ")[1]);
  569 + $(obj).find("#collapseM").attr("id", "collapse_" + global_chat_user_id);
  570 + $(obj).find("#headerN").attr("href", "#collapse_" + global_chat_user_id);
  571 + }
  572 + }
  573 +
  574 + // find a idle td to render the chat.
  575 + var parent = null;
  576 + $("#lst_chats").find("td").each(function(){
  577 + if ($(this).html() != "") {
  578 + return true;
  579 + }
  580 +
  581 + parent = $(this);
  582 + return false; // abort each
  583 + });
  584 +
  585 + if (!parent) {
  586 + warn("没有可用的位置展示流。");
  587 + break;
  588 + }
  589 + $(parent).append(chat.ui);
  590 + $(parent).parent().show();
  591 +
  592 + // when ui elements appent to the page,
  593 + // create the player, or flash will failed.
  594 + if (!chat.parent) {
  595 + chat.parent = $(parent);
  596 +
  597 + if (!no_play) {
  598 + // start the realtime player.
  599 + var _player = new SrsPlayer("rp_raw_" + chat.id, 240, 180, chat);
  600 + _player.on_player_ready = function() {
  601 + this.set_bt(0.5);
  602 + this.play();
  603 + };
  604 + _player.on_player_metadata = function(metadata) {
  605 + this.set_dar(0, 0);
  606 + this.set_fs("screen", 100);
  607 + }
  608 + _player.start(chat.url);
  609 +
  610 + chat.player = _player;
  611 + } else {
  612 + chat.player = null;
  613 + }
  614 +
  615 + $(obj).find("#collapse_main").on('hidden', function(){
  616 + var id = $(this).parent().attr("chat_id");
  617 + var chat = get_previous_chat_user(previous_chats, id);
  618 + if (!chat || !chat.player) {
  619 + return;
  620 + }
  621 + chat.player.stop();
  622 + });
  623 + $(obj).find("#collapse_main").on('shown', function(){
  624 + var id = $(this).parent().attr("chat_id");
  625 + var chat = get_previous_chat_user(previous_chats, id);
  626 + if (!chat || !chat.player) {
  627 + return;
  628 + }
  629 + chat.player.play();
  630 + });
  631 + }
  632 + }
  633 +
  634 + previous_chats = chats;
  635 + }
  636 + function get_previous_chat_user(arr, id) {
  637 + for (var i = 0; i < arr.length; i++) {
  638 + var chat = arr[i];
  639 + if (id == chat.id) {
  640 + return chat;
  641 + }
  642 + }
  643 + return null;
  644 + }
  645 +
  646 + function on_user_publish() {
  647 + if ($("#txt_name").val() == "") {
  648 + $("#txt_name").focus().parent().parent().addClass("error");
  649 + warn(100, "请输入您的名字");
  650 + return;
  651 + }
  652 +
  653 + $("#txt_name").parent().parent().removeClass("error");
  654 +
  655 + // join chat.
  656 + if (!self_chat) {
  657 + on_user_join_chat();
  658 + } else {
  659 + on_user_exit_chat();
  660 + }
  661 + }
  662 + function on_user_exit_chat(complete_pfn) {
  663 + srs_publisher.stop();
  664 + $("#btn_join").text("加入会议");
  665 +
  666 + if (realtime_player) {
  667 + realtime_player.stop();
  668 + }
  669 +
  670 + if (!self_chat) {
  671 + return;
  672 + }
  673 +
  674 + // removed chat
  675 + for (var i = 0; i < previous_chats.length; i++) {
  676 + var chat = previous_chats[i];
  677 +
  678 + if (chat.player) {
  679 + chat.player.stop();
  680 + }
  681 + $("#div_" + chat.id).remove();
  682 + }
  683 + previous_chats = [];
  684 +
  685 + var url = api_server + "/" + self_chat.id;
  686 + // whatever, cleanup local chat.
  687 + self_chat = null;
  688 +
  689 + $("#btn_join").attr("disabled", true);
  690 +
  691 + // publish to api server to requires an id.
  692 + $.ajax({
  693 + type : "DELETE",
  694 + async : true,
  695 + url : url,
  696 + contentType: "text/html",
  697 + data : "",
  698 + dataType : "json",
  699 + complete : function() {
  700 + if (!on_publish_stop()) {
  701 + return;
  702 + }
  703 +
  704 + $("#btn_join").attr("disabled", false);
  705 + if (complete_pfn) {
  706 + complete_pfn();
  707 + }
  708 + },
  709 + error : function(ret) {
  710 + warn(103, "退出会议室失败");
  711 + },
  712 + success : function(ret) {
  713 + if(0 != ret["code"]) {
  714 + warn(104, "退出会议室失败");
  715 + return;
  716 + }
  717 + info("退出会议室成功");
  718 + }
  719 + });
  720 + }
  721 + function on_user_join_chat(complete_pfn) {
  722 + if (self_chat) {
  723 + return;
  724 + }
  725 +
  726 + var url = $("#txt_url").val();
  727 + var vcodec = {};
  728 + var acodec = {};
  729 + srs_publiser_get_codec(
  730 + vcodec, acodec,
  731 + "#sl_cameras", "#sl_microphones",
  732 + "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",
  733 + "#sl_fps", "#sl_bitrate",
  734 + "#sl_acodec"
  735 + );
  736 +
  737 + var chat = {};
  738 + chat.id = -1;
  739 + chat.username = $("#txt_name").val();
  740 + chat.agent = navigator.userAgent;
  741 + chat.url = url;
  742 + chat.vcodec = vcodec;
  743 + chat.acodec = acodec;
  744 +
  745 + $("#btn_join").attr("disabled", true);
  746 +
  747 + // publish to api server to requires an id.
  748 + $.ajax({
  749 + type : "POST",
  750 + async : true,
  751 + url : api_server,
  752 + contentType: "text/html",
  753 + data : JSON.stringify(chat),
  754 + dataType : "json",
  755 + complete : function() {
  756 + $("#btn_join").attr("disabled", false);
  757 + if (complete_pfn) {
  758 + complete_pfn();
  759 + }
  760 + },
  761 + error : function(ret) {
  762 + warn(105, "创建会议室失败:" + JSON.stringify(ret));
  763 + },
  764 + success : function(ret) {
  765 + if(0 != ret["code"]) {
  766 + warn(106, "创建会议室失败: " + JSON.stringify(ret));
  767 + return;
  768 + }
  769 +
  770 + chat.id = ret["data"];
  771 +
  772 + // success, start publish.
  773 + self_chat = chat;
  774 +
  775 + $("#btn_join").text("退出会议");
  776 +
  777 + info("开始推流到服务器。请戴耳机聊天,否则音箱的声音会进入麦克风造成回声。");
  778 + srs_publisher.publish(url, vcodec, acodec);
  779 +
  780 + if (realtime_player) {
  781 + // directly play the url for the realtime player.
  782 + realtime_player.stop();
  783 + realtime_player.play(url, 0);
  784 + }
  785 + }
  786 + });
  787 + }
  788 +</script>
  789 +</html>
788 790
@@ -4,15 +4,6 @@ @@ -4,15 +4,6 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/json2.js"></script>  
11 - <script type="text/javascript" src="js/srs.page.js"></script>  
12 - <script type="text/javascript" src="js/srs.log.js"></script>  
13 - <script type="text/javascript" src="js/srs.player.js"></script>  
14 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
15 - <script type="text/javascript" src="js/srs.utility.js"></script>  
16 <style> 7 <style>
17 body{ 8 body{
18 padding-top: 55px; 9 padding-top: 55px;
@@ -29,250 +20,6 @@ @@ -29,250 +20,6 @@
29 margin-bottom: 10px; 20 margin-bottom: 10px;
30 } 21 }
31 </style> 22 </style>
32 - <script type="text/javascript">  
33 - var srs_player = null;  
34 - var url = null;  
35 -  
36 - var __active_dar = null;  
37 - function select_dar(dar_id, num, den) {  
38 - srs_player.set_dar(num, den);  
39 -  
40 - if (__active_dar) {  
41 - __active_dar.removeClass("active");  
42 - }  
43 -  
44 - __active_dar = $(dar_id).parent();  
45 - __active_dar.addClass("active");  
46 - }  
47 -  
48 - var __active_size = null;  
49 - function select_fs_size(size_id, refer, percent) {  
50 - srs_player.set_fs(refer, percent);  
51 -  
52 - if (__active_size) {  
53 - __active_size.removeClass("active");  
54 - }  
55 -  
56 - __active_size = $(size_id).parent();  
57 - __active_size.addClass("active");  
58 - }  
59 -  
60 - var __active_bt = null;  
61 - function select_buffer_time(bt_id, buffer_time) {  
62 - srs_player.set_bt(buffer_time);  
63 -  
64 - if (__active_bt) {  
65 - __active_bt.removeClass("active");  
66 - }  
67 -  
68 - __active_bt = $(bt_id).parent();  
69 - __active_bt.addClass("active");  
70 - }  
71 -  
72 - $(function(){  
73 - // get the vhost and port to set the default url.  
74 - // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo  
75 - // url set to: rtmp://demo:1935/live/livestream  
76 - srs_init("#txt_url", null, "#main_modal");  
77 -  
78 - $("#fs_tips").tooltip({  
79 - title: "点击视频进入或退出全屏"  
80 - });  
81 -  
82 - $("#main_modal").on("show", function(){  
83 - if (srs_player) {  
84 - return;  
85 - }  
86 -  
87 - $("#div_container").remove();  
88 -  
89 - var div_container = $("<div/>");  
90 - $(div_container).attr("id", "div_container");  
91 - $("#player").append(div_container);  
92 -  
93 - var player = $("<div/>");  
94 - $(player).attr("id", "player_id");  
95 - $(div_container).append(player);  
96 -  
97 - srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height());  
98 - srs_player.on_player_ready = function() {  
99 - select_buffer_time("#btn_bt_0_1", 0.1);  
100 - this.play(url);  
101 - };  
102 - srs_player.on_player_metadata = function(metadata) {  
103 - $("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")");  
104 - select_dar("#btn_dar_original", 0, 0);  
105 - select_fs_size("#btn_fs_size_screen_100", "screen", 100);  
106 - };  
107 - srs_player.on_player_timer = function(time, buffer_length) {  
108 - var buffer = buffer_length / this.buffer_time * 100;  
109 - $("#pb_buffer").width(Number(buffer).toFixed(1) + "%");  
110 -  
111 - $("#pb_buffer_bg").attr("title",  
112 - "缓冲区长度:" + Number(buffer_length).toFixed(1) + "秒("  
113 - + Number(buffer).toFixed(1) + "%)");  
114 -  
115 - var time_str = "";  
116 - // day  
117 - time_str = padding(parseInt(time / 24 / 3600), 2, '0') + " ";  
118 - // hour  
119 - time = time % (24 * 3600);  
120 - time_str += padding(parseInt(time / 3600), 2, '0') + ":";  
121 - // minute  
122 - time = time % (3600);  
123 - time_str += padding(parseInt(time / 60), 2, '0') + ":";  
124 - // seconds  
125 - time = time % (60);  
126 - time_str += padding(parseInt(time), 2, '0');  
127 - // show  
128 - $("#txt_time").val(time_str);  
129 - };  
130 - srs_player.start();  
131 - });  
132 -  
133 - $("#main_modal").on("hide", function(){  
134 - if ($("#main_modal").is(":visible")) {  
135 - return;  
136 - }  
137 -  
138 - if (srs_player) {  
139 - srs_player.stop();  
140 - srs_player = null;  
141 - }  
142 - });  
143 -  
144 - $("#btn_play").click(function(){  
145 - url = $("#txt_url").val();  
146 - $("#main_modal").modal({show:true, keyboard:false});  
147 - });  
148 -  
149 - $("#btn_pause").click(function(){  
150 - if ($("#btn_pause").text() == "暂停") {  
151 - $("#btn_pause").text("继续");  
152 - srs_player.pause();  
153 - } else {  
154 - $("#btn_pause").text("暂停");  
155 - srs_player.resume();  
156 - }  
157 - });  
158 -  
159 - $("#srs_publish").click(function(){  
160 - url = $("#srs_publish").text();  
161 - $("#main_modal").modal({show:true, keyboard:false});  
162 - });  
163 - $("#srs_publish_ld").click(function(){  
164 - url = $("#srs_publish_ld").text();  
165 - $("#main_modal").modal({show:true, keyboard:false});  
166 - });  
167 - $("#srs_publish_sd").click(function(){  
168 - url = $("#srs_publish_sd").text();  
169 - $("#main_modal").modal({show:true, keyboard:false});  
170 - });  
171 - $("#srs_publish_fw").click(function(){  
172 - url = $("#srs_publish_fw").text();  
173 - $("#main_modal").modal({show:true, keyboard:false});  
174 - });  
175 - $("#srs_publish_fw_ld").click(function(){  
176 - url = $("#srs_publish_fw_ld").text();  
177 - $("#main_modal").modal({show:true, keyboard:false});  
178 - });  
179 - $("#srs_publish_fw_sd").click(function(){  
180 - url = $("#srs_publish_fw_sd").text();  
181 - $("#main_modal").modal({show:true, keyboard:false});  
182 - });  
183 -  
184 - var query = parse_query_string();  
185 - var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=live&hls_autostart=true";  
186 - $("#srs_publish_hls").attr("href", jwplayer_url + "&stream=livestream");  
187 - $("#srs_publish_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");  
188 - $("#srs_publish_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");  
189 - var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=forward/live&hls_autostart=true";  
190 - $("#srs_publish_fw_hls").attr("href", jwplayer_url + "&stream=livestream");  
191 - $("#srs_publish_fw_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");  
192 - $("#srs_publish_fw_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");  
193 -  
194 - if (true) {  
195 - $("#btn_dar_original").click(function(){  
196 - select_dar("#btn_dar_original", 0, 0);  
197 - });  
198 - $("#btn_dar_21_9").click(function(){  
199 - select_dar("#btn_dar_21_9", 21, 9);  
200 - });  
201 - $("#btn_dar_16_9").click(function(){  
202 - select_dar("#btn_dar_16_9", 16, 9);  
203 - });  
204 - $("#btn_dar_4_3").click(function(){  
205 - select_dar("#btn_dar_4_3", 4, 3);  
206 - });  
207 - $("#btn_dar_fill").click(function(){  
208 - select_dar("#btn_dar_fill", -1, -1);  
209 - });  
210 - }  
211 -  
212 - if (true) {  
213 - $("#btn_fs_size_video_100").click(function(){  
214 - select_fs_size("#btn_fs_size_video_100", "video", 100);  
215 - });  
216 - $("#btn_fs_size_video_75").click(function(){  
217 - select_fs_size("#btn_fs_size_video_75", "video", 75);  
218 - });  
219 - $("#btn_fs_size_video_50").click(function(){  
220 - select_fs_size("#btn_fs_size_video_50", "video", 50);  
221 - });  
222 - $("#btn_fs_size_screen_100").click(function(){  
223 - select_fs_size("#btn_fs_size_screen_100", "screen", 100);  
224 - });  
225 - $("#btn_fs_size_screen_75").click(function(){  
226 - select_fs_size("#btn_fs_size_screen_75", "screen", 75);  
227 - });  
228 - $("#btn_fs_size_screen_50").click(function(){  
229 - select_fs_size("#btn_fs_size_screen_50", "screen", 50);  
230 - });  
231 - }  
232 -  
233 - if (true) {  
234 - $("#btn_bt_0_1").click(function(){  
235 - select_buffer_time("#btn_bt_0_1", 0.1);  
236 - });  
237 - $("#btn_bt_0_2").click(function(){  
238 - select_buffer_time("#btn_bt_0_2", 0.2);  
239 - });  
240 - $("#btn_bt_0_3").click(function(){  
241 - select_buffer_time("#btn_bt_0_3", 0.3);  
242 - });  
243 - $("#btn_bt_0_5").click(function(){  
244 - select_buffer_time("#btn_bt_0_5", 0.5);  
245 - });  
246 - $("#btn_bt_0_8").click(function(){  
247 - select_buffer_time("#btn_bt_0_8", 0.8);  
248 - });  
249 - $("#btn_bt_1").click(function(){  
250 - select_buffer_time("#btn_bt_1", 1);  
251 - });  
252 - $("#btn_bt_2").click(function(){  
253 - select_buffer_time("#btn_bt_2", 2);  
254 - });  
255 - $("#btn_bt_3").click(function(){  
256 - select_buffer_time("#btn_bt_3", 3);  
257 - });  
258 - $("#btn_bt_5").click(function(){  
259 - select_buffer_time("#btn_bt_5", 5);  
260 - });  
261 - $("#btn_bt_10").click(function(){  
262 - select_buffer_time("#btn_bt_10", 10);  
263 - });  
264 - $("#btn_bt_30").click(function(){  
265 - select_buffer_time("#btn_bt_30", 30);  
266 - });  
267 - }  
268 -  
269 - var query = parse_query_string();  
270 - if (query.autostart == "true") {  
271 - url = $("#txt_url").val();  
272 - $("#main_modal").modal({show:true, keyboard:false});  
273 - }  
274 - });  
275 - </script>  
276 </head> 23 </head>
277 <body> 24 <body>
278 <div class="navbar navbar-fixed-top"> 25 <div class="navbar navbar-fixed-top">
@@ -538,4 +285,263 @@ @@ -538,4 +285,263 @@
538 <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p> 285 <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p>
539 </footer> 286 </footer>
540 </div> 287 </div>
541 -</body>  
  288 +</body>
  289 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  290 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  291 +<script type="text/javascript" src="js/swfobject.js"></script>
  292 +<script type="text/javascript" src="js/json2.js"></script>
  293 +<script type="text/javascript" src="js/srs.page.js"></script>
  294 +<script type="text/javascript" src="js/srs.log.js"></script>
  295 +<script type="text/javascript" src="js/srs.player.js"></script>
  296 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  297 +<script type="text/javascript" src="js/srs.utility.js"></script>
  298 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  299 +<script type="text/javascript">
  300 + var srs_player = null;
  301 + var url = null;
  302 +
  303 + var __active_dar = null;
  304 + function select_dar(dar_id, num, den) {
  305 + srs_player.set_dar(num, den);
  306 +
  307 + if (__active_dar) {
  308 + __active_dar.removeClass("active");
  309 + }
  310 +
  311 + __active_dar = $(dar_id).parent();
  312 + __active_dar.addClass("active");
  313 + }
  314 +
  315 + var __active_size = null;
  316 + function select_fs_size(size_id, refer, percent) {
  317 + srs_player.set_fs(refer, percent);
  318 +
  319 + if (__active_size) {
  320 + __active_size.removeClass("active");
  321 + }
  322 +
  323 + __active_size = $(size_id).parent();
  324 + __active_size.addClass("active");
  325 + }
  326 +
  327 + var __active_bt = null;
  328 + function select_buffer_time(bt_id, buffer_time) {
  329 + srs_player.set_bt(buffer_time);
  330 +
  331 + if (__active_bt) {
  332 + __active_bt.removeClass("active");
  333 + }
  334 +
  335 + __active_bt = $(bt_id).parent();
  336 + __active_bt.addClass("active");
  337 + }
  338 +
  339 + $(function(){
  340 + // get the vhost and port to set the default url.
  341 + // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
  342 + // url set to: rtmp://demo:1935/live/livestream
  343 + srs_init_rtmp("#txt_url", "#main_modal");
  344 +
  345 + $("#fs_tips").tooltip({
  346 + title: "点击视频进入或退出全屏"
  347 + });
  348 +
  349 + $("#main_modal").on("show", function(){
  350 + if (srs_player) {
  351 + return;
  352 + }
  353 +
  354 + $("#div_container").remove();
  355 +
  356 + var div_container = $("<div/>");
  357 + $(div_container).attr("id", "div_container");
  358 + $("#player").append(div_container);
  359 +
  360 + var player = $("<div/>");
  361 + $(player).attr("id", "player_id");
  362 + $(div_container).append(player);
  363 +
  364 + srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height());
  365 + srs_player.on_player_ready = function() {
  366 + select_buffer_time("#btn_bt_0_1", 0.1);
  367 + this.play(url);
  368 + };
  369 + srs_player.on_player_metadata = function(metadata) {
  370 + $("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")");
  371 + select_dar("#btn_dar_original", 0, 0);
  372 + select_fs_size("#btn_fs_size_screen_100", "screen", 100);
  373 + };
  374 + srs_player.on_player_timer = function(time, buffer_length) {
  375 + var buffer = buffer_length / this.buffer_time * 100;
  376 + $("#pb_buffer").width(Number(buffer).toFixed(1) + "%");
  377 +
  378 + $("#pb_buffer_bg").attr("title",
  379 + "缓冲区长度:" + Number(buffer_length).toFixed(1) + "秒("
  380 + + Number(buffer).toFixed(1) + "%)");
  381 +
  382 + var time_str = "";
  383 + // day
  384 + time_str = padding(parseInt(time / 24 / 3600), 2, '0') + " ";
  385 + // hour
  386 + time = time % (24 * 3600);
  387 + time_str += padding(parseInt(time / 3600), 2, '0') + ":";
  388 + // minute
  389 + time = time % (3600);
  390 + time_str += padding(parseInt(time / 60), 2, '0') + ":";
  391 + // seconds
  392 + time = time % (60);
  393 + time_str += padding(parseInt(time), 2, '0');
  394 + // show
  395 + $("#txt_time").val(time_str);
  396 + };
  397 + srs_player.start();
  398 + });
  399 +
  400 + $("#main_modal").on("hide", function(){
  401 + if ($("#main_modal").is(":visible")) {
  402 + return;
  403 + }
  404 +
  405 + if (srs_player) {
  406 + srs_player.stop();
  407 + srs_player = null;
  408 + }
  409 + });
  410 +
  411 + $("#btn_play").click(function(){
  412 + url = $("#txt_url").val();
  413 + $("#main_modal").modal({show:true, keyboard:false});
  414 + });
  415 +
  416 + $("#btn_pause").click(function(){
  417 + if ($("#btn_pause").text() == "暂停") {
  418 + $("#btn_pause").text("继续");
  419 + srs_player.pause();
  420 + } else {
  421 + $("#btn_pause").text("暂停");
  422 + srs_player.resume();
  423 + }
  424 + });
  425 +
  426 + if (true) {
  427 + $("#srs_publish").click(function () {
  428 + url = $("#srs_publish").text();
  429 + $("#main_modal").modal({show: true, keyboard: false});
  430 + });
  431 + $("#srs_publish_ld").click(function () {
  432 + url = $("#srs_publish_ld").text();
  433 + $("#main_modal").modal({show: true, keyboard: false});
  434 + });
  435 + $("#srs_publish_sd").click(function () {
  436 + url = $("#srs_publish_sd").text();
  437 + $("#main_modal").modal({show: true, keyboard: false});
  438 + });
  439 + $("#srs_publish_fw").click(function () {
  440 + url = $("#srs_publish_fw").text();
  441 + $("#main_modal").modal({show: true, keyboard: false});
  442 + });
  443 + $("#srs_publish_fw_ld").click(function () {
  444 + url = $("#srs_publish_fw_ld").text();
  445 + $("#main_modal").modal({show: true, keyboard: false});
  446 + });
  447 + $("#srs_publish_fw_sd").click(function () {
  448 + url = $("#srs_publish_fw_sd").text();
  449 + $("#main_modal").modal({show: true, keyboard: false});
  450 + });
  451 + }
  452 +
  453 + var query = parse_query_string();
  454 + var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=live&hls_autostart=true";
  455 + if (true) {
  456 + $("#srs_publish_hls").attr("href", jwplayer_url + "&stream=livestream");
  457 + $("#srs_publish_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
  458 + $("#srs_publish_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
  459 + var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=forward/live&hls_autostart=true";
  460 + $("#srs_publish_fw_hls").attr("href", jwplayer_url + "&stream=livestream");
  461 + $("#srs_publish_fw_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
  462 + $("#srs_publish_fw_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
  463 + }
  464 +
  465 + if (true) {
  466 + $("#btn_dar_original").click(function(){
  467 + select_dar("#btn_dar_original", 0, 0);
  468 + });
  469 + $("#btn_dar_21_9").click(function(){
  470 + select_dar("#btn_dar_21_9", 21, 9);
  471 + });
  472 + $("#btn_dar_16_9").click(function(){
  473 + select_dar("#btn_dar_16_9", 16, 9);
  474 + });
  475 + $("#btn_dar_4_3").click(function(){
  476 + select_dar("#btn_dar_4_3", 4, 3);
  477 + });
  478 + $("#btn_dar_fill").click(function(){
  479 + select_dar("#btn_dar_fill", -1, -1);
  480 + });
  481 + }
  482 +
  483 + if (true) {
  484 + $("#btn_fs_size_video_100").click(function(){
  485 + select_fs_size("#btn_fs_size_video_100", "video", 100);
  486 + });
  487 + $("#btn_fs_size_video_75").click(function(){
  488 + select_fs_size("#btn_fs_size_video_75", "video", 75);
  489 + });
  490 + $("#btn_fs_size_video_50").click(function(){
  491 + select_fs_size("#btn_fs_size_video_50", "video", 50);
  492 + });
  493 + $("#btn_fs_size_screen_100").click(function(){
  494 + select_fs_size("#btn_fs_size_screen_100", "screen", 100);
  495 + });
  496 + $("#btn_fs_size_screen_75").click(function(){
  497 + select_fs_size("#btn_fs_size_screen_75", "screen", 75);
  498 + });
  499 + $("#btn_fs_size_screen_50").click(function(){
  500 + select_fs_size("#btn_fs_size_screen_50", "screen", 50);
  501 + });
  502 + }
  503 +
  504 + if (true) {
  505 + $("#btn_bt_0_1").click(function(){
  506 + select_buffer_time("#btn_bt_0_1", 0.1);
  507 + });
  508 + $("#btn_bt_0_2").click(function(){
  509 + select_buffer_time("#btn_bt_0_2", 0.2);
  510 + });
  511 + $("#btn_bt_0_3").click(function(){
  512 + select_buffer_time("#btn_bt_0_3", 0.3);
  513 + });
  514 + $("#btn_bt_0_5").click(function(){
  515 + select_buffer_time("#btn_bt_0_5", 0.5);
  516 + });
  517 + $("#btn_bt_0_8").click(function(){
  518 + select_buffer_time("#btn_bt_0_8", 0.8);
  519 + });
  520 + $("#btn_bt_1").click(function(){
  521 + select_buffer_time("#btn_bt_1", 1);
  522 + });
  523 + $("#btn_bt_2").click(function(){
  524 + select_buffer_time("#btn_bt_2", 2);
  525 + });
  526 + $("#btn_bt_3").click(function(){
  527 + select_buffer_time("#btn_bt_3", 3);
  528 + });
  529 + $("#btn_bt_5").click(function(){
  530 + select_buffer_time("#btn_bt_5", 5);
  531 + });
  532 + $("#btn_bt_10").click(function(){
  533 + select_buffer_time("#btn_bt_10", 10);
  534 + });
  535 + $("#btn_bt_30").click(function(){
  536 + select_buffer_time("#btn_bt_30", 30);
  537 + });
  538 + }
  539 +
  540 + var query = parse_query_string();
  541 + if (query.autostart == "true") {
  542 + url = $("#txt_url").val();
  543 + $("#main_modal").modal({show:true, keyboard:false});
  544 + }
  545 + });
  546 +</script>
  547 +</html>
@@ -38,3 +38,4 @@ @@ -38,3 +38,4 @@
38 <buildCSSFiles/> 38 <buildCSSFiles/>
39 <flashCatalyst validateFlashCatalystCompatibility="false"/> 39 <flashCatalyst validateFlashCatalystCompatibility="false"/>
40 </actionScriptProperties> 40 </actionScriptProperties>
  41 +
@@ -4,213 +4,11 @@ @@ -4,213 +4,11 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/json2.js"></script>  
11 - <script type="text/javascript" src="js/srs.page.js"></script>  
12 - <script type="text/javascript" src="js/srs.log.js"></script>  
13 - <script type="text/javascript" src="js/srs.player.js"></script>  
14 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
15 - <script type="text/javascript" src="js/srs.utility.js"></script>  
16 <style> 7 <style>
17 body{ 8 body{
18 padding-top: 55px; 9 padding-top: 55px;
19 } 10 }
20 </style> 11 </style>
21 - <script type="text/javascript">  
22 - var srs_publisher = null;  
23 - var remote_player = null;  
24 - var realtime_player = null;  
25 -  
26 - var query = parse_query_string();  
27 - $(function(){  
28 - // get the vhost and port to set the default url.  
29 - // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo  
30 - // url set to: rtmp://demo:1935/live/livestream  
31 - srs_init("#txt_url", null, null);  
32 -  
33 - if (query.agent == "true") {  
34 - document.write(navigator.userAgent);  
35 - return;  
36 - }  
37 -  
38 - $("#btn_video_settings").click(function(){  
39 - $("#video_modal").modal({show:true});  
40 - });  
41 - $("#btn_audio_settings").click(function(){  
42 - $("#audio_modal").modal({show:true});  
43 - });  
44 -  
45 - $("#remote_tips").tooltip({  
46 - title: "为了支持HLS输出,FLASH编码器输出的流需要经过转码(VP6=>H264,MP3=>aac),所以会黑屏较长时间,请耐心等待"  
47 - });  
48 - $("#low_latecy_tips").tooltip({  
49 - title: "服务器不转码直接转发FLASH编码器的流,所以延迟比支持HLS的流要低很多"  
50 - });  
51 - $("#realtime_player_url").tooltip({  
52 - title: "右键复制RTMP地址"  
53 - });  
54 - $("#remote_player_url").tooltip({  
55 - title: "右键复制RTMP地址"  
56 - });  
57 -  
58 - $("#btn_publish").click(on_user_publish);  
59 -  
60 - // for publish, we use randome stream name.  
61 - $("#txt_url").val($("#txt_url").val() + "." + new Date().getTime());  
62 -  
63 - // start the publisher.  
64 - srs_publisher = new SrsPublisher("local_publisher", 430, 185);  
65 - srs_publisher.on_publisher_ready = function(cameras, microphones) {  
66 - srs_publisher_initialize_page(  
67 - cameras, microphones,  
68 - "#sl_cameras", "#sl_microphones",  
69 - "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",  
70 - "#sl_fps", "#sl_bitrate",  
71 - "#sl_acodec"  
72 - );  
73 - };  
74 - srs_publisher.on_publisher_error = function(code, desc) {  
75 - if (!on_publish_stop()) {  
76 - return;  
77 - }  
78 - error(code, desc + "请重试。");  
79 - };  
80 - srs_publisher.on_publisher_warn = function(code, desc) {  
81 - warn(code, desc);  
82 - };  
83 - srs_publisher.start();  
84 -  
85 - update_play_url();  
86 -  
87 - // if no play specified, donot show the player, for debug the publisher.  
88 - if (query.no_play != "true") {  
89 - // start the normal player with HLS supported.  
90 - remote_player = new SrsPlayer("remote_player", 430, 185);  
91 - remote_player.on_player_ready = function() {  
92 - this.set_bt(0.8);  
93 - };  
94 - remote_player.on_player_metadata = function(metadata) {  
95 - this.set_dar(0, 0);  
96 - this.set_fs("screen", 100);  
97 - }  
98 - remote_player.start();  
99 -  
100 - // start the realtime player.  
101 - realtime_player = new SrsPlayer("realtime_player", 430, 185);  
102 - realtime_player.on_player_ready = function() {  
103 - this.set_bt(0.8);  
104 - };  
105 - realtime_player.on_player_metadata = function(metadata) {  
106 - this.set_dar(0, 0);  
107 - this.set_fs("screen", 100);  
108 - }  
109 - realtime_player.start();  
110 - }  
111 - });  
112 -  
113 - function on_publish_stop() {  
114 - if (!srs_can_republish()) {  
115 - $("#btn_join").attr("disabled", true);  
116 - error(0, "您使用的浏览器很弱,请关闭页面后重新打开页面(刷新也不管用)。<br/>推荐使用Chrome/Firefox/Safari/Opera浏览器,支持重试");  
117 -  
118 - srs_log_disabled = true;  
119 - return false;  
120 - }  
121 -  
122 - return true;  
123 - }  
124 -  
125 - /**  
126 - * we generate the transcoded stream url for flash publish donot support HLS  
127 - * which requires aac, so the publish vhost maybe players for example, we  
128 - * use players_pub vhost(transcoded stream to which) for all clients,  
129 - * both players and players_pub are write HLS to the sample dir,  
130 - * it's ok for the players vhost disabled the HLS, only the  
131 - * players_pub enalbed HLS.  
132 - */  
133 - function update_play_url() {  
134 - var url = $("#txt_url").val();  
135 - var ret = srs_parse_rtmp_url(url);  
136 -  
137 - var remote_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app + "...vhost..." + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;  
138 - $("#realtime_player_url").attr("href", url).attr("target", "_blank");  
139 - $("#remote_player_url").attr("href", remote_url).attr("target", "_blank");  
140 -  
141 - var srs_player_url = "http://" + query.host + query.dir + "/srs_player.html?";  
142 - srs_player_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;  
143 - srs_player_url += "&autostart=true";  
144 -  
145 - var srs_player_rt_url = "http://" + query.host + query.dir + "/srs_player.html?";  
146 - srs_player_rt_url += "vhost=" + ret.vhost + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;  
147 - srs_player_rt_url += "&autostart=true";  
148 -  
149 - var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?";  
150 - jwplayer_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;  
151 - jwplayer_url += "&hls_autostart=true";  
152 -  
153 - var hls_url = "http://" + ret.server + ":" + query.http_port + "/" + ret.app + "/" + ret.stream + ".m3u8";  
154 -  
155 - $("#txt_play_realtime").text("RTMP低延时(点击打开)").attr("href", srs_player_rt_url).attr("target", "_blank");  
156 - $("#txt_play_url").text("RTMP已转码(点击打开)").attr("href", srs_player_url).attr("target", "_blank");  
157 - $("#txt_play_hls").text("HLS-m3u8(点击打开或右键复制)").attr("href", hls_url).attr("target", "_blank");  
158 - $("#txt_play_jwplayer").text("HLS-JWPlayer(点击打开)").attr("href", jwplayer_url).attr("target", "_blank");  
159 - }  
160 - function on_user_publish() {  
161 - if ($("#btn_publish").text() == "停止发布") {  
162 - srs_publisher.stop();  
163 - $("#btn_publish").text("发布视频");  
164 - //$("#txt_play_realtime").text("RTMP低延时(请发布视频)").attr("href", "#").attr("target", "_self");  
165 - //$("#txt_play_realtime").attr("href", "#").attr("target", "_self");  
166 - //$("#txt_play_url").text("RTMP已转码(请发布视频)").attr("href", "#").attr("target", "_self");  
167 - //$("#remote_player_url").attr("href", "#").attr("target", "_self");  
168 - //$("#txt_play_hls").text("HLS-m3u8(请发布视频)").attr("href", "#").attr("target", "_self");  
169 - //$("#txt_play_jwplayer").text("HLS-JWPlayer(请发布视频)").attr("href", "#").attr("target", "_self");  
170 -  
171 - if (!on_publish_stop()) {  
172 - return;  
173 - }  
174 - return;  
175 - }  
176 -  
177 - $("#btn_publish").text("停止发布");  
178 -  
179 - update_play_url();  
180 -  
181 - var url = $("#txt_url").val();  
182 - var vcodec = {};  
183 - var acodec = {};  
184 - srs_publiser_get_codec(  
185 - vcodec, acodec,  
186 - "#sl_cameras", "#sl_microphones",  
187 - "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",  
188 - "#sl_fps", "#sl_bitrate",  
189 - "#sl_acodec"  
190 - );  
191 -  
192 - info("开始推流到服务器");  
193 - srs_publisher.publish(url, vcodec, acodec);  
194 -  
195 - if (realtime_player) {  
196 - // directly play the url for the realtime player.  
197 - realtime_player.stop();  
198 - realtime_player.play(url);  
199 - }  
200 -  
201 - if (remote_player) {  
202 - // the normal player should play the transcoded stream in another vhost.  
203 - // for example, publish stream to vhost players,  
204 - // the realtime player play the vhost players, which may donot support HLS,  
205 - // the normal player play the vhost players_pub, which transcoded to h264/aac with HLS.  
206 - var ret = srs_parse_rtmp_url(url);  
207 - var pub_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app;  
208 - pub_url += "?vhost=" + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;  
209 - remote_player.stop();  
210 - remote_player.play(pub_url);  
211 - }  
212 - }  
213 - </script>  
214 </head> 12 </head>
215 <body> 13 <body>
216 <div class="navbar navbar-fixed-top"> 14 <div class="navbar navbar-fixed-top">
@@ -464,4 +262,208 @@ @@ -464,4 +262,208 @@
464 </footer> 262 </footer>
465 </div> 263 </div>
466 </body> 264 </body>
  265 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  266 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  267 +<script type="text/javascript" src="js/swfobject.js"></script>
  268 +<script type="text/javascript" src="js/json2.js"></script>
  269 +<script type="text/javascript" src="js/srs.page.js"></script>
  270 +<script type="text/javascript" src="js/srs.log.js"></script>
  271 +<script type="text/javascript" src="js/srs.player.js"></script>
  272 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  273 +<script type="text/javascript" src="js/srs.utility.js"></script>
  274 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  275 +<script type="text/javascript">
  276 + var srs_publisher = null;
  277 + var remote_player = null;
  278 + var realtime_player = null;
  279 +
  280 + var query = parse_query_string();
  281 + $(function(){
  282 + // get the vhost and port to set the default url.
  283 + // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
  284 + // url set to: rtmp://demo:1935/live/livestream
  285 + srs_init_rtmp("#txt_url", null);
  286 +
  287 + if (query.agent == "true") {
  288 + document.write(navigator.userAgent);
  289 + return;
  290 + }
  291 +
  292 + $("#btn_video_settings").click(function(){
  293 + $("#video_modal").modal({show:true});
  294 + });
  295 + $("#btn_audio_settings").click(function(){
  296 + $("#audio_modal").modal({show:true});
  297 + });
  298 +
  299 + $("#remote_tips").tooltip({
  300 + title: "为了支持HLS输出,FLASH编码器输出的流需要经过转码(VP6=>H264,MP3=>aac),所以会黑屏较长时间,请耐心等待"
  301 + });
  302 + $("#low_latecy_tips").tooltip({
  303 + title: "服务器不转码直接转发FLASH编码器的流,所以延迟比支持HLS的流要低很多"
  304 + });
  305 + $("#realtime_player_url").tooltip({
  306 + title: "右键复制RTMP地址"
  307 + });
  308 + $("#remote_player_url").tooltip({
  309 + title: "右键复制RTMP地址"
  310 + });
  311 +
  312 + $("#btn_publish").click(on_user_publish);
  313 +
  314 + // for publish, we use randome stream name.
  315 + $("#txt_url").val($("#txt_url").val() + "." + new Date().getTime());
  316 +
  317 + // start the publisher.
  318 + srs_publisher = new SrsPublisher("local_publisher", 430, 185);
  319 + srs_publisher.on_publisher_ready = function(cameras, microphones) {
  320 + srs_publisher_initialize_page(
  321 + cameras, microphones,
  322 + "#sl_cameras", "#sl_microphones",
  323 + "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",
  324 + "#sl_fps", "#sl_bitrate",
  325 + "#sl_acodec"
  326 + );
  327 + };
  328 + srs_publisher.on_publisher_error = function(code, desc) {
  329 + if (!on_publish_stop()) {
  330 + return;
  331 + }
  332 + error(code, desc + "请重试。");
  333 + };
  334 + srs_publisher.on_publisher_warn = function(code, desc) {
  335 + warn(code, desc);
  336 + };
  337 + srs_publisher.start();
  338 +
  339 + update_play_url();
  340 +
  341 + // if no play specified, donot show the player, for debug the publisher.
  342 + if (query.no_play != "true") {
  343 + // start the normal player with HLS supported.
  344 + remote_player = new SrsPlayer("remote_player", 430, 185);
  345 + remote_player.on_player_ready = function() {
  346 + this.set_bt(0.8);
  347 + };
  348 + remote_player.on_player_metadata = function(metadata) {
  349 + this.set_dar(0, 0);
  350 + this.set_fs("screen", 100);
  351 + }
  352 + remote_player.start();
  353 +
  354 + // start the realtime player.
  355 + realtime_player = new SrsPlayer("realtime_player", 430, 185);
  356 + realtime_player.on_player_ready = function() {
  357 + this.set_bt(0.8);
  358 + };
  359 + realtime_player.on_player_metadata = function(metadata) {
  360 + this.set_dar(0, 0);
  361 + this.set_fs("screen", 100);
  362 + }
  363 + realtime_player.start();
  364 + }
  365 + });
  366 +
  367 + function on_publish_stop() {
  368 + if (!srs_can_republish()) {
  369 + $("#btn_join").attr("disabled", true);
  370 + error(0, "您使用的浏览器很弱,请关闭页面后重新打开页面(刷新也不管用)。<br/>推荐使用Chrome/Firefox/Safari/Opera浏览器,支持重试");
  371 +
  372 + srs_log_disabled = true;
  373 + return false;
  374 + }
  375 +
  376 + return true;
  377 + }
  378 +
  379 + /**
  380 + * we generate the transcoded stream url for flash publish donot support HLS
  381 + * which requires aac, so the publish vhost maybe players for example, we
  382 + * use players_pub vhost(transcoded stream to which) for all clients,
  383 + * both players and players_pub are write HLS to the sample dir,
  384 + * it's ok for the players vhost disabled the HLS, only the
  385 + * players_pub enalbed HLS.
  386 + */
  387 + function update_play_url() {
  388 + var url = $("#txt_url").val();
  389 + var ret = srs_parse_rtmp_url(url);
  390 +
  391 + var remote_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app + "...vhost..." + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;
  392 + $("#realtime_player_url").attr("href", url).attr("target", "_blank");
  393 + $("#remote_player_url").attr("href", remote_url).attr("target", "_blank");
  394 +
  395 + var srs_player_url = "http://" + query.host + query.dir + "/srs_player.html?";
  396 + srs_player_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
  397 + srs_player_url += "&autostart=true";
  398 +
  399 + var srs_player_rt_url = "http://" + query.host + query.dir + "/srs_player.html?";
  400 + srs_player_rt_url += "vhost=" + ret.vhost + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
  401 + srs_player_rt_url += "&autostart=true";
  402 +
  403 + var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?";
  404 + jwplayer_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
  405 + jwplayer_url += "&hls_autostart=true";
  406 +
  407 + var hls_url = "http://" + ret.server + ":" + query.http_port + "/" + ret.app + "/" + ret.stream + ".m3u8";
  408 +
  409 + $("#txt_play_realtime").text("RTMP低延时(点击打开)").attr("href", srs_player_rt_url).attr("target", "_blank");
  410 + $("#txt_play_url").text("RTMP已转码(点击打开)").attr("href", srs_player_url).attr("target", "_blank");
  411 + $("#txt_play_hls").text("HLS-m3u8(点击打开或右键复制)").attr("href", hls_url).attr("target", "_blank");
  412 + $("#txt_play_jwplayer").text("HLS-JWPlayer(点击打开)").attr("href", jwplayer_url).attr("target", "_blank");
  413 + }
  414 + function on_user_publish() {
  415 + if ($("#btn_publish").text() == "停止发布") {
  416 + srs_publisher.stop();
  417 + $("#btn_publish").text("发布视频");
  418 + //$("#txt_play_realtime").text("RTMP低延时(请发布视频)").attr("href", "#").attr("target", "_self");
  419 + //$("#txt_play_realtime").attr("href", "#").attr("target", "_self");
  420 + //$("#txt_play_url").text("RTMP已转码(请发布视频)").attr("href", "#").attr("target", "_self");
  421 + //$("#remote_player_url").attr("href", "#").attr("target", "_self");
  422 + //$("#txt_play_hls").text("HLS-m3u8(请发布视频)").attr("href", "#").attr("target", "_self");
  423 + //$("#txt_play_jwplayer").text("HLS-JWPlayer(请发布视频)").attr("href", "#").attr("target", "_self");
  424 +
  425 + if (!on_publish_stop()) {
  426 + return;
  427 + }
  428 + return;
  429 + }
  430 +
  431 + $("#btn_publish").text("停止发布");
  432 +
  433 + update_play_url();
  434 +
  435 + var url = $("#txt_url").val();
  436 + var vcodec = {};
  437 + var acodec = {};
  438 + srs_publiser_get_codec(
  439 + vcodec, acodec,
  440 + "#sl_cameras", "#sl_microphones",
  441 + "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",
  442 + "#sl_fps", "#sl_bitrate",
  443 + "#sl_acodec"
  444 + );
  445 +
  446 + info("开始推流到服务器");
  447 + srs_publisher.publish(url, vcodec, acodec);
  448 +
  449 + if (realtime_player) {
  450 + // directly play the url for the realtime player.
  451 + realtime_player.stop();
  452 + realtime_player.play(url);
  453 + }
  454 +
  455 + if (remote_player) {
  456 + // the normal player should play the transcoded stream in another vhost.
  457 + // for example, publish stream to vhost players,
  458 + // the realtime player play the vhost players, which may donot support HLS,
  459 + // the normal player play the vhost players_pub, which transcoded to h264/aac with HLS.
  460 + var ret = srs_parse_rtmp_url(url);
  461 + var pub_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app;
  462 + pub_url += "?vhost=" + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;
  463 + remote_player.stop();
  464 + remote_player.play(pub_url);
  465 + }
  466 + }
  467 +</script>
  468 +</html>
467 469
@@ -4,21 +4,11 @@ @@ -4,21 +4,11 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/srs.page.js"></script>  
11 <style> 7 <style>
12 body{ 8 body{
13 padding-top: 55px; 9 padding-top: 55px;
14 } 10 }
15 </style> 11 </style>
16 - <script type="text/javascript">  
17 - $(function(){  
18 - update_nav();  
19 - $("#main_frame").attr("src", "http://www.videolan.org/vlc/");  
20 - });  
21 - </script>  
22 </head> 12 </head>
23 <body> 13 <body>
24 <div class="navbar navbar-fixed-top"> 14 <div class="navbar navbar-fixed-top">
@@ -49,4 +39,15 @@ @@ -49,4 +39,15 @@
49 </footer> 39 </footer>
50 </div> 40 </div>
51 </body> 41 </body>
  42 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  43 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  44 +<script type="text/javascript" src="js/swfobject.js"></script>
  45 +<script type="text/javascript" src="js/srs.page.js"></script>
  46 +<script type="text/javascript">
  47 + $(function(){
  48 + update_nav();
  49 + $("#main_frame").attr("src", "http://www.videolan.org/vlc/");
  50 + });
  51 +</script>
  52 +</html>
52 53