mirror of
https://github.com/ossrs/srs.git
synced 2025-02-15 04:42:04 +00:00
Remove files
This commit is contained in:
parent
a7631a2850
commit
6c8622bba1
77 changed files with 0 additions and 16783 deletions
17
trunk/3rdparty/ccache/build_ccache.sh
vendored
17
trunk/3rdparty/ccache/build_ccache.sh
vendored
|
@ -1,17 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# check exists.
|
||||
if [[ -f /usr/local/bin/ccache ]]; then
|
||||
echo "ccache is ok";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
# check sudoer.
|
||||
sudo echo "ok" > /dev/null 2>&1;
|
||||
ret=$?; if [[ 0 -ne ${ret} ]]; then echo "you must be sudoer"; exit 1; fi
|
||||
|
||||
unzip ccache-3.1.9.zip && cd ccache-3.1.9 && ./configure && make
|
||||
ret=$?; if [[ $ret -ne 0 ]]; then echo "build ccache failed."; exit $ret; fi
|
||||
|
||||
sudo cp ccache /usr/local/bin && sudo ln -s ccache /usr/local/bin/gcc && sudo ln -s ccache /usr/local/bin/g++ && sudo ln -s ccache /usr/local/bin/cc && sudo ln -s ccache /usr/local/bin/c++
|
||||
ret=$?; if [[ $ret -ne 0 ]]; then echo "install ccache failed."; exit $ret; fi
|
BIN
trunk/3rdparty/ccache/ccache-3.1.9.zip
vendored
BIN
trunk/3rdparty/ccache/ccache-3.1.9.zip
vendored
Binary file not shown.
11
trunk/3rdparty/ccache/readme.txt
vendored
11
trunk/3rdparty/ccache/readme.txt
vendored
|
@ -1,11 +0,0 @@
|
|||
ccache是samba组织提供的加速编译过程的工具,
|
||||
使用虚拟机编译可以考虑用这个工具,让编译过程飞快。
|
||||
|
||||
链接:
|
||||
http://ccache.samba.org/
|
||||
http://samba.org/ftp/ccache/ccache-3.1.9.tar.xz
|
||||
http://ccache.samba.org/manual.html
|
||||
|
||||
安装方法:
|
||||
bash build_ccache.sh
|
||||
注意:要求以sudoer执行,要修改文件。
|
BIN
trunk/3rdparty/gperftools-2.1.zip
vendored
BIN
trunk/3rdparty/gperftools-2.1.zip
vendored
Binary file not shown.
4
trunk/3rdparty/gprof/readme.txt
vendored
4
trunk/3rdparty/gprof/readme.txt
vendored
|
@ -1,4 +0,0 @@
|
|||
|
||||
为了压缩仓库尺寸,gprof的文件不在新版本提供,可以切换到2.0分支安装:
|
||||
https://github.com/ossrs/srs/tree/2.0release/trunk/3rdparty/gprof
|
||||
|
BIN
trunk/3rdparty/jquery-1.10.2.zip
vendored
BIN
trunk/3rdparty/jquery-1.10.2.zip
vendored
Binary file not shown.
BIN
trunk/3rdparty/openssl-1.1.0e.zip
vendored
BIN
trunk/3rdparty/openssl-1.1.0e.zip
vendored
Binary file not shown.
|
@ -1,17 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="players/js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="players/js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="players/js/winlin.utility.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
setTimeout(function(){
|
||||
window.location.href = "players/index.html" + window.location.search;
|
||||
}, 500);
|
||||
</script>
|
||||
</body>
|
|
@ -1,3 +0,0 @@
|
|||
<cross-domain-policy>
|
||||
<allow-access-from domain="*"/>
|
||||
</cross-domain-policy>
|
9
trunk/research/players/css/bootstrap.min.css
vendored
9
trunk/research/players/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 783 B |
|
@ -1,38 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||
<script type="text/javascript" src="js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="js/winlin.utility.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
update_nav();
|
||||
|
||||
var query = parse_query_string();
|
||||
var url = "srs_player.html?vhost=" + srs_get_player_vhost();
|
||||
|
||||
for (var key in query.user_query) {
|
||||
if (key == "vhost") {
|
||||
continue;
|
||||
}
|
||||
url += "&" + key + "=" + query[key];
|
||||
}
|
||||
|
||||
window.location.href = url;
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
Binary file not shown.
Binary file not shown.
6
trunk/research/players/js/bootstrap.min.js
vendored
6
trunk/research/players/js/bootstrap.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,486 +0,0 @@
|
|||
/*
|
||||
json2.js
|
||||
2013-05-26
|
||||
|
||||
Public Domain.
|
||||
|
||||
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||
|
||||
See http://www.JSON.org/js.html
|
||||
|
||||
|
||||
This code should be minified before deployment.
|
||||
See http://javascript.crockford.com/jsmin.html
|
||||
|
||||
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||
NOT CONTROL.
|
||||
|
||||
|
||||
This file creates a global JSON object containing two methods: stringify
|
||||
and parse.
|
||||
|
||||
JSON.stringify(value, replacer, space)
|
||||
value any JavaScript value, usually an object or array.
|
||||
|
||||
replacer an optional parameter that determines how object
|
||||
values are stringified for objects. It can be a
|
||||
function or an array of strings.
|
||||
|
||||
space an optional parameter that specifies the indentation
|
||||
of nested structures. If it is omitted, the text will
|
||||
be packed without extra whitespace. If it is a number,
|
||||
it will specify the number of spaces to indent at each
|
||||
level. If it is a string (such as '\t' or ' '),
|
||||
it contains the characters used to indent at each level.
|
||||
|
||||
This method produces a JSON text from a JavaScript value.
|
||||
|
||||
When an object value is found, if the object contains a toJSON
|
||||
method, its toJSON method will be called and the result will be
|
||||
stringified. A toJSON method does not serialize: it returns the
|
||||
value represented by the name/value pair that should be serialized,
|
||||
or undefined if nothing should be serialized. The toJSON method
|
||||
will be passed the key associated with the value, and this will be
|
||||
bound to the value
|
||||
|
||||
For example, this would serialize Dates as ISO strings.
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
return this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z';
|
||||
};
|
||||
|
||||
You can provide an optional replacer method. It will be passed the
|
||||
key and value of each member, with this bound to the containing
|
||||
object. The value that is returned from your method will be
|
||||
serialized. If your method returns undefined, then the member will
|
||||
be excluded from the serialization.
|
||||
|
||||
If the replacer parameter is an array of strings, then it will be
|
||||
used to select the members to be serialized. It filters the results
|
||||
such that only members with keys listed in the replacer array are
|
||||
stringified.
|
||||
|
||||
Values that do not have JSON representations, such as undefined or
|
||||
functions, will not be serialized. Such values in objects will be
|
||||
dropped; in arrays they will be replaced with null. You can use
|
||||
a replacer function to replace those with JSON values.
|
||||
JSON.stringify(undefined) returns undefined.
|
||||
|
||||
The optional space parameter produces a stringification of the
|
||||
value that is filled with line breaks and indentation to make it
|
||||
easier to read.
|
||||
|
||||
If the space parameter is a non-empty string, then that string will
|
||||
be used for indentation. If the space parameter is a number, then
|
||||
the indentation will be that many spaces.
|
||||
|
||||
Example:
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||
// text is '["e",{"pluribus":"unum"}]'
|
||||
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||
|
||||
text = JSON.stringify([new Date()], function (key, value) {
|
||||
return this[key] instanceof Date ?
|
||||
'Date(' + this[key] + ')' : value;
|
||||
});
|
||||
// text is '["Date(---current time---)"]'
|
||||
|
||||
|
||||
JSON.parse(text, reviver)
|
||||
This method parses a JSON text to produce an object or array.
|
||||
It can throw a SyntaxError exception.
|
||||
|
||||
The optional reviver parameter is a function that can filter and
|
||||
transform the results. It receives each of the keys and values,
|
||||
and its return value is used instead of the original value.
|
||||
If it returns what it received, then the structure is not modified.
|
||||
If it returns undefined then the member is deleted.
|
||||
|
||||
Example:
|
||||
|
||||
// Parse the text. Values that look like ISO date strings will
|
||||
// be converted to Date objects.
|
||||
|
||||
myData = JSON.parse(text, function (key, value) {
|
||||
var a;
|
||||
if (typeof value === 'string') {
|
||||
a =
|
||||
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||
if (a) {
|
||||
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||
+a[5], +a[6]));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||
var d;
|
||||
if (typeof value === 'string' &&
|
||||
value.slice(0, 5) === 'Date(' &&
|
||||
value.slice(-1) === ')') {
|
||||
d = new Date(value.slice(5, -1));
|
||||
if (d) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
|
||||
This is a reference implementation. You are free to copy, modify, or
|
||||
redistribute.
|
||||
*/
|
||||
|
||||
/*jslint evil: true, regexp: true */
|
||||
|
||||
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||
test, toJSON, toString, valueOf
|
||||
*/
|
||||
|
||||
|
||||
// Create a JSON object only if one does not already exist. We create the
|
||||
// methods in a closure to avoid creating global variables.
|
||||
|
||||
if (typeof JSON !== 'object') {
|
||||
JSON = {};
|
||||
}
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
if (typeof Date.prototype.toJSON !== 'function') {
|
||||
|
||||
Date.prototype.toJSON = function () {
|
||||
|
||||
return isFinite(this.valueOf())
|
||||
? this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z'
|
||||
: null;
|
||||
};
|
||||
|
||||
String.prototype.toJSON =
|
||||
Number.prototype.toJSON =
|
||||
Boolean.prototype.toJSON = function () {
|
||||
return this.valueOf();
|
||||
};
|
||||
}
|
||||
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
gap,
|
||||
indent,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
},
|
||||
rep;
|
||||
|
||||
|
||||
function quote(string) {
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// sequences.
|
||||
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string'
|
||||
? c
|
||||
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' : '"' + string + '"';
|
||||
}
|
||||
|
||||
|
||||
function str(key, holder) {
|
||||
|
||||
// Produce a string from holder[key].
|
||||
|
||||
var i, // The loop counter.
|
||||
k, // The member key.
|
||||
v, // The member value.
|
||||
length,
|
||||
mind = gap,
|
||||
partial,
|
||||
value = holder[key];
|
||||
|
||||
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||
|
||||
if (value && typeof value === 'object' &&
|
||||
typeof value.toJSON === 'function') {
|
||||
value = value.toJSON(key);
|
||||
}
|
||||
|
||||
// If we were called with a replacer function, then call the replacer to
|
||||
// obtain a replacement value.
|
||||
|
||||
if (typeof rep === 'function') {
|
||||
value = rep.call(holder, key, value);
|
||||
}
|
||||
|
||||
// What happens next depends on the value's type.
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return quote(value);
|
||||
|
||||
case 'number':
|
||||
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
|
||||
// If the value is a boolean or null, convert it to a string. Note:
|
||||
// typeof null does not produce 'null'. The case is included here in
|
||||
// the remote chance that this gets fixed someday.
|
||||
|
||||
return String(value);
|
||||
|
||||
// If the type is 'object', we might be dealing with an object or an array or
|
||||
// null.
|
||||
|
||||
case 'object':
|
||||
|
||||
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||
// so watch out for that case.
|
||||
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// Make an array to hold the partial results of stringifying this object value.
|
||||
|
||||
gap += indent;
|
||||
partial = [];
|
||||
|
||||
// Is the value an array?
|
||||
|
||||
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||
|
||||
// The value is an array. Stringify every element. Use null as a placeholder
|
||||
// for non-JSON values.
|
||||
|
||||
length = value.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
partial[i] = str(i, value) || 'null';
|
||||
}
|
||||
|
||||
// Join all of the elements together, separated with commas, and wrap them in
|
||||
// brackets.
|
||||
|
||||
v = partial.length === 0
|
||||
? '[]'
|
||||
: gap
|
||||
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
|
||||
: '[' + partial.join(',') + ']';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
|
||||
// If the replacer is an array, use it to select the members to be stringified.
|
||||
|
||||
if (rep && typeof rep === 'object') {
|
||||
length = rep.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
if (typeof rep[i] === 'string') {
|
||||
k = rep[i];
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// Otherwise, iterate through all of the keys in the object.
|
||||
|
||||
for (k in value) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Join all of the member texts together, separated with commas,
|
||||
// and wrap them in braces.
|
||||
|
||||
v = partial.length === 0
|
||||
? '{}'
|
||||
: gap
|
||||
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
|
||||
: '{' + partial.join(',') + '}';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
// If the JSON object does not yet have a stringify method, give it one.
|
||||
|
||||
if (typeof JSON.stringify !== 'function') {
|
||||
JSON.stringify = function (value, replacer, space) {
|
||||
|
||||
// The stringify method takes a value and an optional replacer, and an optional
|
||||
// space parameter, and returns a JSON text. The replacer can be a function
|
||||
// that can replace values, or an array of strings that will select the keys.
|
||||
// A default replacer method can be provided. Use of the space parameter can
|
||||
// produce text that is more easily readable.
|
||||
|
||||
var i;
|
||||
gap = '';
|
||||
indent = '';
|
||||
|
||||
// If the space parameter is a number, make an indent string containing that
|
||||
// many spaces.
|
||||
|
||||
if (typeof space === 'number') {
|
||||
for (i = 0; i < space; i += 1) {
|
||||
indent += ' ';
|
||||
}
|
||||
|
||||
// If the space parameter is a string, it will be used as the indent string.
|
||||
|
||||
} else if (typeof space === 'string') {
|
||||
indent = space;
|
||||
}
|
||||
|
||||
// If there is a replacer, it must be a function or an array.
|
||||
// Otherwise, throw an error.
|
||||
|
||||
rep = replacer;
|
||||
if (replacer && typeof replacer !== 'function' &&
|
||||
(typeof replacer !== 'object' ||
|
||||
typeof replacer.length !== 'number')) {
|
||||
throw new Error('JSON.stringify');
|
||||
}
|
||||
|
||||
// Make a fake root object containing our value under the key of ''.
|
||||
// Return the result of stringifying the value.
|
||||
|
||||
return str('', {'': value});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// If the JSON object does not yet have a parse method, give it one.
|
||||
|
||||
if (typeof JSON.parse !== 'function') {
|
||||
JSON.parse = function (text, reviver) {
|
||||
|
||||
// The parse method takes a text and an optional reviver function, and returns
|
||||
// a JavaScript value if the text is a valid JSON text.
|
||||
|
||||
var j;
|
||||
|
||||
function walk(holder, key) {
|
||||
|
||||
// The walk method is used to recursively walk the resulting structure so
|
||||
// that modifications can be made.
|
||||
|
||||
var k, v, value = holder[key];
|
||||
if (value && typeof value === 'object') {
|
||||
for (k in value) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||
v = walk(value, k);
|
||||
if (v !== undefined) {
|
||||
value[k] = v;
|
||||
} else {
|
||||
delete value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reviver.call(holder, key, value);
|
||||
}
|
||||
|
||||
|
||||
// Parsing happens in four stages. In the first stage, we replace certain
|
||||
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||
|
||||
text = String(text);
|
||||
cx.lastIndex = 0;
|
||||
if (cx.test(text)) {
|
||||
text = text.replace(cx, function (a) {
|
||||
return '\\u' +
|
||||
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
});
|
||||
}
|
||||
|
||||
// In the second stage, we run the text against regular expressions that look
|
||||
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||
// because they can cause invocation, and '=' because it can cause mutation.
|
||||
// But just to be safe, we want to reject all unexpected forms.
|
||||
|
||||
// We split the second stage into 4 regexp operations in order to work around
|
||||
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||
// we look to see that the remaining characters are only whitespace or ']' or
|
||||
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||
|
||||
if (/^[\],:{}\s]*$/
|
||||
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
|
||||
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
|
||||
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||
|
||||
// In the third stage we use the eval function to compile the text into a
|
||||
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||
// in parens to eliminate the ambiguity.
|
||||
|
||||
j = eval('(' + text + ')');
|
||||
|
||||
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||
// each name/value pair to a reviver function for possible transformation.
|
||||
|
||||
return typeof reviver === 'function'
|
||||
? walk({'': j}, '')
|
||||
: j;
|
||||
}
|
||||
|
||||
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||
|
||||
throw new SyntaxError('JSON.parse');
|
||||
};
|
||||
}
|
||||
}());
|
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -1,76 +0,0 @@
|
|||
"undefined"==typeof jwplayer&&(jwplayer=function(f){if(jwplayer.api)return jwplayer.api.selectPlayer(f)},jwplayer.version="6.4.3359",jwplayer.vid=document.createElement("video"),jwplayer.audio=document.createElement("audio"),jwplayer.source=document.createElement("source"),function(f){function a(g){return function(){return c(g)}}var l=document,e=window,j=navigator,b=f.utils=function(){};b.exists=function(g){switch(typeof g){case "string":return 0<g.length;case "object":return null!==g;case "undefined":return!1}return!0};
|
||||
b.styleDimension=function(g){return g+(0<g.toString().indexOf("%")?"":"px")};b.getAbsolutePath=function(g,a){b.exists(a)||(a=l.location.href);if(b.exists(g)){var c;if(b.exists(g)){c=g.indexOf("://");var j=g.indexOf("?");c=0<c&&(0>j||j>c)}else c=void 0;if(c)return g;c=a.substring(0,a.indexOf("://")+3);var j=a.substring(c.length,a.indexOf("/",c.length+1)),d;0===g.indexOf("/")?d=g.split("/"):(d=a.split("?")[0],d=d.substring(c.length+j.length+1,d.lastIndexOf("/")),d=d.split("/").concat(g.split("/")));
|
||||
for(var h=[],e=0;e<d.length;e++)d[e]&&(b.exists(d[e])&&"."!=d[e])&&(".."==d[e]?h.pop():h.push(d[e]));return c+j+"/"+h.join("/")}};b.extend=function(){var a=b.extend.arguments;if(1<a.length){for(var c=1;c<a.length;c++)b.foreach(a[c],function(c,d){try{b.exists(d)&&(a[0][c]=d)}catch(j){}});return a[0]}return null};b.log=function(a,b){"undefined"!=typeof console&&"undefined"!=typeof console.log&&(b?console.log(a,b):console.log(a))};var c=b.userAgentMatch=function(a){return null!==j.userAgent.toLowerCase().match(a)};
|
||||
b.isIE=a(/msie/i);b.isFF=a(/firefox/i);b.isChrome=a(/chrome/i);b.isIOS=a(/iP(hone|ad|od)/i);b.isIPod=a(/iP(hone|od)/i);b.isIPad=a(/iPad/i);b.isSafari602=a(/Macintosh.*Mac OS X 10_8.*6\.0\.\d* Safari/i);b.isAndroid=function(a){return a?c(RegExp("android.*"+a,"i")):c(/android/i)};b.isMobile=function(){return b.isIOS()||b.isAndroid()};b.saveCookie=function(a,b){l.cookie="jwplayer."+a+"\x3d"+b+"; path\x3d/"};b.getCookies=function(){for(var a={},b=l.cookie.split("; "),c=0;c<b.length;c++){var d=b[c].split("\x3d");
|
||||
0==d[0].indexOf("jwplayer.")&&(a[d[0].substring(9,d[0].length)]=d[1])}return a};b.typeOf=function(a){var b=typeof a;return"object"===b?!a?"null":a instanceof Array?"array":b:b};b.translateEventResponse=function(a,c){var d=b.extend({},c);a==f.events.JWPLAYER_FULLSCREEN&&!d.fullscreen?(d.fullscreen="true"==d.message?!0:!1,delete d.message):"object"==typeof d.data?(d=b.extend(d,d.data),delete d.data):"object"==typeof d.metadata&&b.deepReplaceKeyName(d.metadata,["__dot__","__spc__","__dsh__","__default__"],
|
||||
["."," ","-","default"]);b.foreach(["position","duration","offset"],function(a,b){d[b]&&(d[b]=Math.round(1E3*d[b])/1E3)});return d};b.flashVersion=function(){if(b.isAndroid())return 0;var a=j.plugins,d;try{if("undefined"!==a&&(d=a["Shockwave Flash"]))return parseInt(d.description.replace(/\D+(\d+)\..*/,"$1"))}catch(c){}if("undefined"!=typeof e.ActiveXObject)try{if(d=new ActiveXObject("ShockwaveFlash.ShockwaveFlash"))return parseInt(d.GetVariable("$version").split(" ")[1].split(",")[0])}catch(f){}return 0};
|
||||
b.getScriptPath=function(a){for(var b=l.getElementsByTagName("script"),d=0;d<b.length;d++){var c=b[d].src;if(c&&0<=c.indexOf(a))return c.substr(0,c.indexOf(a))}return""};b.deepReplaceKeyName=function(a,d,c){switch(f.utils.typeOf(a)){case "array":for(var j=0;j<a.length;j++)a[j]=f.utils.deepReplaceKeyName(a[j],d,c);break;case "object":b.foreach(a,function(b,h){var j;if(d instanceof Array&&c instanceof Array){if(d.length!=c.length)return;j=d}else j=[d];for(var e=b,l=0;l<j.length;l++)e=e.replace(RegExp(d[l],
|
||||
"g"),c[l]);a[e]=f.utils.deepReplaceKeyName(h,d,c);b!=e&&delete a[b]})}return a};var d=b.pluginPathType={ABSOLUTE:0,RELATIVE:1,CDN:2};b.getPluginPathType=function(a){if("string"==typeof a){a=a.split("?")[0];var c=a.indexOf("://");if(0<c)return d.ABSOLUTE;var j=a.indexOf("/");a=b.extension(a);return 0>c&&0>j&&(!a||!isNaN(a))?d.CDN:d.RELATIVE}};b.getPluginName=function(a){return a.replace(/^(.*\/)?([^-]*)-?.*\.(swf|js)$/,"$2")};b.getPluginVersion=function(a){return a.replace(/[^-]*-?([^\.]*).*$/,"$1")};
|
||||
b.isYouTube=function(a){return-1<a.indexOf("youtube.com")||-1<a.indexOf("youtu.be")};b.isRtmp=function(a,b){return 0==a.indexOf("rtmp")||"rtmp"==b};b.foreach=function(a,b){var d,c;for(d in a)a.hasOwnProperty(d)&&(c=a[d],b(d,c))};b.isHTTPS=function(){return 0==e.location.href.indexOf("https")};b.repo=function(){var a=""+f.version.split(/\W/).splice(0,2).join("/")+"/";try{b.isHTTPS()&&(a=a.replace("http://","https://ssl."))}catch(d){}return a}}(jwplayer),function(f){var a="video/",
|
||||
l=f.foreach,e={mp4:a+"mp4",vorbis:"audio/ogg",ogg:a+"ogg",webm:a+"webm",aac:"audio/mp4",mp3:"audio/mpeg",hls:"application/vnd.apple.mpegurl"},j={mp4:e.mp4,f4v:e.mp4,m4v:e.mp4,mov:e.mp4,m4a:e.aac,f4a:e.aac,aac:e.aac,mp3:e.mp3,ogv:e.ogg,ogg:e.vorbis,oga:e.vorbis,webm:e.webm,m3u8:e.hls,hls:e.hls},a="video",a={flv:a,f4v:a,mov:a,m4a:a,m4v:a,mp4:a,aac:a,f4a:a,mp3:"sound",smil:"rtmp",m3u8:"hls",hls:"hls"},b=f.extensionmap={};l(j,function(a,d){b[a]={html5:d}});l(a,function(a,d){b[a]||(b[a]={});b[a].flash=
|
||||
d});b.types=e;b.mimeType=function(a){var b;l(e,function(j,e){!b&&e==a&&(b=j)});return b};b.extType=function(a){return b.mimeType(j[a])}}(jwplayer.utils),function(f){var a=f.loaderstatus={NEW:0,LOADING:1,ERROR:2,COMPLETE:3},l=document;f.scriptloader=function(e){function j(){c=a.ERROR;g.sendEvent(d.ERROR)}function b(){c=a.COMPLETE;g.sendEvent(d.COMPLETE)}var c=a.NEW,d=jwplayer.events,g=new d.eventdispatcher;f.extend(this,g);this.load=function(){var g=f.scriptloader.loaders[e];if(g&&(g.getStatus()==
|
||||
a.NEW||g.getStatus()==a.LOADING))g.addEventListener(d.ERROR,j),g.addEventListener(d.COMPLETE,b);else if(f.scriptloader.loaders[e]=this,c==a.NEW){c=a.LOADING;var m=l.createElement("script");m.addEventListener?(m.onload=b,m.onerror=j):m.readyState&&(m.onreadystatechange=function(){("loaded"==m.readyState||"complete"==m.readyState)&&b()});l.getElementsByTagName("head")[0].appendChild(m);m.src=e}};this.getStatus=function(){return c}};f.scriptloader.loaders={}}(jwplayer.utils),function(f){f.trim=function(a){return a.replace(/^\s*/,
|
||||
"").replace(/\s*$/,"")};f.pad=function(a,f,e){for(e||(e="0");a.length<f;)a=e+a;return a};f.xmlAttribute=function(a,f){for(var e=0;e<a.attributes.length;e++)if(a.attributes[e].name&&a.attributes[e].name.toLowerCase()==f.toLowerCase())return a.attributes[e].value.toString();return""};f.extension=function(a){if(!a||"rtmp"==a.substr(0,4))return"";a=a.substring(a.lastIndexOf("/")+1,a.length).split("?")[0].split("#")[0];if(-1<a.lastIndexOf("."))return a.substr(a.lastIndexOf(".")+1,a.length).toLowerCase()};
|
||||
f.stringToColor=function(a){a=a.replace(/(#|0x)?([0-9A-F]{3,6})$/gi,"$2");3==a.length&&(a=a.charAt(0)+a.charAt(0)+a.charAt(1)+a.charAt(1)+a.charAt(2)+a.charAt(2));return parseInt(a,16)}}(jwplayer.utils),function(f){f.key=function(a){var l,e,j;this.edition=function(){return j&&j.getTime()<(new Date).getTime()?"invalid":l};this.token=function(){return e};f.exists(a)||(a="");try{a=f.tea.decrypt(a,"36QXq4W@GSBV^teR");var b=a.split("/");(l=b[0])||(l="free");e=b[1];b[2]&&0<parseInt(b[2])&&(j=new Date,j.setTime(String(b[2])))}catch(c){l=
|
||||
"invalid"}}}(jwplayer.utils),function(f){var a=f.tea={};a.encrypt=function(j,b){if(0==j.length)return"";var c=a.strToLongs(e.encode(j));1>=c.length&&(c[1]=0);for(var d=a.strToLongs(e.encode(b).slice(0,16)),g=c.length,f=c[g-1],m=c[0],n,k=Math.floor(6+52/g),h=0;0<k--;){h+=2654435769;n=h>>>2&3;for(var r=0;r<g;r++)m=c[(r+1)%g],f=(f>>>5^m<<2)+(m>>>3^f<<4)^(h^m)+(d[r&3^n]^f),f=c[r]+=f}c=a.longsToStr(c);return l.encode(c)};a.decrypt=function(j,b){if(0==j.length)return"";for(var c=a.strToLongs(l.decode(j)),
|
||||
d=a.strToLongs(e.encode(b).slice(0,16)),g=c.length,f=c[g-1],m=c[0],n,k=2654435769*Math.floor(6+52/g);0!=k;){n=k>>>2&3;for(var h=g-1;0<=h;h--)f=c[0<h?h-1:g-1],f=(f>>>5^m<<2)+(m>>>3^f<<4)^(k^m)+(d[h&3^n]^f),m=c[h]-=f;k-=2654435769}c=a.longsToStr(c);c=c.replace(/\0+$/,"");return e.decode(c)};a.strToLongs=function(a){for(var b=Array(Math.ceil(a.length/4)),c=0;c<b.length;c++)b[c]=a.charCodeAt(4*c)+(a.charCodeAt(4*c+1)<<8)+(a.charCodeAt(4*c+2)<<16)+(a.charCodeAt(4*c+3)<<24);return b};a.longsToStr=function(a){for(var b=
|
||||
Array(a.length),c=0;c<a.length;c++)b[c]=String.fromCharCode(a[c]&255,a[c]>>>8&255,a[c]>>>16&255,a[c]>>>24&255);return b.join("")};var l={code:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\x3d",encode:function(a,b){var c,d,g,f,m=[],n="",k,h,r=l.code;h=("undefined"==typeof b?0:b)?e.encode(a):a;k=h.length%3;if(0<k)for(;3>k++;)n+="\x3d",h+="\x00";for(k=0;k<h.length;k+=3)c=h.charCodeAt(k),d=h.charCodeAt(k+1),g=h.charCodeAt(k+2),f=c<<16|d<<8|g,c=f>>18&63,d=f>>12&63,g=f>>6&63,f&=63,m[k/
|
||||
3]=r.charAt(c)+r.charAt(d)+r.charAt(g)+r.charAt(f);m=m.join("");return m=m.slice(0,m.length-n.length)+n},decode:function(a,b){b="undefined"==typeof b?!1:b;var c,d,g,f,m,n=[],k,h=l.code;k=b?e.decode(a):a;for(var r=0;r<k.length;r+=4)c=h.indexOf(k.charAt(r)),d=h.indexOf(k.charAt(r+1)),f=h.indexOf(k.charAt(r+2)),m=h.indexOf(k.charAt(r+3)),g=c<<18|d<<12|f<<6|m,c=g>>>16&255,d=g>>>8&255,g&=255,n[r/4]=String.fromCharCode(c,d,g),64==m&&(n[r/4]=String.fromCharCode(c,d)),64==f&&(n[r/4]=String.fromCharCode(c));
|
||||
f=n.join("");return b?e.decode(f):f}},e={encode:function(a){a=a.replace(/[\u0080-\u07ff]/g,function(a){a=a.charCodeAt(0);return String.fromCharCode(192|a>>6,128|a&63)});return a=a.replace(/[\u0800-\uffff]/g,function(a){a=a.charCodeAt(0);return String.fromCharCode(224|a>>12,128|a>>6&63,128|a&63)})},decode:function(a){a=a.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g,function(a){a=(a.charCodeAt(0)&15)<<12|(a.charCodeAt(1)&63)<<6|a.charCodeAt(2)&63;return String.fromCharCode(a)});return a=
|
||||
a.replace(/[\u00c0-\u00df][\u0080-\u00bf]/g,function(a){a=(a.charCodeAt(0)&31)<<6|a.charCodeAt(1)&63;return String.fromCharCode(a)})}}}(jwplayer.utils),function(f){f.events={COMPLETE:"COMPLETE",ERROR:"ERROR",API_READY:"jwplayerAPIReady",JWPLAYER_READY:"jwplayerReady",JWPLAYER_FULLSCREEN:"jwplayerFullscreen",JWPLAYER_RESIZE:"jwplayerResize",JWPLAYER_ERROR:"jwplayerError",JWPLAYER_MEDIA_BEFOREPLAY:"jwplayerMediaBeforePlay",JWPLAYER_MEDIA_BEFORECOMPLETE:"jwplayerMediaBeforeComplete",JWPLAYER_COMPONENT_SHOW:"jwplayerComponentShow",
|
||||
JWPLAYER_COMPONENT_HIDE:"jwplayerComponentHide",JWPLAYER_MEDIA_BUFFER:"jwplayerMediaBuffer",JWPLAYER_MEDIA_BUFFER_FULL:"jwplayerMediaBufferFull",JWPLAYER_MEDIA_ERROR:"jwplayerMediaError",JWPLAYER_MEDIA_LOADED:"jwplayerMediaLoaded",JWPLAYER_MEDIA_COMPLETE:"jwplayerMediaComplete",JWPLAYER_MEDIA_SEEK:"jwplayerMediaSeek",JWPLAYER_MEDIA_TIME:"jwplayerMediaTime",JWPLAYER_MEDIA_VOLUME:"jwplayerMediaVolume",JWPLAYER_MEDIA_META:"jwplayerMediaMeta",JWPLAYER_MEDIA_MUTE:"jwplayerMediaMute",JWPLAYER_MEDIA_LEVELS:"jwplayerMediaLevels",
|
||||
JWPLAYER_MEDIA_LEVEL_CHANGED:"jwplayerMediaLevelChanged",JWPLAYER_CAPTIONS_CHANGED:"jwplayerCaptionsChanged",JWPLAYER_CAPTIONS_LIST:"jwplayerCaptionsList",JWPLAYER_PLAYER_STATE:"jwplayerPlayerState",state:{BUFFERING:"BUFFERING",IDLE:"IDLE",PAUSED:"PAUSED",PLAYING:"PLAYING"},JWPLAYER_PLAYLIST_LOADED:"jwplayerPlaylistLoaded",JWPLAYER_PLAYLIST_ITEM:"jwplayerPlaylistItem",JWPLAYER_PLAYLIST_COMPLETE:"jwplayerPlaylistComplete",JWPLAYER_DISPLAY_CLICK:"jwplayerViewClick",JWPLAYER_CONTROLS:"jwplayerViewControls",
|
||||
JWPLAYER_INSTREAM_CLICK:"jwplayerInstreamClicked",JWPLAYER_INSTREAM_DESTROYED:"jwplayerInstreamDestroyed"}}(jwplayer),function(f){var a=jwplayer.utils;f.eventdispatcher=function(f,e){var j,b;this.resetEventListeners=function(){j={};b=[]};this.resetEventListeners();this.addEventListener=function(b,d,g){try{a.exists(j[b])||(j[b]=[]),"string"==a.typeOf(d)&&(d=(new Function("return "+d))()),j[b].push({listener:d,count:g})}catch(e){a.log("error",e)}return!1};this.removeEventListener=function(b,d){if(j[b]){try{for(var g=
|
||||
0;g<j[b].length;g++)if(j[b][g].listener.toString()==d.toString()){j[b].splice(g,1);break}}catch(e){a.log("error",e)}return!1}};this.addGlobalListener=function(c,d){try{"string"==a.typeOf(c)&&(c=(new Function("return "+c))()),b.push({listener:c,count:d})}catch(g){a.log("error",g)}return!1};this.removeGlobalListener=function(c){if(c){try{for(var d=0;d<b.length;d++)if(b[d].listener.toString()==c.toString()){b.splice(d,1);break}}catch(g){a.log("error",g)}return!1}};this.sendEvent=function(c,d){a.exists(d)||
|
||||
(d={});a.extend(d,{id:f,version:jwplayer.version,type:c});e&&a.log(c,d);if("undefined"!=a.typeOf(j[c]))for(var g=0;g<j[c].length;g++){try{j[c][g].listener(d)}catch(q){a.log("There was an error while handling a listener: "+q.toString(),j[c][g].listener)}j[c][g]&&(1===j[c][g].count?delete j[c][g]:0<j[c][g].count&&(j[c][g].count-=1))}for(g=0;g<b.length;g++){try{b[g].listener(d)}catch(m){a.log("There was an error while handling a listener: "+m.toString(),b[g].listener)}b[g]&&(1===b[g].count?delete b[g]:
|
||||
0<b[g].count&&(b[g].count-=1))}}}}(jwplayer.events),function(f){var a={},l={};f.plugins=function(){};f.plugins.loadPlugins=function(e,j){l[e]=new f.plugins.pluginloader(new f.plugins.model(a),j);return l[e]};f.plugins.registerPlugin=function(e,j,b,c){var d=f.utils.getPluginName(e);a[d]||(a[d]=new f.plugins.plugin(e));a[d].registerPlugin(e,j,b,c)}}(jwplayer),function(f){f.plugins.model=function(a){this.addPlugin=function(l){var e=f.utils.getPluginName(l);a[e]||(a[e]=new f.plugins.plugin(l));return a[e]};
|
||||
this.getPlugins=function(){return a}}}(jwplayer),function(f){var a=jwplayer.utils,l=jwplayer.events;f.pluginmodes={FLASH:0,JAVASCRIPT:1,HYBRID:2};f.plugin=function(e){function j(){switch(a.getPluginPathType(e)){case a.pluginPathType.ABSOLUTE:return e;case a.pluginPathType.RELATIVE:return a.getAbsolutePath(e,window.location.href)}}function b(){n=setTimeout(function(){d=a.loaderstatus.COMPLETE;k.sendEvent(l.COMPLETE)},1E3)}function c(){d=a.loaderstatus.ERROR;k.sendEvent(l.ERROR)}var d=a.loaderstatus.NEW,
|
||||
g,q,m,n,k=new l.eventdispatcher;a.extend(this,k);this.load=function(){if(d==a.loaderstatus.NEW)if(0<e.lastIndexOf(".swf"))g=e,d=a.loaderstatus.COMPLETE,k.sendEvent(l.COMPLETE);else if(a.getPluginPathType(e)==a.pluginPathType.CDN)d=a.loaderstatus.COMPLETE,k.sendEvent(l.COMPLETE);else{d=a.loaderstatus.LOADING;var h=new a.scriptloader(j());h.addEventListener(l.COMPLETE,b);h.addEventListener(l.ERROR,c);h.load()}};this.registerPlugin=function(b,c,e,j){n&&(clearTimeout(n),n=void 0);m=c;e&&j?(g=j,q=e):"string"==
|
||||
typeof e?g=e:"function"==typeof e?q=e:!e&&!j&&(g=b);d=a.loaderstatus.COMPLETE;k.sendEvent(l.COMPLETE)};this.getStatus=function(){return d};this.getPluginName=function(){return a.getPluginName(e)};this.getFlashPath=function(){if(g)switch(a.getPluginPathType(g)){case a.pluginPathType.ABSOLUTE:return g;case a.pluginPathType.RELATIVE:return 0<e.lastIndexOf(".swf")?a.getAbsolutePath(g,window.location.href):a.getAbsolutePath(g,j())}return null};this.getJS=function(){return q};this.getTarget=function(){return m};
|
||||
this.getPluginmode=function(){if("undefined"!=typeof g&&"undefined"!=typeof q)return f.pluginmodes.HYBRID;if("undefined"!=typeof g)return f.pluginmodes.FLASH;if("undefined"!=typeof q)return f.pluginmodes.JAVASCRIPT};this.getNewInstance=function(a,b,d){return new q(a,b,d)};this.getURL=function(){return e}}}(jwplayer.plugins),function(f){var a=f.utils,l=f.events,e=a.foreach;f.plugins.pluginloader=function(j,b){function c(){m?h.sendEvent(l.ERROR,{message:n}):q||(q=!0,g=a.loaderstatus.COMPLETE,h.sendEvent(l.COMPLETE))}
|
||||
function d(){k||c();if(!q&&!m){var b=0,d=j.getPlugins();a.foreach(k,function(g){g=a.getPluginName(g);var e=d[g];g=e.getJS();var h=e.getTarget(),e=e.getStatus();if(e==a.loaderstatus.LOADING||e==a.loaderstatus.NEW)b++;else if(g&&(!h||parseFloat(h)>parseFloat(f.version)))m=!0,n="Incompatible player version",c()});0==b&&c()}}var g=a.loaderstatus.NEW,q=!1,m=!1,n,k=b,h=new l.eventdispatcher;a.extend(this,h);this.setupPlugins=function(b,d,c){var g={length:0,plugins:{}},h=0,f={},r=j.getPlugins();e(d.plugins,
|
||||
function(e,j){var k=a.getPluginName(e),l=r[k],m=l.getFlashPath(),n=l.getJS(),q=l.getURL();m&&(g.plugins[m]=a.extend({},j),g.plugins[m].pluginmode=l.getPluginmode(),g.length++);try{if(n&&d.plugins&&d.plugins[q]){var v=document.createElement("div");v.id=b.id+"_"+k;v.style.position="absolute";v.style.top=0;v.style.zIndex=h+10;f[k]=l.getNewInstance(b,a.extend({},d.plugins[q]),v);h++;b.onReady(c(f[k],v,!0));b.onResize(c(f[k],v))}}catch(B){a.log("ERROR: Failed to load "+k+".")}});b.plugins=f;return g};
|
||||
this.load=function(){if(!(a.exists(b)&&"object"!=a.typeOf(b))){g=a.loaderstatus.LOADING;e(b,function(b){a.exists(b)&&(b=j.addPlugin(b),b.addEventListener(l.COMPLETE,d),b.addEventListener(l.ERROR,r))});var c=j.getPlugins();e(c,function(a,b){b.load()})}d()};var r=this.pluginFailed=function(){m||(m=!0,n="File not found",c())};this.getStatus=function(){return g}}}(jwplayer),function(f){f.playlist=function(a){var l=[];if("array"==f.utils.typeOf(a))for(var e=0;e<a.length;e++)l.push(new f.playlist.item(a[e]));
|
||||
else l.push(new f.playlist.item(a));return l}}(jwplayer),function(f){var a=f.item=function(l){var e=jwplayer.utils,j=e.extend({},a.defaults,l);j.tracks=e.exists(l.tracks)?l.tracks:[];0==j.sources.length&&(j.sources=[new f.source(j)]);for(var b=0;b<j.sources.length;b++){var c=j.sources[b]["default"];j.sources[b]["default"]=c?"true"==c.toString():!1;j.sources[b]=new f.source(j.sources[b])}if(j.captions&&!e.exists(l.tracks)){for(l=0;l<j.captions.length;l++)j.tracks.push(j.captions[l]);delete j.captions}for(b=
|
||||
0;b<j.tracks.length;b++)j.tracks[b]=new f.track(j.tracks[b]);return j};a.defaults={description:"",image:"",mediaid:"",title:"",sources:[],tracks:[]}}(jwplayer.playlist),function(f){var a=jwplayer.utils,l={file:void 0,label:void 0,type:void 0,"default":void 0};f.source=function(e){var j=a.extend({},l);a.foreach(l,function(b){a.exists(e[b])&&(j[b]=e[b],delete e[b])});j.type&&0<j.type.indexOf("/")&&(j.type=a.extensionmap.mimeType(j.type));"m3u8"==j.type&&(j.type="hls");"smil"==j.type&&(j.type="rtmp");
|
||||
return j}}(jwplayer.playlist),function(f){var a=jwplayer.utils,l={file:void 0,label:void 0,kind:"captions","default":!1};f.track=function(e){var j=a.extend({},l);e||(e={});a.foreach(l,function(b){a.exists(e[b])&&(j[b]=e[b],delete e[b])});return j}}(jwplayer.playlist),function(f){var a=f.utils,l=f.events,e=document,j=f.embed=function(b){function c(b,d){a.foreach(d,function(a,d){"function"==typeof b[a]&&b[a].call(b,d)})}function d(a){q(n,t+a.message)}function g(){q(n,t+"No playable sources found")}
|
||||
function q(b,d){if(m.fallback){var c=b.style;c.backgroundColor="#000";c.color="#FFF";c.width=a.styleDimension(m.width);c.height=a.styleDimension(m.height);c.display="table";c.opacity=1;var c=document.createElement("p"),g=c.style;g.verticalAlign="middle";g.textAlign="center";g.display="table-cell";g.font="15px/20px Arial, Helvetica, sans-serif";c.innerHTML=d.replace(":",":\x3cbr\x3e");b.innerHTML="";b.appendChild(c)}}var m=new j.config(b.config),n,k,h,r=m.width,p=m.height,t="Error loading player: ",
|
||||
s=f.plugins.loadPlugins(b.id,m.plugins);m.fallbackDiv&&(h=m.fallbackDiv,delete m.fallbackDiv);m.id=b.id;k=e.getElementById(b.id);m.aspectratio?b.config.aspectratio=m.aspectratio:delete b.config.aspectratio;n=e.createElement("div");n.id=k.id;n.style.width=0<r.toString().indexOf("%")?r:r+"px";n.style.height=0<p.toString().indexOf("%")?p:p+"px";k.parentNode.replaceChild(n,k);f.embed.errorScreen=q;s.addEventListener(l.COMPLETE,function(){if("array"==a.typeOf(m.playlist)&&2>m.playlist.length&&(0==m.playlist.length||
|
||||
!m.playlist[0].sources||0==m.playlist[0].sources.length))g();else if(s.getStatus()==a.loaderstatus.COMPLETE){for(var e=0;e<m.modes.length;e++)if(m.modes[e].type&&j[m.modes[e].type]){var f=a.extend({},m),r=new j[m.modes[e].type](n,m.modes[e],f,s,b);if(r.supportsConfig())return r.addEventListener(l.ERROR,d),r.embed(),c(b,f.events),b}m.fallback?(a.log("No suitable players found and fallback enabled"),new j.download(n,m,g)):(a.log("No suitable players found and fallback disabled"),n.parentNode.replaceChild(h,
|
||||
n))}});s.addEventListener(l.ERROR,function(a){q(n,"Could not load plugins: "+a.message)});s.load();return b}}(jwplayer),function(f){function a(a){if(a.playlist)for(var c=0;c<a.playlist.length;c++)a.playlist[c]=new j(a.playlist[c]);else{var d={};e.foreach(j.defaults,function(c){l(a,d,c)});d.sources||(a.levels?(d.sources=a.levels,delete a.levels):(c={},l(a,c,"file"),l(a,c,"type"),d.sources=c.file?[c]:[]));a.playlist=[new j(d)]}}function l(a,c,d){e.exists(a[d])&&(c[d]=a[d],delete a[d])}var e=f.utils,
|
||||
j=f.playlist.item;(f.embed.config=function(b){var c={fallback:!0,height:270,primary:"html5",width:480,base:b.base?b.base:e.getScriptPath("jwplayer.js"),aspectratio:""};b=e.extend(c,f.defaults,b);var c={type:"html5",src:b.base+"jwplayer.html5.js"},d={type:"flash",src:b.base+"jwplayer.flash.swf"};b.modes="flash"==b.primary?[d,c]:[c,d];b.listbar&&(b.playlistsize=b.listbar.size,b.playlistposition=b.listbar.position);b.flashplayer&&(d.src=b.flashplayer);b.html5player&&(c.src=b.html5player);a(b);d=b.aspectratio;
|
||||
if("string"!=typeof d||!e.exists(d))c=0;else{var g=d.indexOf(":");-1==g?c=0:(c=parseFloat(d.substr(0,g)),d=parseFloat(d.substr(g+1)),c=0>=c||0>=d?0:100*(d/c)+"%")}-1==b.width.toString().indexOf("%")?delete b.aspectratio:c?b.aspectratio=c:delete b.aspectratio;return b}).addConfig=function(b,c){a(c);return e.extend(b,c)}}(jwplayer),function(f){var a=f.utils,l=document;f.embed.download=function(e,f,b){function c(b,d){for(var c=l.querySelectorAll(b),g=0;g<c.length;g++)a.foreach(d,function(a,b){c[g].style[a]=
|
||||
b})}function d(a,b,d){a=l.createElement(a);b&&(a.className="jwdownload"+b);d&&d.appendChild(a);return a}var g=a.extend({},f),q=g.width?g.width:480,m=g.height?g.height:320,n;f=f.logo?f.logo:{prefix:a.repo(),file:"logo.png",margin:10};var k,h,r,g=g.playlist,p,t=["mp4","aac","mp3"];if(g&&g.length){p=g[0];n=p.sources;for(g=0;g<n.length;g++){var s=n[g],u=s.type?s.type:a.extensionmap.extType(a.extension(s.file));s.file&&a.foreach(t,function(b){u==t[b]?(k=s.file,h=p.image):a.isYouTube(s.file)&&(r=s.file)})}k?
|
||||
(n=k,b=h,e&&(g=d("a","display",e),d("div","icon",g),d("div","logo",g),n&&g.setAttribute("href",a.getAbsolutePath(n))),g="#"+e.id+" .jwdownload",e.style.width="",e.style.height="",c(g+"display",{width:a.styleDimension(Math.max(320,q)),height:a.styleDimension(Math.max(180,m)),background:"black center no-repeat "+(b?"url("+b+")":""),backgroundSize:"contain",position:"relative",border:"none",display:"block"}),c(g+"display div",{position:"absolute",width:"100%",height:"100%"}),c(g+"logo",{top:f.margin+
|
||||
"px",right:f.margin+"px",background:"top right no-repeat url("+f.prefix+f.file+")"}),c(g+"icon",{background:"center no-repeat url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAgNJREFUeNrs28lqwkAYB/CZqNVDDj2r6FN41QeIy8Fe+gj6BL275Q08u9FbT8ZdwVfotSBYEPUkxFOoks4EKiJdaDuTjMn3wWBO0V/+sySR8SNSqVRKIR8qaXHkzlqS9jCfzzWcTCYp9hF5o+59sVjsiRzcegSckFzcjT+ruN80TeSlAjCAAXzdJSGPFXRpAAMYwACGZQkSdhG4WCzehMNhqV6vG6vVSrirKVEw66YoSqDb7cqlUilE8JjHd/y1MQefVzqdDmiaJpfLZWHgXMHn8F6vJ1cqlVAkEsGuAn83J4gAd2RZymQygX6/L1erVQt+9ZPWb+CDwcCC2zXGJaewl/DhcHhK3DVj+KfKZrMWvFarcYNLomAv4aPRSFZVlTlcSPA5fDweW/BoNIqFnKV53JvncjkLns/n/cLdS+92O7RYLLgsKfv9/t8XlDn4eDyiw+HA9Jyz2eyt0+kY2+3WFC5hluej0Ha7zQQq9PPwdDq1Et1sNsx/nFBgCqWJ8oAK1aUptNVqcYWewE4nahfU0YQnk4ntUEfGMIU2m01HoLaCKbTRaDgKtaVLk9tBYaBcE/6Artdr4RZ5TB6/dC+9iIe/WgAMYADDpAUJAxjAAAYwgGFZgoS/AtNNTF7Z2bL0BYPBV3Jw5xFwwWcYxgtBP5OkE8i9G7aWGOOCruvauwADALMLMEbKf4SdAAAAAElFTkSuQmCC)"})):
|
||||
r?(f=r,e=d("embed","",e),e.src="http://www.youtube.com/v/"+/v[=\/](\w*)|\/(\w+)$|^(\w+)$/i.exec(f).slice(1).join(""),e.type="application/x-shockwave-flash",e.width=q,e.height=m):b()}}}(jwplayer),function(f){var a=f.utils,l=f.events,e={};(f.embed.flash=function(j,b,c,d,g){function q(a,b,d){var c=document.createElement("param");c.setAttribute("name",b);c.setAttribute("value",d);a.appendChild(c)}function m(a,b,d){return function(){try{d&&document.getElementById(g.id+"_wrapper").appendChild(b);var c=
|
||||
document.getElementById(g.id).getPluginConfig("display");"function"==typeof a.resize&&a.resize(c.width,c.height);b.style.left=c.x;b.style.top=c.h}catch(e){}}}function n(b){if(!b)return{};var d={},c=[];a.foreach(b,function(b,g){var e=a.getPluginName(b);c.push(b);a.foreach(g,function(a,b){d[e+"."+a]=b})});d.plugins=c.join(",");return d}var k=new f.events.eventdispatcher,h=a.flashVersion();a.extend(this,k);this.embed=function(){c.id=g.id;if(10>h)return k.sendEvent(l.ERROR,{message:"Flash version must be 10.0 or greater"}),
|
||||
!1;var f,p,t=g.config.listbar,s=a.extend({},c);if(j.id+"_wrapper"==j.parentNode.id)f=document.getElementById(j.id+"_wrapper");else{f=document.createElement("div");p=document.createElement("div");p.style.display="none";p.id=j.id+"_aspect";f.id=j.id+"_wrapper";f.style.position="relative";f.style.display="block";f.style.width=a.styleDimension(s.width);f.style.height=a.styleDimension(s.height);if(g.config.aspectratio){var u=parseFloat(g.config.aspectratio);p.style.display="block";p.style.marginTop=g.config.aspectratio;
|
||||
f.style.height="auto";f.style.display="inline-block";t&&("bottom"==t.position?p.style.paddingBottom=t.size+"px":"right"==t.position&&(p.style.marginBottom=-1*t.size*(u/100)+"px"))}j.parentNode.replaceChild(f,j);f.appendChild(j);f.appendChild(p)}f=d.setupPlugins(g,s,m);0<f.length?a.extend(s,n(f.plugins)):delete s.plugins;"undefined"!=typeof s["dock.position"]&&"false"==s["dock.position"].toString().toLowerCase()&&(s.dock=s["dock.position"],delete s["dock.position"]);f=s.wmode?s.wmode:s.height&&40>=
|
||||
s.height?"transparent":"opaque";p="height width modes events primary base fallback volume".split(" ");for(t=0;t<p.length;t++)delete s[p[t]];p=a.getCookies();a.foreach(p,function(a,b){"undefined"==typeof s[a]&&(s[a]=b)});p=window.location.href.split("/");p.splice(p.length-1,1);p=p.join("/");s.base=p+"/";e[j.id]=s;a.isIE()?(p='\x3cobject classid\x3d"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" " width\x3d"100%" height\x3d"100%"id\x3d"'+j.id+'" name\x3d"'+j.id+'" tabindex\x3d0""\x3e',p+='\x3cparam name\x3d"movie" value\x3d"'+
|
||||
b.src+'"\x3e',p+='\x3cparam name\x3d"allowfullscreen" value\x3d"true"\x3e\x3cparam name\x3d"allowscriptaccess" value\x3d"always"\x3e',p+='\x3cparam name\x3d"seamlesstabbing" value\x3d"true"\x3e',p+='\x3cparam name\x3d"wmode" value\x3d"'+f+'"\x3e',p+='\x3cparam name\x3d"bgcolor" value\x3d"#000000"\x3e',p+="\x3c/object\x3e",j.outerHTML=p,f=document.getElementById(j.id)):(p=document.createElement("object"),p.setAttribute("type","application/x-shockwave-flash"),p.setAttribute("data",b.src),p.setAttribute("width",
|
||||
"100%"),p.setAttribute("height","100%"),p.setAttribute("bgcolor","#000000"),p.setAttribute("id",j.id),p.setAttribute("name",j.id),p.setAttribute("tabindex",0),q(p,"allowfullscreen","true"),q(p,"allowscriptaccess","always"),q(p,"seamlesstabbing","true"),q(p,"wmode",f),j.parentNode.replaceChild(p,j),f=p);g.config.aspectratio&&(f.style.position="absolute");g.container=f;g.setPlayer(f,"flash")};this.supportsConfig=function(){if(h)if(c){if("string"==a.typeOf(c.playlist))return!0;try{var b=c.playlist[0].sources;
|
||||
if("undefined"==typeof b)return!0;for(var d=0;d<b.length;d++){var g;if(g=b[d].file){var e=b[d].file,f=b[d].type;if(a.isYouTube(e)||a.isRtmp(e,f)||"hls"==f)g=!0;else{var j=a.extensionmap[f?f:a.extension(e)];g=!j?!1:!!j.flash}}if(g)return!0}}catch(k){}}else return!0;return!1}}).getVars=function(a){return e[a]}}(jwplayer),function(f){var a=f.utils,l=a.extensionmap,e=f.events;f.embed.html5=function(j,b,c,d,g){function q(a,b,d){return function(){try{var c=document.querySelector("#"+j.id+" .jwmain");d&&
|
||||
c.appendChild(b);"function"==typeof a.resize&&(a.resize(c.clientWidth,c.clientHeight),setTimeout(function(){a.resize(c.clientWidth,c.clientHeight)},400));b.left=c.style.left;b.top=c.style.top}catch(g){}}}function m(a){n.sendEvent(a.type,{message:"HTML5 player not found"})}var n=this,k=new e.eventdispatcher;a.extend(n,k);n.embed=function(){if(f.html5){d.setupPlugins(g,c,q);j.innerHTML="";var h=f.utils.extend({},c);delete h.volume;h=new f.html5.player(h);g.container=document.getElementById(g.id);g.setPlayer(h,
|
||||
"html5")}else h=new a.scriptloader(b.src),h.addEventListener(e.ERROR,m),h.addEventListener(e.COMPLETE,n.embed),h.load()};n.supportsConfig=function(){if(f.vid.canPlayType)try{if("string"==a.typeOf(c.playlist))return!0;for(var b=c.playlist[0].sources,d=0;d<b.length;d++){var g;var e=b[d].file,j=b[d].type;if(null!==navigator.userAgent.match(/BlackBerry/i)||a.isAndroid()&&("m3u"==a.extension(e)||"m3u8"==a.extension(e))||a.isRtmp(e,j))g=!1;else{var k=l[j?j:a.extension(e)],m;if(!k||k.flash&&!k.html5)m=!1;
|
||||
else{var n=k.html5,q=f.vid;if(n)try{m=q.canPlayType(n)?!0:!1}catch(z){m=!1}else m=!0}g=m}if(g)return!0}}catch(A){}return!1}}}(jwplayer),function(f){var a=f.embed,l=f.utils,e=l.extend(function(e){var b=l.repo(),c=l.extend({},f.defaults),d=l.extend({},c,e.config),g=e.config,q=d.plugins,m=d.analytics,n=b+"jwpsrv.js",k=b+"sharing.js",h=b+"related.js",r=b+"gapro.js",c=f.key?f.key:c.key,p="premium"/*(new f.utils.key(c)).edition()*/,q=q?q:{}; /*alert(c);*/ "ads"==p&&d.advertising&&(d.advertising.client.match(".js$|.swf$")?q[d.advertising.client]=
|
||||
d.advertising:q[b+d.advertising.client+".js"]=d.advertising);delete g.advertising;g.key=c;d.analytics&&(d.analytics.client&&d.analytics.client.match(".js$|.swf$"))&&(n=d.analytics.client);delete g.analytics;if("free"==p||!m||!1!==m.enabled)q[n]=m?m:{};delete q.sharing;delete q.related;if("premium"==p||"ads"==p)d.sharing&&(d.sharing.client&&d.sharing.client.match(".js$|.swf$")&&(k=d.sharing.client),q[k]=d.sharing),d.related&&(d.related.client&&d.related.client.match(".js$|.swf$")&&(h=d.related.client),
|
||||
q[h]=d.related),d.ga&&(d.ga.client&&d.ga.client.match(".js$|.swf$")&&(r=d.ga.client),q[r]=d.ga),d.skin&&(g.skin=d.skin.replace(/^(beelden|bekle|five|glow|modieus|roundster|stormtrooper|vapor)$/i,l.repo()+"skins/$1.xml"));g.plugins=q;return new a(e)},a);f.embed=e}(jwplayer),function(f){var a=[],l=f.utils,e=f.events,j=e.state,b=document,c=f.api=function(a){function g(a,b){return function(d){return b(a,d)}}function q(a,b){p[a]||(p[a]=[],n(e.JWPLAYER_PLAYER_STATE,function(b){var d=b.newstate;b=b.oldstate;
|
||||
if(d==a){var c=p[d];if(c)for(var g=0;g<c.length;g++)"function"==typeof c[g]&&c[g].call(this,{oldstate:b,newstate:d})}}));p[a].push(b);return h}function m(a,b){try{a.jwAddEventListener(b,'function(dat) { jwplayer("'+h.id+'").dispatchEvent("'+b+'", dat); }')}catch(d){l.log("Could not add internal listener")}}function n(a,b){r[a]||(r[a]=[],t&&s&&m(t,a));r[a].push(b);return h}function k(){if(s){for(var a=arguments[0],b=[],d=1;d<arguments.length;d++)b.push(arguments[d]);if("undefined"!=typeof t&&"function"==
|
||||
typeof t[a])switch(b.length){case 4:return t[a](b[0],b[1],b[2],b[3]);case 3:return t[a](b[0],b[1],b[2]);case 2:return t[a](b[0],b[1]);case 1:return t[a](b[0]);default:return t[a]()}return null}u.push(arguments)}var h=this,r={},p={},t=void 0,s=!1,u=[],w=void 0,x={},y={};h.container=a;h.id=a.id;h.getBuffer=function(){return k("jwGetBuffer")};h.getContainer=function(){return h.container};h.addButton=function(a,b,d,c){try{y[c]=d,k("jwDockAddButton",a,b,"jwplayer('"+h.id+"').callback('"+c+"')",c)}catch(g){l.log("Could not add dock button"+
|
||||
g.message)}};h.removeButton=function(a){k("jwDockRemoveButton",a)};h.callback=function(a){if(y[a])y[a]()};h.forceState=function(a){k("jwForceState",a);return h};h.releaseState=function(){return k("jwReleaseState")};h.getDuration=function(){return k("jwGetDuration")};h.getFullscreen=function(){return k("jwGetFullscreen")};h.getStretching=function(){return k("jwGetStretching")};h.getHeight=function(){return k("jwGetHeight")};h.getLockState=function(){return k("jwGetLockState")};h.getMeta=function(){return h.getItemMeta()};
|
||||
h.getMute=function(){return k("jwGetMute")};h.getPlaylist=function(){var a=k("jwGetPlaylist");"flash"==h.renderingMode&&l.deepReplaceKeyName(a,["__dot__","__spc__","__dsh__","__default__"],["."," ","-","default"]);return a};h.getPlaylistItem=function(a){l.exists(a)||(a=h.getCurrentItem());return h.getPlaylist()[a]};h.getPosition=function(){return k("jwGetPosition")};h.getRenderingMode=function(){return h.renderingMode};h.getState=function(){return k("jwGetState")};h.getVolume=function(){return k("jwGetVolume")};
|
||||
h.getWidth=function(){return k("jwGetWidth")};h.setFullscreen=function(a){l.exists(a)?k("jwSetFullscreen",a):k("jwSetFullscreen",!k("jwGetFullscreen"));return h};h.setStretching=function(a){k("jwSetStretching",a);return h};h.setMute=function(a){l.exists(a)?k("jwSetMute",a):k("jwSetMute",!k("jwGetMute"));return h};h.lock=function(){return h};h.unlock=function(){return h};h.load=function(a){k("jwLoad",a);return h};h.playlistItem=function(a){k("jwPlaylistItem",parseInt(a));return h};h.playlistPrev=function(){k("jwPlaylistPrev");
|
||||
return h};h.playlistNext=function(){k("jwPlaylistNext");return h};h.resize=function(a,d){if("flash"!=h.renderingMode){var c=document.getElementById(h.id);c.className=c.className.replace(/\s+aspectMode/,"");c.style.display="block";k("jwResize",a,d)}else{var c=b.getElementById(h.id+"_wrapper"),g=b.getElementById(h.id+"_aspect");g&&(g.style.display="none");c&&(c.style.display="block",c.style.width=l.styleDimension(a),c.style.height=l.styleDimension(d))}return h};h.play=function(a){"undefined"==typeof a?
|
||||
(a=h.getState(),a==j.PLAYING||a==j.BUFFERING?k("jwPause"):k("jwPlay")):k("jwPlay",a);return h};h.pause=function(a){"undefined"==typeof a?(a=h.getState(),a==j.PLAYING||a==j.BUFFERING?k("jwPause"):k("jwPlay")):k("jwPause",a);return h};h.stop=function(){k("jwStop");return h};h.seek=function(a){k("jwSeek",a);return h};h.setVolume=function(a){k("jwSetVolume",a);return h};h.loadInstream=function(a,b){return w=new c.instream(this,t,a,b)};h.getQualityLevels=function(){return k("jwGetQualityLevels")};h.getCurrentQuality=
|
||||
function(){return k("jwGetCurrentQuality")};h.setCurrentQuality=function(a){k("jwSetCurrentQuality",a)};h.getCaptionsList=function(){return k("jwGetCaptionsList")};h.getCurrentCaptions=function(){return k("jwGetCurrentCaptions")};h.setCurrentCaptions=function(a){k("jwSetCurrentCaptions",a)};h.getControls=function(){return k("jwGetControls")};h.getSafeRegion=function(){return k("jwGetSafeRegion")};h.setControls=function(a){k("jwSetControls",a)};h.destroyPlayer=function(){k("jwPlayerDestroy")};var z=
|
||||
{onBufferChange:e.JWPLAYER_MEDIA_BUFFER,onBufferFull:e.JWPLAYER_MEDIA_BUFFER_FULL,onError:e.JWPLAYER_ERROR,onFullscreen:e.JWPLAYER_FULLSCREEN,onMeta:e.JWPLAYER_MEDIA_META,onMute:e.JWPLAYER_MEDIA_MUTE,onPlaylist:e.JWPLAYER_PLAYLIST_LOADED,onPlaylistItem:e.JWPLAYER_PLAYLIST_ITEM,onPlaylistComplete:e.JWPLAYER_PLAYLIST_COMPLETE,onReady:e.API_READY,onResize:e.JWPLAYER_RESIZE,onComplete:e.JWPLAYER_MEDIA_COMPLETE,onSeek:e.JWPLAYER_MEDIA_SEEK,onTime:e.JWPLAYER_MEDIA_TIME,onVolume:e.JWPLAYER_MEDIA_VOLUME,
|
||||
onBeforePlay:e.JWPLAYER_MEDIA_BEFOREPLAY,onBeforeComplete:e.JWPLAYER_MEDIA_BEFORECOMPLETE,onDisplayClick:e.JWPLAYER_DISPLAY_CLICK,onControls:e.JWPLAYER_CONTROLS,onQualityLevels:e.JWPLAYER_MEDIA_LEVELS,onQualityChange:e.JWPLAYER_MEDIA_LEVEL_CHANGED,onCaptionsList:e.JWPLAYER_CAPTIONS_LIST,onCaptionsChange:e.JWPLAYER_CAPTIONS_CHANGED};l.foreach(z,function(a){h[a]=g(z[a],n)});var A={onBuffer:j.BUFFERING,onPause:j.PAUSED,onPlay:j.PLAYING,onIdle:j.IDLE};l.foreach(A,function(a){h[a]=g(A[a],q)});h.remove=
|
||||
function(){if(!s)throw"Cannot call remove() before player is ready";u=[];c.destroyPlayer(this.id)};h.setup=function(a){if(f.embed){var d=b.getElementById(h.id);d&&(a.fallbackDiv=d);d=h;u=[];c.destroyPlayer(d.id);d=f(h.id);d.config=a;return new f.embed(d)}return h};h.registerPlugin=function(a,b,d,c){f.plugins.registerPlugin(a,b,d,c)};h.setPlayer=function(a,b){t=a;h.renderingMode=b};h.detachMedia=function(){if("html5"==h.renderingMode)return k("jwDetachMedia")};h.attachMedia=function(a){if("html5"==
|
||||
h.renderingMode)return k("jwAttachMedia",a)};h.dispatchEvent=function(a,b){if(r[a])for(var d=l.translateEventResponse(a,b),c=0;c<r[a].length;c++)if("function"==typeof r[a][c])try{a==e.JWPLAYER_PLAYLIST_LOADED&&l.deepReplaceKeyName(d.playlist,["__dot__","__spc__","__dsh__","__default__"],["."," ","-","default"]),r[a][c].call(this,d)}catch(g){l.log("There was an error calling back an event handler")}};h.dispatchInstreamEvent=function(a){w&&w.dispatchEvent(a,arguments)};h.callInternal=k;h.playerReady=
|
||||
function(a){s=!0;t||h.setPlayer(b.getElementById(a.id));h.container=b.getElementById(h.id);l.foreach(r,function(a){m(t,a)});n(e.JWPLAYER_PLAYLIST_ITEM,function(){x={}});n(e.JWPLAYER_MEDIA_META,function(a){l.extend(x,a.metadata)});for(h.dispatchEvent(e.API_READY);0<u.length;)k.apply(this,u.shift())};h.getItemMeta=function(){return x};h.getCurrentItem=function(){return k("jwGetPlaylistIndex")};return h};c.selectPlayer=function(d){var g;l.exists(d)||(d=0);d.nodeType?g=d:"string"==typeof d&&(g=b.getElementById(d));
|
||||
return g?(d=c.playerById(g.id))?d:c.addPlayer(new c(g)):"number"==typeof d?a[d]:null};c.playerById=function(b){for(var c=0;c<a.length;c++)if(a[c].id==b)return a[c];return null};c.addPlayer=function(b){for(var c=0;c<a.length;c++)if(a[c]==b)return b;a.push(b);return b};c.destroyPlayer=function(d){for(var c=-1,e,f=0;f<a.length;f++)a[f].id==d&&(c=f,e=a[f]);0<=c&&(d=e.id,f=b.getElementById(d+("flash"==e.renderingMode?"_wrapper":"")),l.clearCss&&l.clearCss("#"+d),f&&("html5"==e.renderingMode&&e.destroyPlayer(),
|
||||
e=b.createElement("div"),e.id=d,f.parentNode.replaceChild(e,f)),a.splice(c,1));return null};f.playerReady=function(a){var b=f.api.playerById(a.id);b?b.playerReady(a):f.api.selectPlayer(a.id).playerReady(a)}}(jwplayer),function(f){var a=f.events,l=f.utils,e=a.state;f.api.instream=function(f,b,c,d){function g(a,b){k[a]||(k[a]=[],n.jwInstreamAddEventListener(a,'function(dat) { jwplayer("'+m.id+'").dispatchInstreamEvent("'+a+'", dat); }'));k[a].push(b);return this}function q(b,c){h[b]||(h[b]=[],g(a.JWPLAYER_PLAYER_STATE,
|
||||
function(a){var c=a.newstate,d=a.oldstate;if(c==b){var e=h[c];if(e)for(var f=0;f<e.length;f++)"function"==typeof e[f]&&e[f].call(this,{oldstate:d,newstate:c,type:a.type})}}));h[b].push(c);return this}var m=f,n=b,k={},h={};this.dispatchEvent=function(a,b){if(k[a])for(var c=l.translateEventResponse(a,b[1]),d=0;d<k[a].length;d++)"function"==typeof k[a][d]&&k[a][d].call(this,c)};this.onError=function(b){return g(a.JWPLAYER_ERROR,b)};this.onFullscreen=function(b){return g(a.JWPLAYER_FULLSCREEN,b)};this.onMeta=
|
||||
function(b){return g(a.JWPLAYER_MEDIA_META,b)};this.onMute=function(b){return g(a.JWPLAYER_MEDIA_MUTE,b)};this.onComplete=function(b){return g(a.JWPLAYER_MEDIA_COMPLETE,b)};this.onTime=function(b){return g(a.JWPLAYER_MEDIA_TIME,b)};this.onBuffer=function(a){return q(e.BUFFERING,a)};this.onPause=function(a){return q(e.PAUSED,a)};this.onPlay=function(a){return q(e.PLAYING,a)};this.onIdle=function(a){return q(e.IDLE,a)};this.onClick=function(b){return g(a.JWPLAYER_INSTREAM_CLICK,b)};this.onInstreamDestroyed=
|
||||
function(b){return g(a.JWPLAYER_INSTREAM_DESTROYED,b)};this.play=function(a){n.jwInstreamPlay(a)};this.pause=function(a){n.jwInstreamPause(a)};this.destroy=function(){n.jwInstreamDestroy()};m.callInternal("jwLoadInstream",c,d?d:{})}}(jwplayer),function(f){var a=f.api,l=a.selectPlayer;a.selectPlayer=function(a){return(a=l(a))?a:{registerPlugin:function(a,b,c){f.plugins.registerPlugin(a,b,c)}}}}(jwplayer));
|
|
@ -1,37 +0,0 @@
|
|||
/**
|
||||
* log specified, there must be a log element as:
|
||||
<!-- for the log -->
|
||||
<div class="alert alert-info fade in" id="txt_log">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><span id="txt_log_title">标题:</span></strong>
|
||||
<span id="txt_log_msg">日志内容</span>
|
||||
</div>
|
||||
*/
|
||||
var srs_log_disabled = false;
|
||||
function info(desc) {
|
||||
if (srs_log_disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$("#txt_log").addClass("alert-info").removeClass("alert-error").removeClass("alert-warn");
|
||||
$("#txt_log_title").text("Info:");
|
||||
$("#txt_log_msg").html(desc);
|
||||
}
|
||||
function warn(code, desc) {
|
||||
if (srs_log_disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$("#txt_log").removeClass("alert-info").removeClass("alert-error").addClass("alert-warn");
|
||||
$("#txt_log_title").text("Warn:");
|
||||
$("#txt_log_msg").html("code: " + code + ", " + desc);
|
||||
}
|
||||
function error(code, desc) {
|
||||
if (srs_log_disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$("#txt_log").removeClass("alert-info").addClass("alert-error").removeClass("alert-warn");
|
||||
$("#txt_log_title").text("Error:");
|
||||
$("#txt_log_msg").html("code: " + code + ", " + desc);
|
||||
}
|
|
@ -1,449 +0,0 @@
|
|||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// to query the swf anti cache.
|
||||
function srs_get_version_code() { return "1.33"; }
|
||||
|
||||
/**
|
||||
* player specified size.
|
||||
*/
|
||||
function srs_get_player_modal() { return 740; }
|
||||
function srs_get_player_width() { return srs_get_player_modal() - 30; }
|
||||
function srs_get_player_height() { return srs_get_player_width() * 9 / 19; }
|
||||
|
||||
// get the default vhost for players.
|
||||
function srs_get_player_vhost() { return "players"; }
|
||||
// the api server port, for chat room.
|
||||
function srs_get_api_server_port() { return 8085; }
|
||||
// the srs http server port
|
||||
function srs_get_srs_http_server_port() { return 8080; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* update the navigator, add same query string.
|
||||
*/
|
||||
function update_nav() {
|
||||
$("#srs_index").attr("href", "index.html" + window.location.search);
|
||||
$("#nav_srs_player").attr("href", "srs_player.html" + window.location.search);
|
||||
$("#nav_srs_publisher").attr("href", "srs_publisher.html" + window.location.search);
|
||||
$("#nav_srs_chat").attr("href", "srs_chat.html" + window.location.search);
|
||||
$("#nav_srs_bwt").attr("href", "srs_bwt.html" + window.location.search);
|
||||
$("#nav_jwplayer6").attr("href", "jwplayer6.html" + window.location.search);
|
||||
$("#nav_osmf").attr("href", "osmf.html" + window.location.search);
|
||||
$("#nav_vlc").attr("href", "vlc.html" + window.location.search);
|
||||
}
|
||||
|
||||
// Special extra params, such as auth_key.
|
||||
function user_extra_params(query, params) {
|
||||
var queries = params || [];
|
||||
var server = (query.server == undefined)? window.location.hostname:query.server;
|
||||
var vhost = (query.vhost == undefined)? window.location.hostname:query.vhost;
|
||||
|
||||
for (var key in query.user_query) {
|
||||
if (key == 'app' || key == 'autostart' || key == 'dir'
|
||||
|| key == 'filename' || key == 'host' || key == 'hostname'
|
||||
|| key == 'http_port' || key == 'pathname' || key == 'port'
|
||||
|| key == 'server' || key == 'stream' || key == 'buffer'
|
||||
|| key == 'schema' || key == 'vhost'
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (query[key]) {
|
||||
queries.push(key + '=' + query[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return queries;
|
||||
}
|
||||
|
||||
/**
|
||||
@param server the ip of server. default to window.location.hostname
|
||||
@param vhost the vhost of rtmp. default to window.location.hostname
|
||||
@param port the port of rtmp. default to 1935
|
||||
@param app the app of rtmp. default to live.
|
||||
@param stream the stream of rtmp. default to livestream.
|
||||
*/
|
||||
function build_default_rtmp_url() {
|
||||
var query = parse_query_string();
|
||||
|
||||
var schema = (!query.schema)? "rtmp":query.schema;
|
||||
var server = (!query.server)? window.location.hostname:query.server;
|
||||
var port = (!query.port)? schema=="http"?80:1935:query.port;
|
||||
var vhost = (!query.vhost)? window.location.hostname:query.vhost;
|
||||
var app = (!query.app)? "live":query.app;
|
||||
var stream = (!query.stream)? "livestream":query.stream;
|
||||
|
||||
var queries = [];
|
||||
if (server != vhost && vhost != "__defaultVhost__") {
|
||||
queries.push("vhost=" + vhost);
|
||||
}
|
||||
queries = user_extra_params(query, queries);
|
||||
|
||||
var uri = schema + "://" + server + ":" + port + "/" + app + "/" + stream + "?" + queries.join('&');
|
||||
while (uri.indexOf("?") == uri.length - 1) {
|
||||
uri = uri.substr(0, uri.length - 1);
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
// for the chat to init the publish url.
|
||||
function build_default_publish_rtmp_url() {
|
||||
var query = parse_query_string();
|
||||
|
||||
var schema = (!query.schema)? "rtmp":query.schema;
|
||||
var server = (!query.server)? window.location.hostname:query.server;
|
||||
var port = (!query.port)? schema=="http"?80:1935:query.port;
|
||||
var vhost = (!query.vhost)? window.location.hostname:query.vhost;
|
||||
var app = (!query.app)? "live":query.app;
|
||||
var stream = (!query.stream)? "demo":query.stream;
|
||||
|
||||
var queries = [];
|
||||
if (server != vhost && vhost != "__defaultVhost__") {
|
||||
queries.push("vhost=" + vhost);
|
||||
}
|
||||
if (query.shp_identify) {
|
||||
queries.push("shp_identify=" + query.shp_identify);
|
||||
}
|
||||
|
||||
var uri = schema + "://" + server + ":" + port + "/" + app + "/" + stream + "?" + queries.join('&');
|
||||
while (uri.indexOf("?") == uri.length - 1) {
|
||||
uri = uri.substr(0, uri.length - 1);
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
// for the bandwidth tool to init page
|
||||
function build_default_bandwidth_rtmp_url() {
|
||||
var query = parse_query_string();
|
||||
|
||||
var server = (!query.server)? window.location.hostname:query.server;
|
||||
var port = (!query.port)? 1935:query.port;
|
||||
var vhost = "bandcheck.srs.com";
|
||||
var app = (!query.app)? "app":query.app;
|
||||
var key = (!query.key)? "35c9b402c12a7246868752e2878f7e0e":query.key;
|
||||
|
||||
return "rtmp://" + server + ":" + port + "/" + app + "?key=" + key + "&vhost=" + vhost;
|
||||
}
|
||||
|
||||
/**
|
||||
@param server the ip of server. default to window.location.hostname
|
||||
@param vhost the vhost of hls. default to window.location.hostname
|
||||
@param hls_vhost the vhost of hls. override the server if specified.
|
||||
@param hls_port the port of hls. default to window.location.port
|
||||
@param app the app of hls. default to live.
|
||||
@param stream the stream of hls. default to livestream.
|
||||
*/
|
||||
function build_default_hls_url() {
|
||||
var query = parse_query_string();
|
||||
|
||||
// for http, use hls_vhost to override server if specified.
|
||||
var server = window.location.hostname;
|
||||
if (query.server != undefined) {
|
||||
server = query.server;
|
||||
} else if (query.hls_vhost != undefined) {
|
||||
server = query.hls_vhost;
|
||||
}
|
||||
|
||||
var port = (!query.hls_port)? window.location.port:query.hls_port;
|
||||
var app = (!query.app)? "live":query.app;
|
||||
var stream = (!query.stream)? "demo":query.stream;
|
||||
|
||||
if (!port) {
|
||||
port = 8080;
|
||||
}
|
||||
|
||||
if (stream.indexOf(".flv") >= 0) {
|
||||
return "http://" + server + ":" + port + "/" + app + "/" + stream;
|
||||
}
|
||||
return "http://" + server + ":" + port + "/" + app + "/" + stream + ".m3u8";
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize the page.
|
||||
* @param rtmp_url the div id contains the rtmp stream url to play
|
||||
* @param hls_url the div id contains the hls stream url to play
|
||||
* @param modal_player the div id contains the modal player
|
||||
*/
|
||||
function srs_init_rtmp(rtmp_url, modal_player) {
|
||||
srs_init(rtmp_url, null, modal_player);
|
||||
}
|
||||
function srs_init_hls(hls_url, modal_player) {
|
||||
srs_init(null, hls_url, modal_player);
|
||||
}
|
||||
function srs_init(rtmp_url, hls_url, modal_player) {
|
||||
update_nav();
|
||||
|
||||
if (rtmp_url) {
|
||||
$(rtmp_url).val(build_default_rtmp_url());
|
||||
}
|
||||
if (hls_url) {
|
||||
$(hls_url).val(build_default_hls_url());
|
||||
}
|
||||
if (modal_player) {
|
||||
$(modal_player).width(srs_get_player_modal() + "px");
|
||||
$(modal_player).css("margin-left", "-" + srs_get_player_modal() / 2 +"px");
|
||||
}
|
||||
}
|
||||
// for the chat to init the publish url.
|
||||
function srs_init_publish(rtmp_url) {
|
||||
update_nav();
|
||||
|
||||
if (rtmp_url) {
|
||||
$(rtmp_url).val(build_default_publish_rtmp_url());
|
||||
}
|
||||
}
|
||||
// for bw to init url
|
||||
// url: scheme://host:port/path?query#fragment
|
||||
function srs_init_bwt(rtmp_url, hls_url) {
|
||||
update_nav();
|
||||
|
||||
if (rtmp_url) {
|
||||
$(rtmp_url).val(build_default_bandwidth_rtmp_url());
|
||||
}
|
||||
}
|
||||
|
||||
// check whether can republish
|
||||
function srs_can_republish() {
|
||||
var browser = get_browser_agents();
|
||||
|
||||
if (browser.Chrome || browser.Firefox) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.MSIE || browser.QQBrowser) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// without default values set.
|
||||
function srs_initialize_codec_page(
|
||||
cameras, microphones,
|
||||
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate,
|
||||
sl_acodec
|
||||
) {
|
||||
$(sl_cameras).empty();
|
||||
for (var i = 0; i < cameras.length; i++) {
|
||||
$(sl_cameras).append("<option value='" + i + "'>" + cameras[i] + "</option");
|
||||
}
|
||||
// optional: select the except matches
|
||||
matchs = ["virtual"];
|
||||
for (var i = 0; i < cameras.length; i++) {
|
||||
for (var j = 0; j < matchs.length; j++) {
|
||||
if (cameras[i].toLowerCase().indexOf(matchs[j]) == -1) {
|
||||
$(sl_cameras + " option[value='" + i + "']").attr("selected", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < matchs.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// optional: select the first matched.
|
||||
matchs = ["truevision", "integrated"];
|
||||
for (var i = 0; i < cameras.length; i++) {
|
||||
for (var j = 0; j < matchs.length; j++) {
|
||||
if (cameras[i].toLowerCase().indexOf(matchs[j]) >= 0) {
|
||||
$(sl_cameras + " option[value='" + i + "']").attr("selected", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < matchs.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$(sl_microphones).empty();
|
||||
for (var i = 0; i < microphones.length; i++) {
|
||||
$(sl_microphones).append("<option value='" + i + "'>" + microphones[i] + "</option");
|
||||
}
|
||||
// optional: select the except matches
|
||||
matchs = ["default"];
|
||||
for (var i = 0; i < microphones.length; i++) {
|
||||
for (var j = 0; j < matchs.length; j++) {
|
||||
if (microphones[i].toLowerCase().indexOf(matchs[j]) == -1) {
|
||||
$(sl_microphones + " option[value='" + i + "']").attr("selected", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < matchs.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// optional: select the first matched.
|
||||
matchs = ["realtek", "内置式麦克风"];
|
||||
for (var i = 0; i < microphones.length; i++) {
|
||||
for (var j = 0; j < matchs.length; j++) {
|
||||
if (microphones[i].toLowerCase().indexOf(matchs[j]) >= 0) {
|
||||
$(sl_microphones + " option[value='" + i + "']").attr("selected", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < matchs.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$(sl_vcodec).empty();
|
||||
var vcodecs = ["h264", "vp6"];
|
||||
vcodecs = ["h264"]; // h264 only.
|
||||
for (var i = 0; i < vcodecs.length; i++) {
|
||||
$(sl_vcodec).append("<option value='" + vcodecs[i] + "'>" + vcodecs[i] + "</option");
|
||||
}
|
||||
|
||||
$(sl_profile).empty();
|
||||
var profiles = ["baseline", "main"];
|
||||
for (var i = 0; i < profiles.length; i++) {
|
||||
$(sl_profile).append("<option value='" + profiles[i] + "'>" + profiles[i] + "</option");
|
||||
}
|
||||
|
||||
$(sl_level).empty();
|
||||
var levels = ["1", "1b", "1.1", "1.2", "1.3",
|
||||
"2", "2.1", "2.2", "3", "3.1", "3.2", "4", "4.1", "4.2", "5", "5.1"];
|
||||
for (var i = 0; i < levels.length; i++) {
|
||||
$(sl_level).append("<option value='" + levels[i] + "'>" + levels[i] + "</option");
|
||||
}
|
||||
|
||||
$(sl_gop).empty();
|
||||
var gops = ["0.3", "0.5", "1", "2", "3", "4",
|
||||
"5", "6", "7", "8", "9", "10", "15", "20"];
|
||||
for (var i = 0; i < gops.length; i++) {
|
||||
$(sl_gop).append("<option value='" + gops[i] + "'>" + gops[i] + "秒</option");
|
||||
}
|
||||
|
||||
$(sl_size).empty();
|
||||
var sizes = ["176x144", "320x240", "352x240",
|
||||
"352x288", "480x360", "640x480", "720x480", "720x576", "800x600",
|
||||
"1024x768", "1280x720", "1360x768", "1920x1080"];
|
||||
for (i = 0; i < sizes.length; i++) {
|
||||
$(sl_size).append("<option value='" + sizes[i] + "'>" + sizes[i] + "</option");
|
||||
}
|
||||
|
||||
$(sl_fps).empty();
|
||||
var fpses = ["5", "10", "15", "20", "24", "25", "29.97", "30"];
|
||||
for (i = 0; i < fpses.length; i++) {
|
||||
$(sl_fps).append("<option value='" + fpses[i] + "'>" + Number(fpses[i]).toFixed(2) + " 帧/秒</option");
|
||||
}
|
||||
|
||||
$(sl_bitrate).empty();
|
||||
var bitrates = ["50", "200", "350", "500", "650", "800",
|
||||
"950", "1000", "1200", "1500", "1800", "2000", "3000", "5000"];
|
||||
for (i = 0; i < bitrates.length; i++) {
|
||||
$(sl_bitrate).append("<option value='" + bitrates[i] + "'>" + bitrates[i] + " kbps</option");
|
||||
}
|
||||
|
||||
$(sl_acodec).empty();
|
||||
var bitrates = ["speex", "nellymoser", "pcma", "pcmu"];
|
||||
for (i = 0; i < bitrates.length; i++) {
|
||||
$(sl_acodec).append("<option value='" + bitrates[i] + "'>" + bitrates[i] + "</option");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* when publisher ready, init the page elements.
|
||||
*/
|
||||
function srs_publisher_initialize_page(
|
||||
cameras, microphones,
|
||||
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate,
|
||||
sl_acodec
|
||||
) {
|
||||
srs_initialize_codec_page(
|
||||
cameras, microphones,
|
||||
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate,
|
||||
sl_acodec
|
||||
);
|
||||
|
||||
//var profiles = ["baseline", "main"];
|
||||
$(sl_profile + " option[value='main']").attr("selected", true);
|
||||
|
||||
//var levels = ["1", "1b", "1.1", "1.2", "1.3",
|
||||
// "2", "2.1", "2.2", "3", "3.1", "3.2", "4", "4.1", "4.2", "5", "5.1"];
|
||||
$(sl_level + " option[value='4.1']").attr("selected", true);
|
||||
|
||||
//var gops = ["0.3", "0.5", "1", "2", "3", "4",
|
||||
// "5", "6", "7", "8", "9", "10", "15", "20"];
|
||||
$(sl_gop + " option[value='10']").attr("selected", true);
|
||||
|
||||
//var sizes = ["176x144", "320x240", "352x240",
|
||||
// "352x288", "480x360", "640x480", "720x480", "720x576", "800x600",
|
||||
// "1024x768", "1280x720", "1360x768", "1920x1080"];
|
||||
$(sl_size + " option[value='640x480']").attr("selected", true);
|
||||
|
||||
//var fpses = ["5", "10", "15", "20", "24", "25", "29.97", "30"];
|
||||
$(sl_fps + " option[value='20']").attr("selected", true);
|
||||
|
||||
//var bitrates = ["50", "200", "350", "500", "650", "800",
|
||||
// "950", "1000", "1200", "1500", "1800", "2000", "3000", "5000"];
|
||||
$(sl_bitrate + " option[value='500']").attr("selected", true);
|
||||
|
||||
// speex
|
||||
$(sl_acodec + " option[value='speex']").attr("selected", true);
|
||||
}
|
||||
/**
|
||||
* for chat, use low latecy settings.
|
||||
*/
|
||||
function srs_chat_initialize_page(
|
||||
cameras, microphones,
|
||||
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate,
|
||||
sl_acodec
|
||||
) {
|
||||
srs_initialize_codec_page(
|
||||
cameras, microphones,
|
||||
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate,
|
||||
sl_acodec
|
||||
);
|
||||
|
||||
//var profiles = ["baseline", "main"];
|
||||
$(sl_profile + " option[value='baseline']").attr("selected", true);
|
||||
|
||||
//var levels = ["1", "1b", "1.1", "1.2", "1.3",
|
||||
// "2", "2.1", "2.2", "3", "3.1", "3.2", "4", "4.1", "4.2", "5", "5.1"];
|
||||
$(sl_level + " option[value='3.1']").attr("selected", true);
|
||||
|
||||
//var gops = ["0.3", "0.5", "1", "2", "3", "4",
|
||||
// "5", "6", "7", "8", "9", "10", "15", "20"];
|
||||
$(sl_gop + " option[value='2']").attr("selected", true);
|
||||
|
||||
//var sizes = ["176x144", "320x240", "352x240",
|
||||
// "352x288", "480x360", "640x480", "720x480", "720x576", "800x600",
|
||||
// "1024x768", "1280x720", "1360x768", "1920x1080"];
|
||||
$(sl_size + " option[value='480x360']").attr("selected", true);
|
||||
|
||||
//var fpses = ["5", "10", "15", "20", "24", "25", "29.97", "30"];
|
||||
$(sl_fps + " option[value='15']").attr("selected", true);
|
||||
|
||||
//var bitrates = ["50", "200", "350", "500", "650", "800",
|
||||
// "950", "1000", "1200", "1500", "1800", "2000", "3000", "5000"];
|
||||
$(sl_bitrate + " option[value='350']").attr("selected", true);
|
||||
|
||||
// speex
|
||||
$(sl_acodec + " option[value='speex']").attr("selected", true);
|
||||
}
|
||||
/**
|
||||
* get the vcodec and acodec.
|
||||
*/
|
||||
function srs_publiser_get_codec(
|
||||
vcodec, acodec,
|
||||
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate,
|
||||
sl_acodec
|
||||
) {
|
||||
acodec.codec = $(sl_acodec).val();
|
||||
acodec.device_code = $(sl_microphones).val();
|
||||
acodec.device_name = $(sl_microphones).text();
|
||||
|
||||
vcodec.device_code = $(sl_cameras).find("option:selected").val();
|
||||
vcodec.device_name = $(sl_cameras).find("option:selected").text();
|
||||
|
||||
vcodec.codec = $(sl_vcodec).find("option:selected").val();
|
||||
vcodec.profile = $(sl_profile).find("option:selected").val();
|
||||
vcodec.level = $(sl_level).find("option:selected").val();
|
||||
vcodec.fps = $(sl_fps).find("option:selected").val();
|
||||
vcodec.gop = $(sl_gop).find("option:selected").val();
|
||||
vcodec.size = $(sl_size).find("option:selected").val();
|
||||
vcodec.bitrate = $(sl_bitrate).find("option:selected").val();
|
||||
}
|
|
@ -1,382 +0,0 @@
|
|||
/**
|
||||
* the SrsPlayer object.
|
||||
* @param container the html container id.
|
||||
* @param width a float value specifies the width of player.
|
||||
* @param height a float value specifies the height of player.
|
||||
* @param private_object [optional] an object that used as private object,
|
||||
* for example, the logic chat object which owner this player.
|
||||
* Usage:
|
||||
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||
<script type="text/javascript" src="js/srs.player.js"></script>
|
||||
<div id="player"></div>
|
||||
var p = new SrsPlayer("player", 640, 480);
|
||||
p.set_srs_player_url("srs_player.swf?v=1.0.0");
|
||||
p.on_player_ready = function() {
|
||||
p.set_bt(0.8);
|
||||
p.set_mbt(1.2);
|
||||
p.play("rtmp://ossrs.net/live/livestream");
|
||||
};
|
||||
p.on_player_metadata = function(metadata) {
|
||||
console.log(metadata);
|
||||
console.log(p.dump_log());
|
||||
};
|
||||
p.start();
|
||||
*/
|
||||
function SrsPlayer(container, width, height, private_object) {
|
||||
if (!SrsPlayer.__id) {
|
||||
SrsPlayer.__id = 100;
|
||||
}
|
||||
if (!SrsPlayer.__players) {
|
||||
SrsPlayer.__players = [];
|
||||
}
|
||||
|
||||
SrsPlayer.__players.push(this);
|
||||
|
||||
this.private_object = private_object;
|
||||
this.container = container;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.id = SrsPlayer.__id++;
|
||||
this.stream_url = null;
|
||||
this.buffer_time = 0.3; // default to 0.3
|
||||
this.max_buffer_time = this.buffer_time * 3; // default to 3 x bufferTime.
|
||||
this.volume = 1.0; // default to 100%
|
||||
this.callbackObj = null;
|
||||
this.srs_player_url = "srs_player/release/srs_player.swf?_version="+srs_get_version_code();
|
||||
|
||||
// callback set the following values.
|
||||
this.meatadata = {}; // for on_player_metadata
|
||||
this.time = 0; // current stream time.
|
||||
this.buffer_length = 0; // current stream buffer length.
|
||||
this.kbps = 0; // current stream bitrate(video+audio) in kbps.
|
||||
this.fps = 0; // current stream video fps.
|
||||
this.rtime = 0; // flash relative time in ms.
|
||||
|
||||
this.__fluency = {
|
||||
total_empty_count: 0,
|
||||
total_empty_time: 0,
|
||||
current_empty_time: 0
|
||||
};
|
||||
this.__fluency.on_stream_empty = function(time) {
|
||||
this.total_empty_count++;
|
||||
this.current_empty_time = time;
|
||||
};
|
||||
this.__fluency.on_stream_full = function(time) {
|
||||
if (this.current_empty_time > 0) {
|
||||
this.total_empty_time += time - this.current_empty_time;
|
||||
this.current_empty_time = 0;
|
||||
}
|
||||
};
|
||||
this.__fluency.calc = function(time) {
|
||||
var den = this.total_empty_count * 4 + this.total_empty_time * 2 + time;
|
||||
if (den > 0) {
|
||||
return time * 100 / den;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* user can set some callback, then start the player.
|
||||
* @param url the default url.
|
||||
* callbacks:
|
||||
* on_player_ready():int, when srs player ready, user can play().
|
||||
* on_player_metadata(metadata:Object):int, when srs player get metadata.
|
||||
* methods:
|
||||
* set_bt(t:Number):void, set the buffer time in seconds.
|
||||
* set_mbt(t:Number):void, set the max buffer time in seconds.
|
||||
* dump_log():String, get all logs of player.
|
||||
*/
|
||||
SrsPlayer.prototype.start = function(url) {
|
||||
if (url) {
|
||||
this.stream_url = url;
|
||||
}
|
||||
|
||||
// embed the flash.
|
||||
var flashvars = {};
|
||||
flashvars.id = this.id;
|
||||
flashvars.on_player_ready = "__srs_on_player_ready";
|
||||
flashvars.on_player_metadata = "__srs_on_player_metadata";
|
||||
flashvars.on_player_timer = "__srs_on_player_timer";
|
||||
flashvars.on_player_empty = "__srs_on_player_empty";
|
||||
flashvars.on_player_full = "__srs_on_player_full";
|
||||
flashvars.on_player_status = "__srs_on_player_status";
|
||||
|
||||
var params = {};
|
||||
params.wmode = "opaque";
|
||||
params.allowFullScreen = "true";
|
||||
params.allowScriptAccess = "always";
|
||||
|
||||
var attributes = {};
|
||||
|
||||
var self = this;
|
||||
|
||||
swfobject.embedSWF(
|
||||
this.srs_player_url,
|
||||
this.container,
|
||||
this.width, this.height,
|
||||
"11.1.0", "js/AdobeFlashPlayerInstall.swf",
|
||||
flashvars, params, attributes,
|
||||
function(callbackObj){
|
||||
self.callbackObj = callbackObj;
|
||||
if (!callbackObj.success) {
|
||||
console.error('Initialize player failed:'); console.error(callbackObj);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* play the stream.
|
||||
* @param stream_url the url of stream, rtmp or http.
|
||||
* @param volume the volume, 0 is mute, 1 is 100%, 2 is 200%.
|
||||
*/
|
||||
SrsPlayer.prototype.play = function(url, volume) {
|
||||
this.stop();
|
||||
SrsPlayer.__players.push(this);
|
||||
|
||||
if (url) {
|
||||
this.stream_url = url;
|
||||
}
|
||||
|
||||
// volume maybe 0, so never use if(volume) to check its value.
|
||||
if (volume != null && volume != undefined) {
|
||||
this.volume = volume;
|
||||
}
|
||||
|
||||
this.callbackObj.ref.__play(this.stream_url, this.width, this.height, this.buffer_time, this.max_buffer_time, this.volume);
|
||||
}
|
||||
/**
|
||||
* stop play stream.
|
||||
*/
|
||||
SrsPlayer.prototype.stop = function() {
|
||||
this.callbackObj.ref.__stop();
|
||||
}
|
||||
/**
|
||||
* pause the play.
|
||||
*/
|
||||
SrsPlayer.prototype.pause = function() {
|
||||
this.callbackObj.ref.__pause();
|
||||
}
|
||||
/**
|
||||
* resume the play.
|
||||
*/
|
||||
SrsPlayer.prototype.resume = function() {
|
||||
this.callbackObj.ref.__resume();
|
||||
}
|
||||
/**
|
||||
* get the stream fluency, where 100 is 100%.
|
||||
*/
|
||||
SrsPlayer.prototype.fluency = function() {
|
||||
return this.__fluency.calc(this.rtime);
|
||||
}
|
||||
/**
|
||||
* get the stream empty count.
|
||||
*/
|
||||
SrsPlayer.prototype.empty_count = function() {
|
||||
return this.__fluency.total_empty_count;
|
||||
}
|
||||
/**
|
||||
* get all log data.
|
||||
*/
|
||||
SrsPlayer.prototype.dump_log = function() {
|
||||
return this.callbackObj.ref.__dump_log();
|
||||
}
|
||||
/**
|
||||
* to set the DAR, for example, DAR=16:9 where num=16,den=9.
|
||||
* @param num, for example, 16.
|
||||
* use metadata width if 0.
|
||||
* use user specified width if -1.
|
||||
* @param den, for example, 9.
|
||||
* use metadata height if 0.
|
||||
* use user specified height if -1.
|
||||
*/
|
||||
SrsPlayer.prototype.set_dar = function(num, den) {
|
||||
this.callbackObj.ref.__set_dar(num, den);
|
||||
}
|
||||
/**
|
||||
* set the fullscreen size data.
|
||||
* @refer the refer fullscreen mode. it can be:
|
||||
* video: use video orignal size.
|
||||
* screen: use screen size to rescale video.
|
||||
* @param percent, the rescale percent, where
|
||||
* 100 means 100%.
|
||||
*/
|
||||
SrsPlayer.prototype.set_fs = function(refer, percent) {
|
||||
this.callbackObj.ref.__set_fs(refer, percent);
|
||||
}
|
||||
/**
|
||||
* set the stream buffer time in seconds.
|
||||
* @buffer_time the buffer time in seconds.
|
||||
*/
|
||||
SrsPlayer.prototype.set_bt = function(buffer_time) {
|
||||
if (this.buffer_time == buffer_time) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.buffer_time = buffer_time;
|
||||
this.callbackObj.ref.__set_bt(buffer_time);
|
||||
|
||||
// reset the max buffer time to 3 x buffer_time.
|
||||
this.set_mbt(buffer_time * 3);
|
||||
}
|
||||
/**
|
||||
* set the stream max buffer time in seconds.
|
||||
* @param max_buffer_time the max buffer time in seconds.
|
||||
* @remark this is the key feature for realtime communication by flash.
|
||||
*/
|
||||
SrsPlayer.prototype.set_mbt = function(max_buffer_time) {
|
||||
// we must atleast set the max buffer time to 0.6s.
|
||||
max_buffer_time = Math.max(0.6, max_buffer_time);
|
||||
// max buffer time always greater than buffer time.
|
||||
max_buffer_time = Math.max(this.buffer_time, max_buffer_time);
|
||||
|
||||
if (parseInt(this.max_buffer_time * 10) == parseInt(max_buffer_time * 10)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.max_buffer_time = max_buffer_time;
|
||||
this.callbackObj.ref.__set_mbt(max_buffer_time);
|
||||
}
|
||||
/**
|
||||
* set the srs_player.swf url
|
||||
* @param url, srs_player.swf's url.
|
||||
* @param params, object.
|
||||
*/
|
||||
SrsPlayer.prototype.set_srs_player_url = function(url, params) {
|
||||
var query_array = [],
|
||||
query_string = "",
|
||||
p;
|
||||
params = params || {};
|
||||
params._version = srs_get_version_code();
|
||||
for (p in params) {
|
||||
if (params.hasOwnProperty(p)) {
|
||||
query_array.push(p + "=" + encodeURIComponent(params[p]));
|
||||
}
|
||||
}
|
||||
query_string = query_array.join("&");
|
||||
this.srs_player_url = url + "?" + query_string;
|
||||
}
|
||||
/**
|
||||
* the callback when player is ready.
|
||||
*/
|
||||
SrsPlayer.prototype.on_player_ready = function() {
|
||||
}
|
||||
/**
|
||||
* the callback when player got metadata.
|
||||
* @param metadata the metadata which player got.
|
||||
*/
|
||||
SrsPlayer.prototype.on_player_metadata = function(metadata) {
|
||||
// ignore.
|
||||
}
|
||||
/**
|
||||
* the callback when player timer event.
|
||||
* @param time current stream time.
|
||||
* @param buffer_length current buffer length.
|
||||
* @param kbps current video plus audio bitrate in kbps.
|
||||
* @param fps current video fps.
|
||||
* @param rtime current relative time by flash.util.getTimer().
|
||||
*/
|
||||
SrsPlayer.prototype.on_player_timer = function(time, buffer_length, kbps, fps, rtime) {
|
||||
// ignore.
|
||||
}
|
||||
/**
|
||||
* the callback when player got NetStream.Buffer.Empty
|
||||
* @param time current relative time by flash.util.getTimer().
|
||||
*/
|
||||
SrsPlayer.prototype.on_player_empty = function(time) {
|
||||
// ignore.
|
||||
}
|
||||
/**
|
||||
* the callback when player got NetStream.Buffer.Full
|
||||
* @param time current relative time by flash.util.getTimer().
|
||||
*/
|
||||
SrsPlayer.prototype.on_player_full = function(time) {
|
||||
// ignore.
|
||||
}
|
||||
/**
|
||||
* the callback when player status change.
|
||||
* @param code the status code, "init", "connected", "play", "closed", "rejected", "failed".
|
||||
* init => connected/rejected/failed
|
||||
* connected => play/rejected => closed
|
||||
* @param desc the description for the status.
|
||||
*/
|
||||
SrsPlayer.prototype.on_player_status = function(code, desc) {
|
||||
// ignore.
|
||||
}
|
||||
|
||||
/**
|
||||
* helpers.
|
||||
*/
|
||||
function __srs_find_player(id) {
|
||||
for (var i = 0; i < SrsPlayer.__players.length; i++) {
|
||||
var player = SrsPlayer.__players[i];
|
||||
|
||||
if (player.id != id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
throw new Error("player not found. id=" + id);
|
||||
}
|
||||
function __srs_on_player_ready(id) {
|
||||
var player = __srs_find_player(id);
|
||||
player.on_player_ready();
|
||||
}
|
||||
function __srs_on_player_metadata(id, metadata) {
|
||||
var player = __srs_find_player(id);
|
||||
|
||||
// user may override the on_player_metadata,
|
||||
// so set the data before invoke it.
|
||||
player.metadata = metadata;
|
||||
|
||||
player.on_player_metadata(metadata);
|
||||
}
|
||||
function __srs_on_player_timer(id, time, buffer_length, kbps, fps, rtime) {
|
||||
var player = __srs_find_player(id);
|
||||
|
||||
buffer_length = Math.max(0, buffer_length);
|
||||
buffer_length = Math.min(player.buffer_time, buffer_length);
|
||||
|
||||
time = Math.max(0, time);
|
||||
|
||||
// user may override the on_player_timer,
|
||||
// so set the data before invoke it.
|
||||
player.time = time;
|
||||
player.buffer_length = buffer_length;
|
||||
player.kbps = kbps;
|
||||
player.fps = fps;
|
||||
player.rtime = rtime;
|
||||
|
||||
player.on_player_timer(time, buffer_length, kbps, fps, rtime);
|
||||
}
|
||||
function __srs_on_player_empty(id, time) {
|
||||
var player = __srs_find_player(id);
|
||||
player.__fluency.on_stream_empty(time);
|
||||
player.on_player_empty(time);
|
||||
}
|
||||
function __srs_on_player_full(id, time) {
|
||||
var player = __srs_find_player(id);
|
||||
player.__fluency.on_stream_full(time);
|
||||
player.on_player_full(time);
|
||||
}
|
||||
function __srs_on_player_status(id, code, desc) {
|
||||
var player = __srs_find_player(id);
|
||||
player.on_player_status(code, desc);
|
||||
|
||||
if (code != "closed") {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < SrsPlayer.__players.length; i++) {
|
||||
var player = SrsPlayer.__players[i];
|
||||
|
||||
if (player.id != this.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SrsPlayer.__players.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
/**
|
||||
* the SrsPublisher object.
|
||||
* @param container the html container id.
|
||||
* @param width a float value specifies the width of publisher.
|
||||
* @param height a float value specifies the height of publisher.
|
||||
* @param private_object [optional] an object that used as private object,
|
||||
* for example, the logic chat object which owner this publisher.
|
||||
*/
|
||||
function SrsPublisher(container, width, height, private_object) {
|
||||
if (!SrsPublisher.__id) {
|
||||
SrsPublisher.__id = 100;
|
||||
}
|
||||
if (!SrsPublisher.__publishers) {
|
||||
SrsPublisher.__publishers = [];
|
||||
}
|
||||
|
||||
SrsPublisher.__publishers.push(this);
|
||||
|
||||
this.private_object = private_object;
|
||||
this.container = container;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.id = SrsPublisher.__id++;
|
||||
this.callbackObj = null;
|
||||
|
||||
// set the values when publish.
|
||||
this.url = null;
|
||||
this.vcodec = {};
|
||||
this.acodec = {};
|
||||
|
||||
// callback set the following values.
|
||||
this.cameras = [];
|
||||
this.microphones = [];
|
||||
this.code = 0;
|
||||
|
||||
// error code defines.
|
||||
this.errors = {
|
||||
"100": "无法获取指定的摄像头。", //error_camera_get
|
||||
"101": "无法获取指定的麦克风。", //error_microphone_get
|
||||
"102": "摄像头为禁用状态,推流时请允许flash访问摄像头。", //error_camera_muted
|
||||
"103": "服务器关闭了连接。", //error_connection_closed
|
||||
"104": "服务器连接失败。", //error_connection_failed
|
||||
"199": "未知错误。"
|
||||
};
|
||||
}
|
||||
/**
|
||||
* user can set some callback, then start the publisher.
|
||||
* callbacks:
|
||||
* on_publisher_ready(cameras, microphones):int, when srs publisher ready, user can publish.
|
||||
* on_publisher_error(code, desc):int, when srs publisher error, callback this method.
|
||||
* on_publisher_warn(code, desc):int, when srs publisher warn, callback this method.
|
||||
*/
|
||||
SrsPublisher.prototype.start = function() {
|
||||
// embed the flash.
|
||||
var flashvars = {};
|
||||
flashvars.id = this.id;
|
||||
flashvars.width = this.width;
|
||||
flashvars.height = this.height;
|
||||
flashvars.on_publisher_ready = "__srs_on_publisher_ready";
|
||||
flashvars.on_publisher_error = "__srs_on_publisher_error";
|
||||
flashvars.on_publisher_warn = "__srs_on_publisher_warn";
|
||||
|
||||
var params = {};
|
||||
params.wmode = "opaque";
|
||||
params.allowFullScreen = "true";
|
||||
params.allowScriptAccess = "always";
|
||||
|
||||
var attributes = {};
|
||||
|
||||
var self = this;
|
||||
|
||||
swfobject.embedSWF(
|
||||
"srs_publisher/release/srs_publisher.swf?_version="+srs_get_version_code(),
|
||||
this.container,
|
||||
this.width, this.height,
|
||||
"11.1.0", "js/AdobeFlashPlayerInstall.swf",
|
||||
flashvars, params, attributes,
|
||||
function(callbackObj){
|
||||
self.callbackObj = callbackObj;
|
||||
}
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* publish stream to server.
|
||||
* @param url a string indicates the rtmp url to publish.
|
||||
* @param vcodec an object contains the video codec info.
|
||||
* @param acodec an object contains the audio codec info.
|
||||
*/
|
||||
SrsPublisher.prototype.publish = function(url, vcodec, acodec) {
|
||||
this.stop();
|
||||
SrsPublisher.__publishers.push(this);
|
||||
|
||||
if (url) {
|
||||
this.url = url;
|
||||
}
|
||||
if (vcodec) {
|
||||
this.vcodec = vcodec;
|
||||
}
|
||||
if (acodec) {
|
||||
this.acodec = acodec;
|
||||
}
|
||||
|
||||
this.callbackObj.ref.__publish(this.url, this.width, this.height, this.vcodec, this.acodec);
|
||||
}
|
||||
SrsPublisher.prototype.stop = function() {
|
||||
for (var i = 0; i < SrsPublisher.__publishers.length; i++) {
|
||||
var player = SrsPublisher.__publishers[i];
|
||||
|
||||
if (player.id != this.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SrsPublisher.__publishers.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
this.callbackObj.ref.__stop();
|
||||
}
|
||||
/**
|
||||
* when publisher ready.
|
||||
* @param cameras a string array contains the names of cameras.
|
||||
* @param microphones a string array contains the names of microphones.
|
||||
*/
|
||||
SrsPublisher.prototype.on_publisher_ready = function(cameras, microphones) {
|
||||
}
|
||||
/**
|
||||
* when publisher error.
|
||||
* @code the error code.
|
||||
* @desc the error desc message.
|
||||
*/
|
||||
SrsPublisher.prototype.on_publisher_error = function(code, desc) {
|
||||
throw new Error("publisher error. code=" + code + ", desc=" + desc);
|
||||
}
|
||||
SrsPublisher.prototype.on_publisher_warn = function(code, desc) {
|
||||
throw new Error("publisher warn. code=" + code + ", desc=" + desc);
|
||||
}
|
||||
function __srs_find_publisher(id) {
|
||||
for (var i = 0; i < SrsPublisher.__publishers.length; i++) {
|
||||
var publisher = SrsPublisher.__publishers[i];
|
||||
|
||||
if (publisher.id != id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return publisher;
|
||||
}
|
||||
|
||||
throw new Error("publisher not found. id=" + id);
|
||||
}
|
||||
function __srs_on_publisher_ready(id, cameras, microphones) {
|
||||
var publisher = __srs_find_publisher(id);
|
||||
|
||||
publisher.cameras = cameras;
|
||||
publisher.microphones = microphones;
|
||||
|
||||
publisher.on_publisher_ready(cameras, microphones);
|
||||
}
|
||||
function __srs_on_publisher_error(id, code) {
|
||||
var publisher = __srs_find_publisher(id);
|
||||
|
||||
publisher.code = code;
|
||||
|
||||
publisher.on_publisher_error(code, publisher.errors[""+code]);
|
||||
}
|
||||
function __srs_on_publisher_warn(id, code) {
|
||||
var publisher = __srs_find_publisher(id);
|
||||
|
||||
publisher.code = code;
|
||||
|
||||
publisher.on_publisher_warn(code, publisher.errors[""+code]);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* parse the rtmp url,
|
||||
* for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
|
||||
* @return object {server, port, vhost, app, stream}
|
||||
*/
|
||||
function srs_parse_rtmp_url(rtmp_url) {
|
||||
return parse_rtmp_url(rtmp_url);
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1,667 +0,0 @@
|
|||
// winlin.utility.js
|
||||
|
||||
/**
|
||||
* common utilities
|
||||
* depends: jquery1.10
|
||||
* https://code.csdn.net/snippets/147103
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||
* v 1.0.17
|
||||
*/
|
||||
|
||||
/**
|
||||
* padding the output.
|
||||
* padding(3, 5, '0') is 00003
|
||||
* padding(3, 5, 'x') is xxxx3
|
||||
* @see http://blog.csdn.net/win_lin/article/details/12065413
|
||||
*/
|
||||
function padding(number, length, prefix) {
|
||||
if(String(number).length >= length){
|
||||
return String(number);
|
||||
}
|
||||
return padding(prefix+number, length, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* extends system array, to remove all specified elem.
|
||||
* @param arr the array to remove elem from.
|
||||
* @param elem the elem to remove.
|
||||
* @remark all elem will be removed.
|
||||
* for example,
|
||||
* arr = [10, 15, 20, 30, 20, 40]
|
||||
* system_array_remove(arr, 10) // arr=[15, 20, 30, 20, 40]
|
||||
* system_array_remove(arr, 20) // arr=[15, 30, 40]
|
||||
*/
|
||||
function system_array_remove(arr, elem) {
|
||||
if (!arr) {
|
||||
return;
|
||||
}
|
||||
|
||||
var removed = true;
|
||||
var i = 0;
|
||||
while (removed) {
|
||||
removed = false;
|
||||
for (; i < arr.length; i++) {
|
||||
if (elem == arr[i]) {
|
||||
arr.splice(i, 1);
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the array contains specified element.
|
||||
* @param arr the array to find.
|
||||
* @param elem_or_function the element value or compare function.
|
||||
* @returns true contains elem; otherwise false.
|
||||
* for example,
|
||||
* arr = [10, 15, 20, 30, 20, 40]
|
||||
* system_array_contains(arr, 10) // true
|
||||
* system_array_contains(arr, 11) // false
|
||||
* system_array_contains(arr, function(elem){return elem == 30;}); // true
|
||||
* system_array_contains(arr, function(elem){return elem == 60;}); // false
|
||||
*/
|
||||
function system_array_contains(arr, elem_or_function) {
|
||||
return system_array_get(arr, elem_or_function) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the specified element from array
|
||||
* @param arr the array to find.
|
||||
* @param elem_or_function the element value or compare function.
|
||||
* @returns the matched elem; otherwise null.
|
||||
* for example,
|
||||
* arr = [10, 15, 20, 30, 20, 40]
|
||||
* system_array_get(arr, 10) // 10
|
||||
* system_array_get(arr, 11) // null
|
||||
* system_array_get(arr, function(elem){return elem == 30;}); // 30
|
||||
* system_array_get(arr, function(elem){return elem == 60;}); // null
|
||||
*/
|
||||
function system_array_get(arr, elem_or_function) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (typeof elem_or_function == "function") {
|
||||
if (elem_or_function(arr[i])) {
|
||||
return arr[i];
|
||||
}
|
||||
} else {
|
||||
if (elem_or_function == arr[i]) {
|
||||
return arr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* to iterate on array.
|
||||
* @param arr the array to iterate on.
|
||||
* @param pfn the function to apply on it. return false to break loop.
|
||||
* for example,
|
||||
* arr = [10, 15, 20, 30, 20, 40]
|
||||
* system_array_foreach(arr, function(elem, index){
|
||||
* console.log('index=' + index + ',elem=' + elem);
|
||||
* });
|
||||
* @return true when iterate all elems.
|
||||
*/
|
||||
function system_array_foreach(arr, pfn) {
|
||||
if (!pfn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (!pfn(arr[i], i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the str starts with flag.
|
||||
*/
|
||||
function system_string_startswith(str, flag) {
|
||||
if (typeof flag == "object" && flag.constructor == Array) {
|
||||
for (var i = 0; i < flag.length; i++) {
|
||||
if (system_string_startswith(str, flag[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str && flag && str.length >= flag.length && str.indexOf(flag) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether the str ends with flag.
|
||||
*/
|
||||
function system_string_endswith(str, flag) {
|
||||
if (typeof flag == "object" && flag.constructor == Array) {
|
||||
for (var i = 0; i < flag.length; i++) {
|
||||
if (system_string_endswith(str, flag[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str && flag && str.length >= flag.length && str.indexOf(flag) == str.length - flag.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* trim the start and end of flag in str.
|
||||
* @param flag a string to trim.
|
||||
*/
|
||||
function system_string_trim(str, flag) {
|
||||
if (!flag || !flag.length || typeof flag != "string") {
|
||||
return str;
|
||||
}
|
||||
|
||||
while (system_string_startswith(str, flag)) {
|
||||
str = str.substr(flag.length);
|
||||
}
|
||||
|
||||
while (system_string_endswith(str, flag)) {
|
||||
str = str.substr(0, str.length - flag.length);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* array sort asc, for example:
|
||||
* [a, b] in [10, 11, 9]
|
||||
* then sort to: [9, 10, 11]
|
||||
* Usage, for example:
|
||||
obj.data.data.sort(function(a, b){
|
||||
return array_sort_asc(a.metadata.meta_id, b.metadata.meta_id);
|
||||
});
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||
* @remark, if need desc, use -1*array_sort_asc(a,b)
|
||||
*/
|
||||
function array_sort_asc(elem_a, elem_b) {
|
||||
if (elem_a > elem_b) {
|
||||
return 1;
|
||||
}
|
||||
return (elem_a < elem_b)? -1 : 0;
|
||||
}
|
||||
function array_sort_desc(elem_a, elem_b) {
|
||||
return -1 * array_sort_asc(elem_a, elem_b);
|
||||
}
|
||||
function system_array_sort_asc(elem_a, elem_b) {
|
||||
return array_sort_asc(elem_a, elem_b);
|
||||
}
|
||||
function system_array_sort_desc(elem_a, elem_b) {
|
||||
return -1 * array_sort_asc(elem_a, elem_b);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse the query string to object.
|
||||
* parse the url location object as: host(hostname:http_port), pathname(dir/filename)
|
||||
* for example, url http://192.168.1.168:1980/ui/players.html?vhost=player.vhost.com&app=test&stream=livestream
|
||||
* parsed to object:
|
||||
{
|
||||
host : "192.168.1.168:1980",
|
||||
hostname : "192.168.1.168",
|
||||
http_port : 1980,
|
||||
pathname : "/ui/players.html",
|
||||
dir : "/ui",
|
||||
filename : "/players.html",
|
||||
|
||||
vhost : "player.vhost.com",
|
||||
app : "test",
|
||||
stream : "livestream"
|
||||
}
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||
*/
|
||||
function parse_query_string(){
|
||||
var obj = {};
|
||||
|
||||
// add the uri object.
|
||||
// parse the host(hostname:http_port), pathname(dir/filename)
|
||||
obj.host = window.location.host;
|
||||
obj.hostname = window.location.hostname;
|
||||
obj.http_port = (window.location.port == "")? 80:window.location.port;
|
||||
obj.pathname = window.location.pathname;
|
||||
if (obj.pathname.lastIndexOf("/") <= 0) {
|
||||
obj.dir = "/";
|
||||
obj.filename = "";
|
||||
} else {
|
||||
obj.dir = obj.pathname.substr(0, obj.pathname.lastIndexOf("/"));
|
||||
obj.filename = obj.pathname.substr(obj.pathname.lastIndexOf("/"));
|
||||
}
|
||||
|
||||
// pure user query object.
|
||||
obj.user_query = {};
|
||||
|
||||
// parse the query string.
|
||||
var query_string = String(window.location.search).replace(" ", "").split("?")[1];
|
||||
if(query_string == undefined){
|
||||
query_string = String(window.location.hash).replace(" ", "").split("#")[1];
|
||||
if(query_string == undefined){
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
__fill_query(query_string, obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function __fill_query(query_string, obj) {
|
||||
// pure user query object.
|
||||
obj.user_query = {};
|
||||
|
||||
if (query_string.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// split again for angularjs.
|
||||
if (query_string.indexOf("?") >= 0) {
|
||||
query_string = query_string.split("?")[1];
|
||||
}
|
||||
|
||||
var queries = query_string.split("&");
|
||||
for (var i = 0; i < queries.length; i++) {
|
||||
var elem = queries[i];
|
||||
|
||||
var query = elem.split("=");
|
||||
obj[query[0]] = query[1];
|
||||
obj.user_query[query[0]] = query[1];
|
||||
}
|
||||
|
||||
// alias domain for vhost.
|
||||
if (obj.domain) {
|
||||
obj.vhost = obj.domain;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse the rtmp url,
|
||||
* for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
|
||||
* @return object {server, port, vhost, app, stream}
|
||||
* for exmaple, rtmp_url is rtmp://demo.srs.com:1935/live...vhost...players/livestream
|
||||
* parsed to object:
|
||||
{
|
||||
server: "demo.srs.com",
|
||||
port: 1935,
|
||||
vhost: "players",
|
||||
app: "live",
|
||||
stream: "livestream"
|
||||
}
|
||||
*/
|
||||
function parse_rtmp_url(rtmp_url) {
|
||||
// @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
|
||||
var a = document.createElement("a");
|
||||
a.href = rtmp_url.replace("rtmp://", "http://");
|
||||
|
||||
var vhost = a.hostname;
|
||||
var app = a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1);
|
||||
var stream = a.pathname.substr(a.pathname.lastIndexOf("/") + 1);
|
||||
|
||||
// parse the vhost in the params of app, that srs supports.
|
||||
app = app.replace("...vhost...", "?vhost=");
|
||||
if (app.indexOf("?") >= 0) {
|
||||
var params = app.substr(app.indexOf("?"));
|
||||
app = app.substr(0, app.indexOf("?"));
|
||||
|
||||
if (params.indexOf("vhost=") > 0) {
|
||||
vhost = params.substr(params.indexOf("vhost=") + "vhost=".length);
|
||||
if (vhost.indexOf("&") > 0) {
|
||||
vhost = vhost.substr(0, vhost.indexOf("&"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// when vhost equals to server, and server is ip,
|
||||
// the vhost is __defaultVhost__
|
||||
if (a.hostname == vhost) {
|
||||
var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
||||
if (re.test(a.hostname)) {
|
||||
vhost = "__defaultVhost__";
|
||||
}
|
||||
}
|
||||
|
||||
// parse the schema
|
||||
var schema = "rtmp";
|
||||
if (rtmp_url.indexOf("://") > 0) {
|
||||
schema = rtmp_url.substr(0, rtmp_url.indexOf("://"));
|
||||
}
|
||||
var port = (a.port == "")? (schema=="http"?"80":"1935"):a.port;
|
||||
|
||||
var ret = {
|
||||
url: rtmp_url,
|
||||
schema: schema,
|
||||
server: a.hostname, port: port,
|
||||
vhost: vhost, app: app, stream: stream
|
||||
};
|
||||
__fill_query(a.search, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the agent.
|
||||
* @return an object specifies some browser.
|
||||
* for example, get_browser_agents().MSIE
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||
*/
|
||||
function get_browser_agents() {
|
||||
var agent = navigator.userAgent;
|
||||
|
||||
/**
|
||||
WindowsPC platform, Win7:
|
||||
chrome 31.0.1650.63:
|
||||
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
|
||||
(KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
|
||||
firefox 23.0.1:
|
||||
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101
|
||||
Firefox/23.0
|
||||
safari 5.1.7(7534.57.2):
|
||||
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2
|
||||
(KHTML, like Gecko) Version/5.1.7 Safari/534.57.2
|
||||
opera 15.0.1147.153:
|
||||
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
|
||||
(KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
|
||||
OPR/15.0.1147.153
|
||||
360 6.2.1.272:
|
||||
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
|
||||
Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
|
||||
.NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
|
||||
.NET4.0E)
|
||||
IE 10.0.9200.16750(update: 10.0.12):
|
||||
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
|
||||
Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
|
||||
.NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
|
||||
.NET4.0E)
|
||||
*/
|
||||
|
||||
return {
|
||||
// platform
|
||||
Android: agent.indexOf("Android") != -1,
|
||||
Windows: agent.indexOf("Windows") != -1,
|
||||
iPhone: agent.indexOf("iPhone") != -1,
|
||||
// Windows Browsers
|
||||
Chrome: agent.indexOf("Chrome") != -1,
|
||||
Firefox: agent.indexOf("Firefox") != -1,
|
||||
QQBrowser: agent.indexOf("QQBrowser") != -1,
|
||||
MSIE: agent.indexOf("MSIE") != -1,
|
||||
// Android Browsers
|
||||
Opera: agent.indexOf("Presto") != -1,
|
||||
MQQBrowser: agent.indexOf("MQQBrowser") != -1
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* format relative seconds to HH:MM:SS,
|
||||
* for example, 210s formated to 00:03:30
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||
* @usage relative_seconds_to_HHMMSS(210)
|
||||
*/
|
||||
function relative_seconds_to_HHMMSS(seconds){
|
||||
var date = new Date();
|
||||
date.setTime(Number(seconds) * 1000);
|
||||
|
||||
var ret = padding(date.getUTCHours(), 2, '0')
|
||||
+ ":" + padding(date.getUTCMinutes(), 2, '0')
|
||||
+ ":" + padding(date.getUTCSeconds(), 2, '0');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* format absolute seconds to HH:MM:SS,
|
||||
* for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 10:01:20
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||
* @usage absolute_seconds_to_HHMMSS(new Date().getTime() / 1000)
|
||||
*/
|
||||
function absolute_seconds_to_HHMMSS(seconds){
|
||||
var date = new Date();
|
||||
date.setTime(Number(seconds) * 1000);
|
||||
|
||||
var ret = padding(date.getHours(), 2, '0')
|
||||
+ ":" + padding(date.getMinutes(), 2, '0')
|
||||
+ ":" + padding(date.getSeconds(), 2, '0');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* format absolute seconds to YYYY-mm-dd,
|
||||
* for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 2014-01-08
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||
* @usage absolute_seconds_to_YYYYmmdd(new Date().getTime() / 1000)
|
||||
*/
|
||||
function absolute_seconds_to_YYYYmmdd(seconds) {
|
||||
var date = new Date();
|
||||
date.setTime(Number(seconds) * 1000);
|
||||
|
||||
var ret = date.getFullYear()
|
||||
+ "-" + padding(date.getMonth() + 1, 2, '0')
|
||||
+ "-" + padding(date.getDate(), 2, '0');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse the date in str to Date object.
|
||||
* @param str the date in str, format as "YYYY-mm-dd", for example, 2014-12-11
|
||||
* @returns a date object.
|
||||
* @usage YYYYmmdd_parse("2014-12-11")
|
||||
*/
|
||||
function YYYYmmdd_parse(str) {
|
||||
var date = new Date();
|
||||
date.setTime(Date.parse(str));
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* async refresh function call. to avoid multiple call.
|
||||
* @remark AsyncRefresh is for jquery to refresh the speicified pfn in a page;
|
||||
* if angularjs, use AsyncRefresh2 to change pfn, cancel previous request for angularjs use singleton object.
|
||||
* @param refresh_interval the default refresh interval ms.
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||
* the pfn can be implements as following:
|
||||
var async_refresh = new AsyncRefresh(pfn, 3000);
|
||||
function pfn() {
|
||||
if (!async_refresh.refresh_is_enabled()) {
|
||||
async_refresh.request(100);
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
type: 'GET', async: true, url: 'xxxxx',
|
||||
complete: function(){
|
||||
if (!async_refresh.refresh_is_enabled()) {
|
||||
async_refresh.request(0);
|
||||
} else {
|
||||
async_refresh.request(async_refresh.refresh_interval);
|
||||
}
|
||||
},
|
||||
success: function(res){
|
||||
// if donot allow refresh, directly return.
|
||||
if (!async_refresh.refresh_is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// render the res.
|
||||
}
|
||||
});
|
||||
}
|
||||
*/
|
||||
function AsyncRefresh(pfn, refresh_interval) {
|
||||
this.refresh_interval = refresh_interval;
|
||||
|
||||
this.__handler = null;
|
||||
this.__pfn = pfn;
|
||||
|
||||
this.__enabled = true;
|
||||
}
|
||||
/**
|
||||
* disable the refresher, the pfn must check the refresh state.
|
||||
*/
|
||||
AsyncRefresh.prototype.refresh_disable = function() {
|
||||
this.__enabled = false;
|
||||
}
|
||||
AsyncRefresh.prototype.refresh_enable = function() {
|
||||
this.__enabled = true;
|
||||
}
|
||||
AsyncRefresh.prototype.refresh_is_enabled = function() {
|
||||
return this.__enabled;
|
||||
}
|
||||
/**
|
||||
* start new async request
|
||||
* @param timeout the timeout in ms.
|
||||
* user can use the refresh_interval of the AsyncRefresh object,
|
||||
* which initialized in constructor.
|
||||
*/
|
||||
AsyncRefresh.prototype.request = function(timeout) {
|
||||
if (this.__handler) {
|
||||
clearTimeout(this.__handler);
|
||||
}
|
||||
|
||||
this.__handler = setTimeout(this.__pfn, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* async refresh v2, support cancellable refresh, and change the refresh pfn.
|
||||
* @remakr for angularjs. if user only need jquery, maybe AsyncRefresh is better.
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17994347
|
||||
* Usage:
|
||||
bsmControllers.controller('CServers', ['$scope', 'MServer', function($scope, MServer){
|
||||
async_refresh2.refresh_change(function(){
|
||||
// 获取服务器列表
|
||||
MServer.servers_load({}, function(data){
|
||||
$scope.servers = data.data.servers;
|
||||
async_refresh2.request();
|
||||
});
|
||||
}, 3000);
|
||||
|
||||
async_refresh2.request(0);
|
||||
}]);
|
||||
bsmControllers.controller('CStreams', ['$scope', 'MStream', function($scope, MStream){
|
||||
async_refresh2.refresh_change(function(){
|
||||
// 获取流列表
|
||||
MStream.streams_load({}, function(data){
|
||||
$scope.streams = data.data.streams;
|
||||
async_refresh2.request();
|
||||
});
|
||||
}, 3000);
|
||||
|
||||
async_refresh2.request(0);
|
||||
}]);
|
||||
*/
|
||||
function AsyncRefresh2() {
|
||||
/**
|
||||
* the function callback before call the pfn.
|
||||
* the protype is function():bool, which return true to invoke, false to abort the call.
|
||||
* null to ignore this callback.
|
||||
*
|
||||
* for example, user can abort the refresh by find the class popover:
|
||||
* async_refresh2.on_before_call_pfn = function() {
|
||||
* if ($(".popover").length > 0) {
|
||||
* async_refresh2.request();
|
||||
* return false;
|
||||
* }
|
||||
* return true;
|
||||
* };
|
||||
*/
|
||||
this.on_before_call_pfn = null;
|
||||
|
||||
// use a anonymous function to call, and check the enabled when actually invoke.
|
||||
this.__call = {
|
||||
pfn: null,
|
||||
timeout: 0,
|
||||
__enabled: false,
|
||||
__handler: null
|
||||
};
|
||||
}
|
||||
// singleton
|
||||
var async_refresh2 = new AsyncRefresh2();
|
||||
/**
|
||||
* initialize or refresh change. cancel previous request, setup new request.
|
||||
* @param pfn a function():void to request after timeout. null to disable refresher.
|
||||
* @param timeout the timeout in ms, to call pfn. null to disable refresher.
|
||||
*/
|
||||
AsyncRefresh2.prototype.initialize = function(pfn, timeout) {
|
||||
this.refresh_change(pfn, timeout);
|
||||
}
|
||||
/**
|
||||
* stop refresh, the refresh pfn is set to null.
|
||||
*/
|
||||
AsyncRefresh2.prototype.stop = function() {
|
||||
this.__call.__enabled = false;
|
||||
}
|
||||
/**
|
||||
* restart refresh, use previous config.
|
||||
*/
|
||||
AsyncRefresh2.prototype.restart = function() {
|
||||
this.__call.__enabled = true;
|
||||
this.request(0);
|
||||
}
|
||||
/**
|
||||
* change refresh pfn, the old pfn will set to disabled.
|
||||
*/
|
||||
AsyncRefresh2.prototype.refresh_change = function(pfn, timeout) {
|
||||
// cancel the previous call.
|
||||
if (this.__call.__handler) {
|
||||
clearTimeout(this.__handler);
|
||||
}
|
||||
this.__call.__enabled = false;
|
||||
|
||||
// setup new call.
|
||||
this.__call = {
|
||||
pfn: pfn,
|
||||
timeout: timeout,
|
||||
__enabled: true,
|
||||
__handler: null
|
||||
};
|
||||
}
|
||||
/**
|
||||
* start new request, we never auto start the request,
|
||||
* user must start new request when previous completed.
|
||||
* @param timeout [optional] if not specified, use the timeout in initialize or refresh_change.
|
||||
*/
|
||||
AsyncRefresh2.prototype.request = function(timeout) {
|
||||
var self = this;
|
||||
var this_call = this.__call;
|
||||
|
||||
// clear previous timeout.
|
||||
if (this_call.__handler) {
|
||||
clearTimeout(this_call.__handler);
|
||||
}
|
||||
|
||||
// override the timeout
|
||||
if (timeout == undefined) {
|
||||
timeout = this_call.timeout;
|
||||
}
|
||||
|
||||
// if user disabled refresher.
|
||||
if (this_call.pfn == null || timeout == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this_call.__handler = setTimeout(function(){
|
||||
// cancelled by refresh_change, ignore.
|
||||
if (!this_call.__enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// callback if the handler installled.
|
||||
if (self.on_before_call_pfn) {
|
||||
if (!self.on_before_call_pfn()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// do the actual call.
|
||||
this_call.pfn();
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
// other components.
|
||||
/**
|
||||
* jquery/bootstrap pager.
|
||||
* depends: jquery1.10, boostrap2
|
||||
* https://code.csdn.net/snippets/146160
|
||||
* @see: http://blog.csdn.net/win_lin/article/details/17628631
|
||||
*/
|
|
@ -1,149 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="js/srs.log.js"></script>
|
||||
<script type="text/javascript" src="js/srs.player.js"></script>
|
||||
<script type="text/javascript" src="js/srs.publisher.js"></script>
|
||||
<script type="text/javascript" src="js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="js/winlin.utility.js"></script>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
#main_modal {
|
||||
width: 700px;
|
||||
margin-left: -350px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="js/jwplayer.js" ></script>
|
||||
<script type='text/javascript'>jwplayer.key = 'N8zhkmYvvRwOhz4aTGkySoEri4x+9pQwR7GHIQ=='; </script>
|
||||
<script type="text/javascript">
|
||||
/****
|
||||
* The parameters for this page:
|
||||
* schema, the protocol schema, rtmp or http.
|
||||
* server, the ip of the url.
|
||||
* port, the rtmp port of url.
|
||||
* vhost, the vhost of url, can equals to server.
|
||||
* app, the app of url.
|
||||
* stream, the stream of url, can endwith .flv or .mp4 or nothing for RTMP.
|
||||
* autostart, whether auto play the stream.
|
||||
* Additional params:
|
||||
* hls_vhost, the vhost for hls.
|
||||
* hls_port, the port for hls play.
|
||||
* hls_autostart, whether auto play the hls stream.
|
||||
*/
|
||||
var _player = null;
|
||||
var _url = null;
|
||||
$(function(){
|
||||
// get the vhost and port to set the default url.
|
||||
// for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
|
||||
// url set to: rtmp://demo:1935/live/livestream
|
||||
srs_init("#txt_rtmp_url", "#txt_hls_url", "#main_modal");
|
||||
|
||||
$("#main_modal").on("hide", function(){
|
||||
$("#div_container").remove();
|
||||
_player.stop();
|
||||
});
|
||||
|
||||
$("#main_modal").on("show", function(){
|
||||
$("#div_container").remove();
|
||||
|
||||
var div_container = $("<div/>");
|
||||
$(div_container).attr("id", "div_container");
|
||||
$("#player").append(div_container);
|
||||
|
||||
var player = $("<div/>");
|
||||
$(player).attr("id", "player_id");
|
||||
$(div_container).append(player);
|
||||
|
||||
var conf = {
|
||||
file: _url,
|
||||
width: srs_get_player_width(),
|
||||
height: srs_get_player_height(),
|
||||
autostart: true,
|
||||
analytics: { enabled: false}
|
||||
};
|
||||
_player = jwplayer('player_id').setup(conf);
|
||||
});
|
||||
|
||||
$("#btn_play_rtmp").click(function(){
|
||||
_url = $("#txt_rtmp_url").val();
|
||||
$("#main_modal").modal({show:true, keyboard:false});
|
||||
});
|
||||
|
||||
$("#btn_play_hls").click(function(){
|
||||
_url = $("#txt_hls_url").val();
|
||||
$("#main_modal").modal({show:true, keyboard:false});
|
||||
});
|
||||
|
||||
var query = parse_query_string();
|
||||
if (query.hls_autostart == "true") {
|
||||
_url = $("#txt_hls_url").val();
|
||||
$("#main_modal").modal({show:true, keyboard:false});
|
||||
} else if (query.rtmp_autostart == "true") {
|
||||
_url = $("#txt_rtmp_url").val();
|
||||
$("#main_modal").modal({show:true, keyboard:false});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/jwplayer'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a id="srs_index" class="brand" href="#">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<li class="active"><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
|
||||
<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="alert alert-info fade in">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><span>Usage:</span></strong> <span>输入地址后点击播放按钮</span>
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
URL:
|
||||
<input type="text" id="txt_rtmp_url" class="input-xxlarge" value=""></input>
|
||||
<button class="btn btn-primary" id="btn_play_rtmp">播放RTMP</button>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="form-inline">
|
||||
URL:
|
||||
<input type="text" id="txt_hls_url" class="input-xxlarge" value=""></input>
|
||||
<button class="btn btn-primary" id="btn_play_hls"> 播放HLS </button>
|
||||
</div>
|
||||
<div id="main_modal" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>JWPlayer6</h3>
|
||||
</div>
|
||||
<div class="modal-body" id="player">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true"> 关闭 </button>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<footer>
|
||||
<p><a href="https://github.com/ossrs/srs">SRS Team © 2013</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
setTimeout(function(){
|
||||
window.location.href = "players/index.html" + window.location.search;
|
||||
}, 500);
|
||||
</script>
|
||||
</html>
|
|
@ -1,125 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
#main_modal {
|
||||
width: 700px;
|
||||
margin-left: -350px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/osmf'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a id="srs_index" class="brand" href="#">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
|
||||
<li class="active"><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="alert alert-info fade in">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><span>Usage:</span></strong> <span>输入地址后点击播放按钮</span>
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
URL:
|
||||
<input type="text" id="txt_url" class="input-xxlarge" value=""></input>
|
||||
<button class="btn btn-primary" id="btn_play">播放视频</button>
|
||||
</div>
|
||||
<div id="main_modal" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>AdobeOSMF</h3>
|
||||
</div>
|
||||
<div class="modal-body" id="player">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true"> 关闭 </button>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<footer>
|
||||
<p><a href="https://github.com/ossrs/srs">SRS Team © 2013</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||
<script type="text/javascript" src="js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="js/srs.log.js"></script>
|
||||
<script type="text/javascript" src="js/srs.player.js"></script>
|
||||
<script type="text/javascript" src="js/srs.publisher.js"></script>
|
||||
<script type="text/javascript" src="js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="js/winlin.utility.js"></script>
|
||||
<script type="text/javascript">
|
||||
function osmf_play(url) {
|
||||
$("#div_container").remove();
|
||||
|
||||
var div_container = $("<div/>");
|
||||
$(div_container).attr("id", "div_container");
|
||||
$("#player").append(div_container);
|
||||
|
||||
var player = $("<div/>");
|
||||
$(player).attr("id", "player_id");
|
||||
$(div_container).append(player);
|
||||
|
||||
var flashvars = {};
|
||||
flashvars.src = url;
|
||||
flashvars.streamType = "live"; // live or recorded
|
||||
flashvars.autoPlay = true;
|
||||
flashvars.controlBarAutoHide = false;
|
||||
flashvars.scaleMode = "stretch";
|
||||
flashvars.bufferTime = 0.8;
|
||||
|
||||
var params = {};
|
||||
params.allowFullScreen = true;
|
||||
|
||||
var attributes = {};
|
||||
|
||||
swfobject.embedSWF(
|
||||
"js/StrobeMediaPlayback.swf", "player_id",
|
||||
srs_get_player_width(), srs_get_player_height(),
|
||||
"11.1", "js/AdobeFlashPlayerInstall.swf",
|
||||
flashvars, params, attributes
|
||||
);
|
||||
}
|
||||
$(function(){
|
||||
// get the vhost and port to set the default url.
|
||||
// for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
|
||||
// url set to: rtmp://demo:1935/live/livestream
|
||||
srs_init_rtmp("#txt_url", "#main_modal");
|
||||
|
||||
$("#main_modal").on("hide", function(){
|
||||
osmf_play("http://localhost");
|
||||
$("#div_container").remove();
|
||||
});
|
||||
$("#main_modal").on("show", function(){
|
||||
var url = $("#txt_url").val();
|
||||
osmf_play(url);
|
||||
});
|
||||
|
||||
$("#btn_play").click(function(){
|
||||
$("#main_modal").modal({show:true, keyboard:false});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -1,18 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
<script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="players/js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="players/js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="players/js/winlin.utility.js"></script>
|
||||
<script type="text/javascript">
|
||||
setTimeout(function(){
|
||||
window.location.href = "players/index.html" + window.location.search;
|
||||
}, 500);
|
||||
</script>
|
||||
</html>
|
|
@ -1,204 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
#main_modal {
|
||||
width: 700px;
|
||||
margin-left: -350px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/bwt'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a id="srs_index" class="brand" href="#">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li class="active"><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div name="detect_flash">
|
||||
<div id="main_flash_alert" class="alert alert-danger fade in hide">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><p>Usage:</p></strong>
|
||||
<p>
|
||||
请点击下面的图标,启用Flash
|
||||
</p>
|
||||
<p>
|
||||
若没有见到这个图标,Chrome浏览器请打开
|
||||
<span class="text-info">chrome://settings/content/flash</span> 并修改为"Ask first"。
|
||||
</p>
|
||||
</div>
|
||||
<div id="main_flash_hdr" class="hide">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main_content" class="hide">
|
||||
<div class="alert alert-info fade in">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><span>Usage:</span></strong> <span>点击“开始测速”即可测带宽,最大可测试带宽由服务器限制</span>
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
URL:
|
||||
<input type="text" id="txt_url" class="input-xxlarge" value=""></input>
|
||||
<button class="btn btn-primary" id="btn_play">开始测速</button>
|
||||
</div>
|
||||
<div id="main_modal" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>SRS Bandwidth Check</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row-fluid">
|
||||
<div class="span1"></div>
|
||||
<div class="span10">
|
||||
<div class="progress progress-striped active" id="pb_buffer_bg">
|
||||
<div class="bar" style="width: 0%;" id="progress_bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span1"></div>
|
||||
</div>
|
||||
<div id="check_status">status</div>
|
||||
<div id="check_info">info</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true"> 关闭 </button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p></p>
|
||||
<p><a href="https://github.com/ossrs/srs">SRS Team © 2013</a></p>
|
||||
</footer>
|
||||
<div class="container">
|
||||
<div id="player"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||
<script type="text/javascript" src="js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="js/srs.log.js"></script>
|
||||
<script type="text/javascript" src="js/srs.player.js"></script>
|
||||
<script type="text/javascript" src="js/srs.publisher.js"></script>
|
||||
<script type="text/javascript" src="js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="js/winlin.utility.js"></script>
|
||||
<script type="text/javascript" src="srs_bwt/src/srs.bandwidth.js"></script>
|
||||
<script type="text/javascript">
|
||||
var __on_flash_ready = null;
|
||||
|
||||
$(function(){
|
||||
// 探测Flash是否正常启用。
|
||||
$('#main_flash_hdr').html(
|
||||
'\
|
||||
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="100%" height="100%"> \
|
||||
<param name="movie" value="srs_player/release/srs_player.swf"> \
|
||||
<param name="quality" value="autohigh"> \
|
||||
<param name="swliveconnect" value="true"> \
|
||||
<param name="allowScriptAccess" value="always"> \
|
||||
<param name="bgcolor" value="#0"> \
|
||||
<param name="allowFullScreen" value="true"> \
|
||||
<param name="wmode" value="opaque"> \
|
||||
<param name="FlashVars" value="log=1"> \
|
||||
<param name="flashvars" value="id=1&on_player_ready=__on_flash_ready"> \
|
||||
<embed src="srs_player/release/srs_player.swf" width="100%" height="100%" \
|
||||
quality="autohigh" bgcolor="#0" align="middle" allowfullscreen="true" allowscriptaccess="always" \
|
||||
type="application/x-shockwave-flash" swliveconnect="true" wmode="opaque" \
|
||||
flashvars="id=1&on_player_ready=__on_flash_ready" \
|
||||
pluginspage="http://www.macromedia.com/go/getflashplayer"> \
|
||||
</object> \
|
||||
'
|
||||
);
|
||||
$('#main_flash_hdr').show();
|
||||
|
||||
var showFlashHdr = setTimeout(function(){
|
||||
$('#main_flash_alert').show();
|
||||
}, 300);
|
||||
|
||||
__on_flash_ready = function (id) {
|
||||
clearTimeout(showFlashHdr);
|
||||
|
||||
$('#main_flash_alert').hide();
|
||||
$('#main_flash_hdr').hide();
|
||||
$('#main_content').show();
|
||||
|
||||
autoLoadPage();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var bandwidth = null;
|
||||
|
||||
var autoLoadPage = function() {
|
||||
srs_init_bwt("#txt_url");
|
||||
|
||||
$("#btn_play").click(on_click_play);
|
||||
$("#main_modal").on("show", on_start_bandwidth_test);
|
||||
$("#main_modal").on("hide", on_stop_bandwidth_test);
|
||||
};
|
||||
|
||||
function on_click_play() {
|
||||
$("#check_status").text("");
|
||||
$("#check_info").text("");
|
||||
$("#progress_bar").width("0%");
|
||||
$("#main_modal").modal({show:true, keyboard:false});
|
||||
}
|
||||
function on_start_bandwidth_test() {
|
||||
$("#div_container").remove();
|
||||
$("#progress_bar").removeClass("bar-danger");
|
||||
|
||||
var div_container = $("<div/>");
|
||||
$(div_container).attr("id", "div_container");
|
||||
$("#player").append(div_container);
|
||||
|
||||
var player = $("<div/>");
|
||||
$(player).attr("id", "player_id");
|
||||
$(div_container).append(player);
|
||||
|
||||
var url = $("#txt_url").val();
|
||||
|
||||
bandwidth = new SrsBandwidth("player_id", 100, 1);
|
||||
bandwidth.on_bandwidth_ready = function() {
|
||||
this.check_bandwidth(url);
|
||||
}
|
||||
bandwidth.on_update_progress = function(percent) {
|
||||
$("#progress_bar").width(percent + "%");
|
||||
}
|
||||
bandwidth.on_update_status = function(status) {
|
||||
$("#check_status").text(status);
|
||||
}
|
||||
bandwidth.on_srs_info = function(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip) {
|
||||
$("#check_info").text(
|
||||
"server:" + srs_server + ", srs_id:" + srs_id + ", srs_pid:" + srs_pid + ", ip:" + srs_server_ip
|
||||
);
|
||||
}
|
||||
bandwidth.on_error = function(code) {
|
||||
$("#progress_bar").addClass("bar-danger");
|
||||
}
|
||||
bandwidth.render(url);
|
||||
}
|
||||
function on_stop_bandwidth_test() {
|
||||
bandwidth.stop();
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -1,41 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<actionScriptProperties analytics="false" mainApplicationPath="srs_bwt.as" projectUUID="00251213-e6a2-4dd5-a033-125cc78f843c" version="10">
|
||||
<compiler additionalCompilerArguments="-locale en_US" autoRSLOrdering="true" copyDependentFiles="false" fteInMXComponents="false" generateAccessible="true" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="true" htmlPlayerVersionCheck="true" includeNetmonSwc="false" outputFolderPath="release" removeUnusedRSL="true" sourceFolderPath="src" strict="true" targetPlayerVersion="0.0.0" useApolloConfig="false" useDebugRSLSwfs="true" verifyDigests="true" warn="true">
|
||||
<compilerSourcePath/>
|
||||
<libraryPath defaultLinkType="0">
|
||||
<libraryPathEntry kind="4" path="">
|
||||
<excludedEntries>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_charts.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="1" linkType="1" path="${PROJECT_FRAMEWORKS}/locale/{locale}"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/advancedgrids.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_air.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/charts.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/framework.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/mx/mx.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/netmon.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/sparkskins.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/rpc.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/datavisualization.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp_air.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/videoPlayer.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flash-integration.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_flashflexkit.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_agent.swc" useDefaultLinkType="false"/>
|
||||
</excludedEntries>
|
||||
</libraryPathEntry>
|
||||
</libraryPath>
|
||||
<sourceAttachmentPath/>
|
||||
</compiler>
|
||||
<applications>
|
||||
<application path="srs_bwt.as"/>
|
||||
</applications>
|
||||
<modules/>
|
||||
<buildCSSFiles/>
|
||||
<flashCatalyst validateFlashCatalystCompatibility="false"/>
|
||||
</actionScriptProperties>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>srs_bwt</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.adobe.flexbuilder.project.flexbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
Binary file not shown.
|
@ -1,593 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2016 SRS(ossrs)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package
|
||||
{
|
||||
import flash.events.NetStatusEvent;
|
||||
import flash.external.ExternalInterface;
|
||||
import flash.net.NetConnection;
|
||||
import flash.net.NetStream;
|
||||
import flash.net.ObjectEncoding;
|
||||
import flash.utils.clearTimeout;
|
||||
import flash.utils.setTimeout;
|
||||
|
||||
/**
|
||||
* SRS bandwidth check/test library,
|
||||
* user can copy this file and use it directly,
|
||||
* this library will export as callback functions, and js callback functions.
|
||||
*
|
||||
* Usage:
|
||||
* var bandwidth:SrsBandwidth = new SrsBandwidth();
|
||||
* bandwidth.initialize(......); // required
|
||||
* bandwidth.check_bandwidth(......); // required
|
||||
* bandwidth.stop(); // optional
|
||||
*
|
||||
* @remark we donot use event, but use callback functions set by initialize.
|
||||
*/
|
||||
public class SrsBandwidth
|
||||
{
|
||||
/**
|
||||
* server notice client to do the downloading/play bandwidth test.
|
||||
*/
|
||||
public static const StatusSrsBwtcPlayStart:String = "srs.bwtc.play.start";
|
||||
/**
|
||||
* server notice client to complete the downloading/play bandwidth test.
|
||||
*/
|
||||
public static const StatusSrsBwtcPlayStop:String = "srs.bwtc.play.stop";
|
||||
/**
|
||||
* server notice client to do the uploading/publish bandwidth test.
|
||||
*/
|
||||
public static const StatusSrsBwtcPublishStart:String = "srs.bwtc.publish.start";
|
||||
/**
|
||||
* server notice client to complete the uploading/publish bandwidth test.
|
||||
*/
|
||||
public static const StatusSrsBwtcPublishStop:String = "srs.bwtc.publish.stop";
|
||||
|
||||
/**
|
||||
* constructor, do nothing
|
||||
*/
|
||||
public function SrsBandwidth()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize the bandwidth test tool, the callbacks. null to ignore.
|
||||
*
|
||||
* the as callbacks.
|
||||
* @param as_on_ready, function():void, callback when bandwidth tool is ready to run.
|
||||
* @param as_on_status_change, function(code:String, data:String):void, where:
|
||||
* code can be:
|
||||
* "NetConnection.Connect.Failed", see NetStatusEvent(evt.info.code).
|
||||
* "NetConnection.Connect.Rejected", see NetStatusEvent(evt.info.code).
|
||||
* "NetConnection.Connect.Success", see NetStatusEvent(evt.info.code).
|
||||
* "NetConnection.Connect.Closed", see NetStatusEvent(evt.info.code).
|
||||
* SrsBandwidth.StatusSrsBwtcPlayStart, "srs.bwtc.play.start", when srs start test play bandwidth.
|
||||
* SrsBandwidth.StatusSrsBwtcPlayStop, "srs.bwtc.play.stop", when srs complete test play bandwidth.
|
||||
* SrsBandwidth.StatusSrsBwtcPublishStart, "srs.bwtc.publish.start", when srs start test publish bandwidth.
|
||||
* SrsBandwidth.StatusSrsBwtcPublishStop, "srs.bwtc.publish.stop", when srs complete test publish bandwidth.
|
||||
* data is extra parameter:
|
||||
* kbps, for code is SrsBandwidth.StatusSrsBwtcPlayStop or SrsBandwidth.StatusSrsBwtcPublishStop.
|
||||
* "", otherwise empty string.
|
||||
* @param as_on_progress_change, function(percent:Number):void, where:
|
||||
* percent, the progress percent, 0 means 0%, 100 means 100%.
|
||||
* @param as_on_srs_info, function(srs_server:String, srs_primary:String, srs_authors:String, srs_id:String, srs_pid:String, srs_server_ip:String):void, where:
|
||||
* srs_server: the srs server info.
|
||||
* srs_primary: the srs primary authors info.
|
||||
* srs_authors: the srs authors info.
|
||||
* srs_id: the tracable log id, to direclty grep the log.
|
||||
* srs_pid: the srs process id, to direclty grep the log.
|
||||
* srs_server_ip: the srs server ip, where client connected at.
|
||||
* @param as_on_complete, function(start_time:Number, end_time:Number, play_kbps:Number, publish_kbps:Number, play_bytes:Number, publish_bytes:Number, play_time:Number, publish_time:Number):void, where
|
||||
* start_time, the start timestamp, in ms.
|
||||
* end_time, the finish timestamp, in ms.
|
||||
* play_kbps, the play/downloading kbps.
|
||||
* publish_kbps, the publish/uploading kbps.
|
||||
* play_bytes, the bytes play/download from server, in bytes.
|
||||
* publish_bytes, the bytes publish/upload to server, in bytes.
|
||||
* play_time, the play/download duration time, in ms.
|
||||
* publish_time, the publish/upload duration time, in ms.
|
||||
*
|
||||
* the js callback id.
|
||||
* @param js_id, specifies the id of swfobject, used to identify the bandwidth object.
|
||||
* for all js callback, the first param always be the js_id, to identify the callback object.
|
||||
*
|
||||
* the js callbacks.
|
||||
* @param js_on_ready, function(js_id:String):void, callback when bandwidth tool is ready to run.
|
||||
* @param js_on_status_change, function(js_id:String, code:String, data:String):void
|
||||
* @param as_on_progress_change, function(js_id:String, percent:Number):void
|
||||
* @param as_on_srs_info, function(js_id:String, srs_server:String, srs_primary:String, srs_authors:String, srs_id:String, srs_pid:String, srs_server_ip:String):void
|
||||
* @param as_on_complete, function(js_id:String, start_time:Number, end_time:Number, play_kbps:Number, publish_kbps:Number, play_bytes:Number, publish_bytes:Number, play_time:Number, publish_time:Number):void
|
||||
*
|
||||
* the js export functions.
|
||||
* @param js_export_check_bandwidth, function(url:String):void, for js to start bandwidth check, @see: check_bandwidth(url:String):void
|
||||
* @param js_export_stop, function():void, for js to stop bandwidth check, @see: stop():void
|
||||
*
|
||||
* @remark, all parameters can be null.
|
||||
* @remark, as and js callback use same parameter, except that the js calblack first parameter is js_id:String.
|
||||
*/
|
||||
public function initialize(
|
||||
as_on_ready:Function, as_on_status_change:Function, as_on_progress_change:Function, as_on_srs_info:Function, as_on_complete:Function,
|
||||
js_id:String, js_on_ready:String, js_on_status_change:String, js_on_progress_change:String, js_on_srs_info:String, js_on_complete:String,
|
||||
js_export_check_bandwidth:String, js_export_stop:String
|
||||
):void {
|
||||
this.as_on_ready = as_on_ready;
|
||||
this.as_on_srs_info = as_on_srs_info;
|
||||
this.as_on_status_change = as_on_status_change;
|
||||
this.as_on_progress_change = as_on_progress_change;
|
||||
this.as_on_complete = as_on_complete;
|
||||
|
||||
this.js_id = js_id;
|
||||
this.js_on_srs_info = js_on_srs_info;
|
||||
this.js_on_ready = js_on_ready;
|
||||
this.js_on_status_change = js_on_status_change;
|
||||
this.js_on_progress_change = js_on_progress_change;
|
||||
this.js_on_complete = js_on_complete;
|
||||
|
||||
this.js_export_check_bandwidth = js_export_check_bandwidth;
|
||||
this.js_export_stop = js_export_stop;
|
||||
|
||||
flash.utils.setTimeout(this.system_on_js_ready, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* start check bandwidth.
|
||||
* @param url, a String indicates the url to check bandwidth,
|
||||
* format as: rtmp://server:port/app?key=xxx&&vhost=xxx
|
||||
* for example, rtmp://dev:1935/app?key=35c9b402c12a7246868752e2878f7e0e&vhost=bandcheck.srs.com
|
||||
* where the key and vhost must be config in SRS, like:
|
||||
* vhost bandcheck.srs.com {
|
||||
* enabled on;
|
||||
* chunk_size 65000;
|
||||
* bandcheck {
|
||||
* enabled on;
|
||||
* key "35c9b402c12a7246868752e2878f7e0e";
|
||||
* interval 30;
|
||||
* limit_kbps 4000;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @remark user must invoke this as method, or js exported method.
|
||||
*/
|
||||
public function check_bandwidth(url:String):void {
|
||||
this.js_call_check_bandwidth(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* stop check bancwidth.
|
||||
* @remark it's optional, however, user can abort the bandwidth check.
|
||||
*/
|
||||
public function stop():void {
|
||||
this.js_call_stop();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////// ///////////////////////////////
|
||||
////////////////////////// ///////////////////////////////
|
||||
////////////////////////// ///////////////////////////////
|
||||
////////////////////////// ///////////////////////////////
|
||||
////////////////////////// Private Section, ignore please. ///////////////////////////////
|
||||
////////////////////////// ///////////////////////////////
|
||||
////////////////////////// ///////////////////////////////
|
||||
////////////////////////// ///////////////////////////////
|
||||
////////////////////////// ///////////////////////////////
|
||||
////////////////////////// ///////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* ***********************************************************************
|
||||
* private section, including private fields, method and embeded classes.
|
||||
* ***********************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* as callback.
|
||||
*/
|
||||
private var as_on_ready:Function;
|
||||
private var as_on_srs_info:Function;
|
||||
private var as_on_status_change:Function;
|
||||
private var as_on_progress_change:Function;
|
||||
private var as_on_complete:Function;
|
||||
|
||||
/**
|
||||
* js callback.
|
||||
*/
|
||||
private var js_id:String;
|
||||
private var js_on_ready:String;
|
||||
private var js_on_srs_info:String;
|
||||
private var js_on_status_change:String;
|
||||
private var js_on_progress_change:String;
|
||||
private var js_on_complete:String;
|
||||
|
||||
/**
|
||||
* js export functions.
|
||||
*/
|
||||
private var js_export_check_bandwidth:String;
|
||||
private var js_export_stop:String;
|
||||
|
||||
/**
|
||||
* srs debug infos
|
||||
*/
|
||||
private var srs_server:String = null;
|
||||
private var srs_primary:String = null;
|
||||
private var srs_authors:String = null;
|
||||
private var srs_id:String = null;
|
||||
private var srs_pid:String = null;
|
||||
private var srs_server_ip:String = null;
|
||||
|
||||
/**
|
||||
* the underlayer connection, to send call message to do the bandwidth
|
||||
* check/test with server.
|
||||
*/
|
||||
private var connection:NetConnection = null;
|
||||
// for bms4, use stream to play then do bandwidth test.
|
||||
private var stream:NetStream = null;
|
||||
|
||||
/**
|
||||
* use timeout to sendout publish call packets.
|
||||
* when got stop publish packet from server, stop publish call loop.
|
||||
*/
|
||||
private var publish_timeout_handler:uint = 0;
|
||||
|
||||
/**
|
||||
* system callack event, when js ready, register callback for js.
|
||||
* the actual main function.
|
||||
*/
|
||||
private function system_on_js_ready():void {
|
||||
if (!flash.external.ExternalInterface.available) {
|
||||
log("js not ready, try later.");
|
||||
flash.utils.setTimeout(this.system_on_js_ready, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.js_export_check_bandwidth != null) {
|
||||
flash.external.ExternalInterface.addCallback(this.js_export_check_bandwidth, this.js_call_check_bandwidth);
|
||||
}
|
||||
if (this.js_export_stop != null) {
|
||||
flash.external.ExternalInterface.addCallback(this.js_export_stop, this.js_call_stop);
|
||||
}
|
||||
|
||||
if (as_on_ready != null) {
|
||||
as_on_ready();
|
||||
}
|
||||
if (js_on_ready != null) {
|
||||
flash.external.ExternalInterface.call(this.js_on_ready, this.js_id);
|
||||
}
|
||||
}
|
||||
private function js_call_check_bandwidth(url:String):void {
|
||||
js_call_stop();
|
||||
|
||||
__on_progress_change(0);
|
||||
|
||||
// init connection
|
||||
log("create connection for bandwidth check");
|
||||
connection = new NetConnection;
|
||||
connection.objectEncoding = ObjectEncoding.AMF0;
|
||||
connection.client = {
|
||||
onStatus: onStatus,
|
||||
// play
|
||||
onSrsBandCheckStartPlayBytes: onSrsBandCheckStartPlayBytes,
|
||||
onSrsBandCheckPlaying: onSrsBandCheckPlaying,
|
||||
onSrsBandCheckStopPlayBytes: onSrsBandCheckStopPlayBytes,
|
||||
// publish
|
||||
onSrsBandCheckStartPublishBytes: onSrsBandCheckStartPublishBytes,
|
||||
onSrsBandCheckStopPublishBytes: onSrsBandCheckStopPublishBytes,
|
||||
onSrsBandCheckFinished: onSrsBandCheckFinished
|
||||
};
|
||||
connection.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
|
||||
connection.connect(url);
|
||||
|
||||
__on_progress_change(3);
|
||||
}
|
||||
private function js_call_stop():void {
|
||||
if (connection) {
|
||||
connection.close();
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NetConnection callback this function, when recv server call "onSrsBandCheckStartPlayBytes"
|
||||
* then start @updatePlayProgressTimer for updating the progressbar
|
||||
* */
|
||||
private function onSrsBandCheckStartPlayBytes(evt:Object):void{
|
||||
var duration_ms:Number = evt.duration_ms;
|
||||
var interval_ms:Number = evt.interval_ms;
|
||||
log("start play test, duration=" + duration_ms + ", interval=" + interval_ms);
|
||||
|
||||
connection.call("onSrsBandCheckStartingPlayBytes", null);
|
||||
__on_status_change(SrsBandwidth.StatusSrsBwtcPlayStart);
|
||||
|
||||
__on_progress_change(10);
|
||||
}
|
||||
private function onSrsBandCheckPlaying(evt:Object):void{
|
||||
}
|
||||
private function onSrsBandCheckStopPlayBytes(evt:Object):void{
|
||||
var duration_ms:Number = evt.duration_ms;
|
||||
var interval_ms:Number = evt.interval_ms;
|
||||
var duration_delta:Number = evt.duration_delta;
|
||||
var bytes_delta:Number = evt.bytes_delta;
|
||||
|
||||
var kbps:Number = 0;
|
||||
if(duration_delta > 0){
|
||||
kbps = bytes_delta * 8.0 / duration_delta; // b/ms == kbps
|
||||
}
|
||||
kbps = (int(kbps * 10))/10.0;
|
||||
|
||||
flash.utils.setTimeout(stopPlayTest, 0);
|
||||
__on_status_change(SrsBandwidth.StatusSrsBwtcPlayStop, String(kbps));
|
||||
|
||||
__on_progress_change(40);
|
||||
}
|
||||
private function stopPlayTest():void{
|
||||
connection.call("onSrsBandCheckStoppedPlayBytes", null);
|
||||
}
|
||||
/**
|
||||
* publishing methods.
|
||||
*/
|
||||
private function onSrsBandCheckStartPublishBytes(evt:Object):void{
|
||||
var duration_ms:Number = evt.duration_ms;
|
||||
var interval_ms:Number = evt.interval_ms;
|
||||
|
||||
connection.call("onSrsBandCheckStartingPublishBytes", null);
|
||||
|
||||
flash.utils.setTimeout(publisher, 0);
|
||||
__on_status_change(SrsBandwidth.StatusSrsBwtcPublishStart);
|
||||
|
||||
__on_progress_change(60);
|
||||
}
|
||||
private function publisher():void{
|
||||
var data:Array = new Array();
|
||||
|
||||
/**
|
||||
* the data size cannot too large, it will increase the test time.
|
||||
* server need atleast got one packet, then timeout to stop the publish.
|
||||
*
|
||||
* cannot too small neither, it will limit the max publish kbps.
|
||||
*
|
||||
* the test values:
|
||||
* test_s test_s
|
||||
* data_size max_publish_kbps (no limit) (limit upload to 5KBps)
|
||||
* 100 2116 6.5 7.3
|
||||
* 200 4071 6.5 7.7
|
||||
* 300 6438 6.5 10.3
|
||||
* 400 9328 6.5 10.2
|
||||
* 500 10377 6.5 10.0
|
||||
* 600 13737 6.5 10.8
|
||||
* 700 15635 6.5 12.0
|
||||
* 800 18103 6.5 14.0
|
||||
* 900 20484 6.5 14.2
|
||||
* 1000 21447 6.5 16.8
|
||||
*/
|
||||
var data_size:int = 900;
|
||||
for(var i:int; i < data_size; i++) {
|
||||
data.push("SrS band check data from client's publishing......");
|
||||
}
|
||||
|
||||
connection.call("onSrsBandCheckPublishing", null, data);
|
||||
|
||||
publish_timeout_handler = flash.utils.setTimeout(publisher, 0);
|
||||
}
|
||||
private function onSrsBandCheckStopPublishBytes(evt:Object):void{
|
||||
var duration_ms:Number = evt.duration_ms;
|
||||
var interval_ms:Number = evt.interval_ms;
|
||||
var duration_delta:Number = evt.duration_delta;
|
||||
var bytes_delta:Number = evt.bytes_delta;
|
||||
|
||||
var kbps:Number = 0;
|
||||
if(duration_delta > 0){
|
||||
kbps = bytes_delta * 8.0 / duration_delta; // b/ms == kbps
|
||||
}
|
||||
kbps = (int(kbps * 10))/10.0;
|
||||
|
||||
stopPublishTest();
|
||||
|
||||
__on_progress_change(90);
|
||||
}
|
||||
private function stopPublishTest():void{
|
||||
// the stop publish response packet can not send out, for the queue is full.
|
||||
//connection.call("onSrsBandCheckStoppedPublishBytes", null);
|
||||
|
||||
// clear the timeout to stop the send loop.
|
||||
if (publish_timeout_handler > 0) {
|
||||
flash.utils.clearTimeout(publish_timeout_handler);
|
||||
publish_timeout_handler = 0;
|
||||
}
|
||||
}
|
||||
private function onSrsBandCheckFinished(evt:Object):void{
|
||||
var start_time:Number = evt.start_time;
|
||||
var end_time:Number = evt.end_time;
|
||||
var play_kbps:Number = evt.play_kbps;
|
||||
var publish_kbps:Number = evt.publish_kbps;
|
||||
var play_bytes:Number = evt.play_bytes;
|
||||
var play_time:Number = evt.play_time;
|
||||
var publish_bytes:Number = evt.publish_bytes;
|
||||
var publish_time:Number = evt.publish_time;
|
||||
|
||||
if (this.as_on_complete != null) {
|
||||
this.as_on_complete(start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time);
|
||||
}
|
||||
if (this.js_on_complete != null) {
|
||||
flash.external.ExternalInterface.call(this.js_on_complete, this.js_id,
|
||||
start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time);
|
||||
}
|
||||
|
||||
__on_progress_change(100);
|
||||
|
||||
// when got finish packet, directly close connection.
|
||||
js_call_stop();
|
||||
|
||||
// the last final packet can not send out, for the queue is full.
|
||||
//connection.call("finalClientPacket", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* get NetConnection NetStatusEvent
|
||||
*/
|
||||
private function onStatus(evt:NetStatusEvent): void {
|
||||
log(evt.info.code);
|
||||
|
||||
var srs_version:String = null;
|
||||
if (evt.info.hasOwnProperty("data") && evt.info.data) {
|
||||
if (evt.info.data.hasOwnProperty("srs_server")) {
|
||||
srs_server = evt.info.data.srs_server;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_primary")) {
|
||||
srs_primary = evt.info.data.srs_primary;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_authors")) {
|
||||
srs_authors = evt.info.data.srs_authors;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_id")) {
|
||||
srs_id = evt.info.data.srs_id;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_pid")) {
|
||||
srs_pid = evt.info.data.srs_pid;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_server_ip")) {
|
||||
srs_server_ip = evt.info.data.srs_server_ip;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_version")) {
|
||||
srs_version = evt.info.data.srs_version;
|
||||
}
|
||||
|
||||
if (this.as_on_srs_info != null) {
|
||||
this.as_on_srs_info(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip);
|
||||
}
|
||||
if (this.js_on_srs_info != null) {
|
||||
flash.external.ExternalInterface.call(this.js_on_srs_info, this.js_id,
|
||||
srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip);
|
||||
}
|
||||
}
|
||||
|
||||
var e:NetStatusEvent = evt;
|
||||
var foo:Function = function():void{
|
||||
var evt:NetStatusEvent = e;
|
||||
if (evt.info.code) {
|
||||
__on_status_change(evt.info.code);
|
||||
}
|
||||
switch(evt.info.code){
|
||||
case "NetConnection.Connect.Success":
|
||||
__on_progress_change(8);
|
||||
break;
|
||||
}
|
||||
};
|
||||
foo();
|
||||
|
||||
// for bms4, play stream to trigger the bandwidth check.
|
||||
if (evt.info.code != "NetConnection.Connect.Success") {
|
||||
return;
|
||||
}
|
||||
if (stream != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var is_bms:Boolean = false;
|
||||
if (srs_server.indexOf("BMS/") == 0 || srs_server.indexOf("UPYUN/") == 0) {
|
||||
is_bms = true;
|
||||
}
|
||||
if (parseInt(srs_version.charAt(0)) >= 4 && is_bms) {
|
||||
stream = new NetStream(connection);
|
||||
stream.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void{
|
||||
log(evt.info.code);
|
||||
|
||||
if (evt.info.code == "NetStream.Play.Start") {
|
||||
}
|
||||
});
|
||||
stream.play("test");
|
||||
log("play stream for " + srs_server + " " + srs_version);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* invoke the callback.
|
||||
*/
|
||||
private function __on_progress_change(percent:Number):void {
|
||||
if (this.as_on_progress_change != null) {
|
||||
this.as_on_progress_change(percent);
|
||||
}
|
||||
if (this.js_on_progress_change != null) {
|
||||
flash.external.ExternalInterface.call(this.js_on_progress_change, this.js_id,
|
||||
percent);
|
||||
}
|
||||
}
|
||||
private function __on_status_change(code:String, data:String=""):void {
|
||||
if (this.as_on_status_change != null) {
|
||||
this.as_on_status_change(code, data);
|
||||
}
|
||||
if (this.js_on_status_change != null) {
|
||||
flash.external.ExternalInterface.call(this.js_on_status_change, this.js_id,
|
||||
code, data);
|
||||
}
|
||||
}
|
||||
|
||||
private function log(msg:String):void {
|
||||
trace(msg);
|
||||
if (ExternalInterface.available) {
|
||||
ExternalInterface.call("console.log", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2016 SRS(ossrs)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* the SrsBandwidth library for js to do bandwidth test.
|
||||
* @param container the html container id.
|
||||
* @param width a float value specifies the width of bandwidth.
|
||||
* @param height a float value specifies the height of bandwidth.
|
||||
* @param private_object [optional] an object that used as private object,
|
||||
* for example, the logic chat object which owner this bandwidth.
|
||||
* Usage:
|
||||
var bandwidth = new SrsBandwidth("container_id", 100, 1);
|
||||
bandwidth.on_bandwidth_ready = function() {
|
||||
// auto start check bandwidth when tool is ready.
|
||||
this.check_bandwidth(url);
|
||||
}
|
||||
bandwidth.on_update_progress = function(percent) {
|
||||
// console.log(percent + "%");
|
||||
}
|
||||
bandwidth.on_update_status = function(status) {
|
||||
// console.log(status);
|
||||
}
|
||||
bandwidth.on_srs_info = function(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip) {
|
||||
// console.log(
|
||||
// "server:" + srs_server + ", primary:" + srs_primary + ", authors:" + srs_authors +
|
||||
// ", srs_id:" + srs_id + ", srs_pid:" + srs_pid + ", ip:" + srs_server_ip
|
||||
//);
|
||||
}
|
||||
bandwidth.render("rtmp://dev:1935/app?key=35c9b402c12a7246868752e2878f7e0e&vhost=bandcheck.srs.com");
|
||||
* where the HTML page must contains an element:
|
||||
<div id="container_id"></div>
|
||||
* this js will directly erase the container by swfobject.
|
||||
*/
|
||||
function SrsBandwidth(container, width, height, private_object) {
|
||||
if (!SrsBandwidth.__id) {
|
||||
SrsBandwidth.__id = 100;
|
||||
}
|
||||
if (!SrsBandwidth.__bandwidths) {
|
||||
SrsBandwidth.__bandwidths = [];
|
||||
}
|
||||
|
||||
SrsBandwidth.__bandwidths.push(this);
|
||||
|
||||
this.private_object = private_object;
|
||||
this.container = container;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.id = SrsBandwidth.__id++;
|
||||
this.stream_url = null;
|
||||
this.callbackObj = null;
|
||||
|
||||
// the callback set data.
|
||||
this.percent = 0;
|
||||
this.status = "";
|
||||
this.server = "";
|
||||
this.completed = false;
|
||||
}
|
||||
/**
|
||||
* user can set some callback, then start the bandwidth.
|
||||
* @param url the bandwidth test url.
|
||||
* callbacks:
|
||||
* on_bandwidth_ready():void, when srs bandwidth ready, user can play.
|
||||
* on_update_progress(percent:Number):void, when srs bandwidth update the progress.
|
||||
* percent:Number 100 means 100%.
|
||||
* on_update_status(status:String):void, when srs bandwidth update the status.
|
||||
* status:String the human readable status text.
|
||||
*/
|
||||
SrsBandwidth.prototype.render = function(url) {
|
||||
if (url) {
|
||||
this.stream_url = url;
|
||||
}
|
||||
|
||||
// embed the flash.
|
||||
var flashvars = {};
|
||||
flashvars.id = this.id;
|
||||
flashvars.on_bandwidth_ready = "__srs_on_bandwidth_ready";
|
||||
flashvars.on_update_progress = "__srs_on_update_progress";
|
||||
flashvars.on_update_status = "__srs_on_update_status";
|
||||
flashvars.on_srs_info = "__srs_on_srs_info";
|
||||
flashvars.on_complete = "__srs_on_complete";
|
||||
|
||||
var params = {};
|
||||
params.wmode = "opaque";
|
||||
params.allowFullScreen = "true";
|
||||
params.allowScriptAccess = "always";
|
||||
|
||||
var attributes = {};
|
||||
|
||||
var self = this;
|
||||
|
||||
swfobject.embedSWF(
|
||||
"srs_bwt/release/srs_bwt.swf?_version="+srs_get_version_code(),
|
||||
this.container,
|
||||
this.width, this.height,
|
||||
"11.1.0", "js/AdobeFlashbandwidthInstall.swf",
|
||||
flashvars, params, attributes,
|
||||
function(callbackObj){
|
||||
self.callbackObj = callbackObj;
|
||||
}
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* play the stream.
|
||||
* @param stream_url the url of stream, rtmp or http.
|
||||
*/
|
||||
SrsBandwidth.prototype.check_bandwidth = function(url) {
|
||||
this.stop();
|
||||
SrsBandwidth.__bandwidths.push(this);
|
||||
|
||||
// the callback set data.
|
||||
this.percent = 0;
|
||||
this.status = "";
|
||||
this.server = "";
|
||||
this.completed = false;
|
||||
|
||||
if (url) {
|
||||
this.stream_url = url;
|
||||
}
|
||||
|
||||
this.callbackObj.ref.__check_bandwidth(this.stream_url);
|
||||
}
|
||||
SrsBandwidth.prototype.stop = function(url) {
|
||||
for (var i = 0; i < SrsBandwidth.__bandwidths.length; i++) {
|
||||
var bandwidth = SrsBandwidth.__bandwidths[i];
|
||||
|
||||
if (bandwidth.id != this.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SrsBandwidth.__bandwidths.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
this.callbackObj.ref.__stop();
|
||||
}
|
||||
SrsBandwidth.prototype.on_bandwidth_ready = function() {
|
||||
}
|
||||
SrsBandwidth.prototype.on_update_progress = function(percent) {
|
||||
}
|
||||
SrsBandwidth.prototype.on_update_status = function(status) {
|
||||
}
|
||||
SrsBandwidth.prototype.on_srs_info = function(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip) {
|
||||
}
|
||||
SrsBandwidth.prototype.on_complete = function(start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time) {
|
||||
}
|
||||
SrsBandwidth.prototype.on_error = function(code) {
|
||||
}
|
||||
function __srs_find_bandwidth(id) {
|
||||
for (var i = 0; i < SrsBandwidth.__bandwidths.length; i++) {
|
||||
var bandwidth = SrsBandwidth.__bandwidths[i];
|
||||
|
||||
if (bandwidth.id != id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return bandwidth;
|
||||
}
|
||||
|
||||
throw new Error("bandwidth not found. id=" + id);
|
||||
}
|
||||
function __srs_on_bandwidth_ready(id) {
|
||||
var bandwidth = __srs_find_bandwidth(id);
|
||||
bandwidth.on_bandwidth_ready();
|
||||
}
|
||||
function __srs_on_update_progress(id, percent) {
|
||||
var bandwidth = __srs_find_bandwidth(id);
|
||||
bandwidth.percent = percent;
|
||||
bandwidth.on_update_progress(percent);
|
||||
}
|
||||
function __srs_on_update_status(id, code, data) {
|
||||
var bandwidth = __srs_find_bandwidth(id);
|
||||
|
||||
var status = "";
|
||||
switch(code){
|
||||
case "NetConnection.Connect.Failed":
|
||||
if (bandwidth.completed) {
|
||||
return;
|
||||
}
|
||||
bandwidth.on_error(code);
|
||||
status = "连接服务器失败!";
|
||||
break;
|
||||
case "NetConnection.Connect.Rejected":
|
||||
if (bandwidth.completed) {
|
||||
return;
|
||||
}
|
||||
bandwidth.completed = true;
|
||||
bandwidth.on_update_progress(100);
|
||||
bandwidth.on_error(code);
|
||||
status = "服务器拒绝连接,测速过于频繁!";
|
||||
break;
|
||||
case "NetConnection.Connect.Success":
|
||||
status = "连接服务器成功!";
|
||||
break;
|
||||
case "NetConnection.Connect.Closed":
|
||||
if (bandwidth.completed) {
|
||||
return;
|
||||
}
|
||||
bandwidth.on_error(code);
|
||||
status = "连接已断开!";
|
||||
break;
|
||||
case "srs.bwtc.play.start":
|
||||
status = "开始测试下行带宽";
|
||||
break;
|
||||
case "srs.bwtc.play.stop":
|
||||
bandwidth.completed = true;
|
||||
status = "下行带宽测试完毕," + data + "kbps,开始测试上行带宽。";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
bandwidth.status = status;
|
||||
bandwidth.on_update_status(status);
|
||||
}
|
||||
function __srs_on_srs_info(id, srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip) {
|
||||
var bandwidth = __srs_find_bandwidth(id);
|
||||
bandwidth.status = status;
|
||||
bandwidth.server = srs_server_ip;
|
||||
bandwidth.on_srs_info(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip);
|
||||
}
|
||||
function __srs_on_complete(id, start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time) {
|
||||
var bandwidth = __srs_find_bandwidth(id);
|
||||
|
||||
var status = "检测结束: " + bandwidth.server + " 上行: " + publish_kbps + " kbps" + " 下行: " + play_kbps + " kbps"
|
||||
+ " 测试时间: " + Number((end_time - start_time) / 1000).toFixed(1) + " 秒";
|
||||
bandwidth.status = status;
|
||||
bandwidth.on_update_status(status);
|
||||
|
||||
bandwidth.on_complete(start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time);
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2016 SRS(ossrs)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package
|
||||
{
|
||||
import flash.display.LoaderInfo;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.StageAlign;
|
||||
import flash.display.StageScaleMode;
|
||||
import flash.events.Event;
|
||||
import flash.events.NetStatusEvent;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.external.ExternalInterface;
|
||||
import flash.net.NetConnection;
|
||||
import flash.net.ObjectEncoding;
|
||||
import flash.system.System;
|
||||
import flash.ui.ContextMenu;
|
||||
import flash.ui.ContextMenuItem;
|
||||
import flash.utils.Timer;
|
||||
import flash.utils.setTimeout;
|
||||
|
||||
public class srs_bwt extends Sprite
|
||||
{
|
||||
/**
|
||||
* the SRS bandwidth check/test library object.
|
||||
*/
|
||||
private var bandwidth:SrsBandwidth = new SrsBandwidth();
|
||||
|
||||
/**
|
||||
* when not specifies any param, directly run the swf.
|
||||
*/
|
||||
private var default_url:String = "rtmp://dev:1935/app?key=35c9b402c12a7246868752e2878f7e0e&vhost=bandcheck.srs.com";
|
||||
|
||||
public function srs_bwt()
|
||||
{
|
||||
if (!this.stage) {
|
||||
this.addEventListener(Event.ADDED_TO_STAGE, this.system_on_add_to_stage);
|
||||
} else {
|
||||
this.system_on_add_to_stage(null);
|
||||
}
|
||||
}
|
||||
private function system_on_add_to_stage(evt:Event):void {
|
||||
this.stage.scaleMode = StageScaleMode.NO_SCALE;
|
||||
this.stage.align = StageAlign.TOP_LEFT;
|
||||
|
||||
// init context menu
|
||||
var myMenu:ContextMenu = new ContextMenu();
|
||||
myMenu.hideBuiltInItems();
|
||||
myMenu.customItems.push(new ContextMenuItem("SRS带宽测试工具", true));
|
||||
this.contextMenu = myMenu;
|
||||
|
||||
check_bandwidth();
|
||||
}
|
||||
|
||||
private function check_bandwidth():void {
|
||||
// closure
|
||||
var self:srs_bwt = this;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// initialize the bandwidth check/test library
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// js callback, set to null if ignore.
|
||||
var conf:Object = this.root.loaderInfo.parameters;
|
||||
var js_id:String = conf.id? conf.id:null;
|
||||
var js_on_ready:String = conf.on_bandwidth_ready? conf.on_bandwidth_ready:null;
|
||||
var js_on_srs_info:String = conf.on_srs_info? conf.on_srs_info:null;
|
||||
var js_on_progress_change:String = conf.on_update_progress? conf.on_update_progress:null;
|
||||
var js_on_status_change:String = conf.on_update_status? conf.on_update_status:null;
|
||||
var js_on_complete:String = conf.on_complete? conf.on_complete:null;
|
||||
|
||||
// js export, set to null to disable
|
||||
var js_export_check_bandwidth:String = "__check_bandwidth";
|
||||
var js_export_stop:String = "__stop";
|
||||
|
||||
// as callback, set to null if ignore.
|
||||
var as_on_ready:Function = function():void {
|
||||
self.on_ready();
|
||||
};
|
||||
var as_on_status_change:Function = function(code:String, data:String):void {
|
||||
self.on_status_change(code, data);
|
||||
};
|
||||
var as_on_progress_change:Function = function(percent:Number):void {
|
||||
self.on_progress(percent);
|
||||
};
|
||||
var as_on_srs_info:Function = function(srs_server:String, srs_primary:String, srs_authors:String, srs_id:String, srs_pid:String, srs_server_ip:String):void {
|
||||
self.update_context_items(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip);
|
||||
};
|
||||
var as_on_complete:Function = function(start_time:Number, end_time:Number, play_kbps:Number, publish_kbps:Number, play_bytes:Number, publish_bytes:Number, play_time:Number, publish_time:Number):void {
|
||||
self.on_complete(start_time, end_time, play_kbps, publish_kbps, play_bytes, publish_bytes, play_time, publish_time);
|
||||
};
|
||||
|
||||
bandwidth.initialize(
|
||||
as_on_ready, as_on_status_change, as_on_progress_change, as_on_srs_info, as_on_complete,
|
||||
js_id, js_on_ready, js_on_status_change, js_on_progress_change, js_on_srs_info, js_on_complete,
|
||||
js_export_check_bandwidth, js_export_stop
|
||||
);
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
private function on_ready():void {
|
||||
var conf:Object = this.root.loaderInfo.parameters;
|
||||
|
||||
// for directly run swf.
|
||||
if (!conf.id) {
|
||||
log("directly run swf, load default url: " + this.default_url);
|
||||
this.bandwidth.check_bandwidth(this.default_url);
|
||||
}
|
||||
|
||||
}
|
||||
private function on_progress(percent:Number):void {
|
||||
log("progress:" + percent + "%");
|
||||
}
|
||||
private function update_context_items(
|
||||
srs_server:String, srs_primary:String, srs_authors:String,
|
||||
srs_id:String, srs_pid:String, srs_server_ip:String
|
||||
):void {
|
||||
// for context menu
|
||||
var customItems:Array = [new ContextMenuItem("SrsPlayer")];
|
||||
if (srs_server != null) {
|
||||
customItems.push(new ContextMenuItem("Server: " + srs_server));
|
||||
}
|
||||
if (srs_primary != null) {
|
||||
customItems.push(new ContextMenuItem("Primary: " + srs_primary));
|
||||
}
|
||||
if (srs_authors != null) {
|
||||
customItems.push(new ContextMenuItem("Authors: " + srs_authors));
|
||||
}
|
||||
if (srs_server_ip != null) {
|
||||
customItems.push(new ContextMenuItem("SrsIp: " + srs_server_ip));
|
||||
}
|
||||
if (srs_pid != null) {
|
||||
customItems.push(new ContextMenuItem("SrsPid: " + srs_pid));
|
||||
}
|
||||
if (srs_id != null) {
|
||||
customItems.push(new ContextMenuItem("SrsId: " + srs_id));
|
||||
}
|
||||
contextMenu.customItems = customItems;
|
||||
}
|
||||
public function on_status_change(code:String, data:String): void {
|
||||
log(code);
|
||||
switch(code){
|
||||
case "NetConnection.Connect.Failed":
|
||||
log("连接服务器失败!");
|
||||
break;
|
||||
case "NetConnection.Connect.Rejected":
|
||||
log("服务器拒绝连接!");
|
||||
break;
|
||||
case "NetConnection.Connect.Success":
|
||||
log("连接服务器成功!");
|
||||
break;
|
||||
case SrsBandwidth.StatusSrsBwtcPlayStart:
|
||||
log("开始测试下行带宽");
|
||||
break;
|
||||
case SrsBandwidth.StatusSrsBwtcPlayStop:
|
||||
log("下行带宽测试完毕," + data + "kbps,开始测试上行带宽。");
|
||||
break;
|
||||
case SrsBandwidth.StatusSrsBwtcPublishStart:
|
||||
log("开始测试上行带宽");
|
||||
break;
|
||||
case SrsBandwidth.StatusSrsBwtcPublishStop:
|
||||
log("上行带宽测试完毕," + data + "kbps,");
|
||||
break;
|
||||
case "NetConnection.Connect.Closed":
|
||||
log("连接已断开!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
private function on_complete(
|
||||
start_time:Number, end_time:Number, play_kbps:Number, publish_kbps:Number,
|
||||
play_bytes:Number, publish_bytes:Number, play_time:Number, publish_time:Number
|
||||
):void {
|
||||
var status:String = "检测结束: 上行: " + publish_kbps + " kbps" + " 下行: " + play_kbps + " kbps"
|
||||
+ " 测试时间: " + Number((end_time - start_time) / 1000).toFixed(1) + " 秒";
|
||||
log(status);
|
||||
}
|
||||
|
||||
private function log(msg:String):void {
|
||||
trace(msg);
|
||||
if (ExternalInterface.available) {
|
||||
ExternalInterface.call("console.log", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
.accordion-group {
|
||||
width: 310px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/chat'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a id="srs_index" class="brand" href="#">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li class="active"><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<!-- for the log -->
|
||||
<div class="alert alert-danger fade in" id="txt_log">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><span id="txt_log_title">Warning:</span></strong>
|
||||
<span id="txt_log_msg">
|
||||
SRS不支持实时聊天,请使用<a href="https://webrtc.org/" target="_blank">WebRTC</a>,
|
||||
SRS会在未来考虑支持(<a href="https://github.com/ossrs/srs/issues/307" target="_blank">#307</a>)。
|
||||
</span>
|
||||
</div>
|
||||
<hr/>
|
||||
<footer>
|
||||
<p><a href="https://github.com/ossrs/srs">SRS Team © 2013</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
</html>
|
||||
|
|
@ -1,717 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
#my_modal_footer {
|
||||
margin-top: -20px;
|
||||
padding-top: 3px;
|
||||
}
|
||||
#main_modal {
|
||||
margin-top: -60px;
|
||||
}
|
||||
.div_play_time {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#pb_buffer_bg {
|
||||
margin-top: -4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/srsplayer'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a id="srs_index" class="brand" href="#">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li class="active"><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div name="detect_flash">
|
||||
<div id="main_flash_alert" class="alert alert-danger fade in hide">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><p>Usage:</p></strong>
|
||||
<p>
|
||||
请点击下面的图标,启用Flash
|
||||
</p>
|
||||
<p>
|
||||
若没有见到这个图标,Chrome浏览器请打开
|
||||
<span class="text-info">chrome://settings/content/flash</span> 并修改为"Ask first"。
|
||||
</p>
|
||||
</div>
|
||||
<div id="main_flash_hdr" class="hide">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main_content" class="hide">
|
||||
<div class="alert alert-info fade in">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><span>Usage:</span></strong> <span>输入RTMP/HTTP-FLV/HLS地址后点击“播放视频”即可播放视频</span>
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
URL:
|
||||
<input type="text" id="txt_url" class="input-xxlarge" value="">
|
||||
<button class="btn btn-primary" id="btn_play">播放视频</button>
|
||||
<button class="btn" id="btn_generate_link">生成链接</button>
|
||||
<p></p>
|
||||
<p>
|
||||
推荐的其他播放器:
|
||||
<ul>
|
||||
<li><a href="http://bilibili.github.io/flv.js/demo">flv.js</a>,H5/MSE播放HTTP-FLV</li>
|
||||
<li><a href="https://hls-js.netlify.com/demo">hls.js</a>,H5/MSE播放HLS</li>
|
||||
<li><a href="http://reference.dashif.org/dash.js/nightly/samples/dash-if-reference-player/index.html">dash.js</a>,H5/MSE播放MPEG-DASH</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<div id="link_modal" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3><a href="https://github.com/ossrs/srs">SRS Link Generator</a></h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="link_server">服务器地址</label>
|
||||
<div class="controls">
|
||||
<span id="link_server" class="span4 uneditable-input"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="link_port">服务器端口</label>
|
||||
<div class="controls">
|
||||
<span id="link_port" class="span2 uneditable-input"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="link_vhost">RTMP Vhost</label>
|
||||
<div class="controls">
|
||||
<span id="link_vhost" class="span4 uneditable-input"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="link_app">RTMP App</label>
|
||||
<div class="controls">
|
||||
<span id="link_app" class="span4 uneditable-input"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="link_stream">RTMP Stream</label>
|
||||
<div class="controls">
|
||||
<span id="link_stream" class="span4 uneditable-input"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="link_rtmp">RTMP地址</label>
|
||||
<div class="controls">
|
||||
<span id="link_rtmp" class="span4 uneditable-input"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="link_url">播放链接地址</label>
|
||||
<div class="controls">
|
||||
<div style="margin-top:5px;"><a href="#" id="link_url" target="_blank">请右键拷贝此链接地址.</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer"></div>
|
||||
</div>
|
||||
<div id="main_modal" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3><a href="https://github.com/ossrs/srs">SrsPlayer</a></h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="player"></div>
|
||||
<div class="progress progress-striped active" id="pb_buffer_bg">
|
||||
<div class="bar" style="width: 0%;" id="pb_buffer"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer" id="my_modal_footer">
|
||||
<div>
|
||||
<div class="btn-group dropup">
|
||||
<button class="btn dropdown-toggle" data-toggle="dropdown">
|
||||
全屏比例大小<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a id="btn_fs_size_screen_100" href="#">屏幕大小(100%)</a></li>
|
||||
<li><a id="btn_fs_size_screen_75" href="#">屏幕大小(75%)</a></li>
|
||||
<li><a id="btn_fs_size_screen_50" href="#">屏幕大小(50%)</a></li>
|
||||
<li><a id="btn_fs_size_video_100" href="#">视频大小(100%)</a></li>
|
||||
<li><a id="btn_fs_size_video_75" href="#">视频大小(75%)</a></li>
|
||||
<li><a id="btn_fs_size_video_50" href="#">视频大小(50%)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group dropup">
|
||||
<button class="btn dropdown-toggle" data-toggle="dropdown">显示比例<span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a id="btn_dar_original" href="#">视频原始比例</a></li>
|
||||
<li><a id="btn_dar_21_9" href="#">宽屏影院(21:9)</a></li>
|
||||
<li><a id="btn_dar_16_9" href="#">宽屏电视(16:9)</a></li>
|
||||
<li><a id="btn_dar_4_3" href="#">窄屏(4:3)</a></li>
|
||||
<li><a id="btn_dar_fill" href="#">填充(容器比例)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group dropup">
|
||||
<button class="btn dropdown-toggle" data-toggle="dropdown">缓冲区大小<span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a id="btn_bt_0_1" href="#">0.1秒(实时)</a></li>
|
||||
<li><a id="btn_bt_0_2" href="#">0.2秒(实时)</a></li>
|
||||
<li><a id="btn_bt_0_3" href="#">0.3秒(实时)</a></li>
|
||||
<li><a id="btn_bt_0_5" href="#">0.5秒(实时)</a></li>
|
||||
<li><a id="btn_bt_0_8" href="#">0.8秒(会议)</a></li>
|
||||
<li><a id="btn_bt_1_0" href="#">1秒(低延迟)</a></li>
|
||||
<li><a id="btn_bt_2_0" href="#">2秒(较低延时)</a></li>
|
||||
<li><a id="btn_bt_3_0" href="#">3秒(流畅播放)</a></li>
|
||||
<li><a id="btn_bt_4_0" href="#">4秒(流畅播放)</a></li>
|
||||
<li><a id="btn_bt_5_0" href="#">5秒(网速较低)</a></li>
|
||||
<li><a id="btn_bt_6_0" href="#">6秒(网速较低)</a></li>
|
||||
<li><a id="btn_bt_8_0" href="#">8秒(网速较低)</a></li>
|
||||
<li><a id="btn_bt_10_0" href="#">10秒(无所谓延迟)</a></li>
|
||||
<li><a id="btn_bt_15_0" href="#">15秒(无所谓延迟)</a></li>
|
||||
<li><a id="btn_bt_20_0" href="#">20秒(无所谓延迟)</a></li>
|
||||
<li><a id="btn_bt_30_0" href="#">30秒(流畅第一)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group dropup">
|
||||
<button class="btn dropdown-toggle" data-toggle="dropdown">最大缓冲区<span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a id="btn_mbt_0_6" href="#">0.6秒(实时)</a></li>
|
||||
<li><a id="btn_mbt_0_9" href="#">0.9秒(实时)</a></li>
|
||||
<li><a id="btn_mbt_1_2" href="#">1.2秒(实时)</a></li>
|
||||
<li><a id="btn_mbt_1_5" href="#">1.5秒(实时)</a></li>
|
||||
<li><a id="btn_mbt_2_4" href="#">2.4秒(会议)</a></li>
|
||||
<li><a id="btn_mbt_3_0" href="#">3秒(低延迟)</a></li>
|
||||
<li><a id="btn_mbt_6_0" href="#">6秒(较低延时)</a></li>
|
||||
<li><a id="btn_mbt_9_0" href="#">9秒(流畅播放)</a></li>
|
||||
<li><a id="btn_mbt_12_0" href="#">12秒(流畅播放)</a></li>
|
||||
<li><a id="btn_mbt_15_0" href="#">15秒(网速较低)</a></li>
|
||||
<li><a id="btn_mbt_18_0" href="#">18秒(网速较低)</a></li>
|
||||
<li><a id="btn_mbt_24_0" href="#">24秒(网速较低)</a></li>
|
||||
<li><a id="btn_mbt_30_0" href="#">30秒(无所谓延迟)</a></li>
|
||||
<li><a id="btn_mbt_45_0" href="#">45秒(无所谓延迟)</a></li>
|
||||
<li><a id="btn_mbt_60_0" href="#">60秒(无所谓延迟)</a></li>
|
||||
<li><a id="btn_mbt_90_0" href="#">90秒(流畅第一)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group dropup">
|
||||
<a id="btn_fullscreen" class="btn">全屏</a>
|
||||
</div>
|
||||
<div class="btn-group dropup">
|
||||
<button id="btn_pause" class="btn">暂停播放</button>
|
||||
<button id="btn_resume" class="btn hide">继续播放</button>
|
||||
</div>
|
||||
<div class="btn-group dropup">
|
||||
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">关闭播放器</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hide" id="fullscreen_tips">
|
||||
请<font color="red">点击视频</font>进入全屏模式~<br/>
|
||||
由于安全原因,Flash全屏无法使用JS触发
|
||||
</div>
|
||||
<div>
|
||||
<div class="input-prepend div_play_time" title="BufferLength/BufferTime/MaxBufferTime">
|
||||
<span class="add-on">@B</span>
|
||||
<input class="span2" style="width:80px" id="txt_buffer" type="text" placeholder="0/0/0s">
|
||||
</div>
|
||||
<div class="input-prepend div_play_time" title="视频的播放流畅度">
|
||||
<span class="add-on">@F</span>
|
||||
<input class="span2" style="width:57px" id="txt_fluency" type="text" placeholder="100%">
|
||||
</div>
|
||||
<div class="input-prepend div_play_time" title="视频总共卡顿次数">
|
||||
<span class="add-on">@E</span>
|
||||
<input class="span2" style="width:45px" id="txt_empty_count" type="text" placeholder="0">
|
||||
</div>
|
||||
<div class="input-prepend div_play_time" title="视频当前的帧率FPS">
|
||||
<span class="add-on">@F</span>
|
||||
<input class="span2" style="width:55px" id="txt_fps" type="text" placeholder="fps">
|
||||
</div>
|
||||
<div class="input-prepend div_play_time" title="视频当前的码率(视频+音频),单位:Kbps">
|
||||
<span class="add-on">@B</span>
|
||||
<input class="span2" style="width:55px" id="txt_bitrate" type="text" placeholder="kbps">
|
||||
</div>
|
||||
<div class="input-prepend div_play_time" title="播放时长,格式:天 时:分:秒">
|
||||
<span class="add-on">@T</span>
|
||||
<input class="span2" style="width:85px" id="txt_time" type="text" placeholder="天 时:分:秒">
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top:-12px;">
|
||||
<span id="debug_info"></span>
|
||||
URL: <a href="#" id="player_url"></a>
|
||||
<div class="input-prepend div_play_time" title="当前时间:年-月-日 时:分:秒">
|
||||
<span class="add-on">@N</span>
|
||||
<input class="span2" style="width:135px" id="player_clock" type="text" placeholder="年-月-日 时:分:秒">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="input-prepend" title="首播时间,点播放到开始播放的时间,秒">
|
||||
<span class="add-on">@PST</span>
|
||||
<input class="span1" style="width:60px" id="txt_pst" type="text" placeholder="N秒">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p></p>
|
||||
<p><a href="https://github.com/ossrs/srs">SRS Team © 2013</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||
<script type="text/javascript" src="js/json2.js"></script>
|
||||
<script type="text/javascript" src="js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="js/srs.log.js"></script>
|
||||
<script type="text/javascript" src="js/srs.player.js"></script>
|
||||
<script type="text/javascript" src="js/srs.publisher.js"></script>
|
||||
<script type="text/javascript" src="js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="js/winlin.utility.js"></script>
|
||||
<script type="text/javascript">
|
||||
var __on_flash_ready = null;
|
||||
|
||||
$(function(){
|
||||
// 探测Flash是否正常启用。
|
||||
$('#main_flash_hdr').html(
|
||||
'\
|
||||
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="100%" height="100%"> \
|
||||
<param name="movie" value="srs_player/release/srs_player.swf"> \
|
||||
<param name="quality" value="autohigh"> \
|
||||
<param name="swliveconnect" value="true"> \
|
||||
<param name="allowScriptAccess" value="always"> \
|
||||
<param name="bgcolor" value="#0"> \
|
||||
<param name="allowFullScreen" value="true"> \
|
||||
<param name="wmode" value="opaque"> \
|
||||
<param name="FlashVars" value="log=1"> \
|
||||
<param name="flashvars" value="id=1&on_player_ready=__on_flash_ready"> \
|
||||
<embed src="srs_player/release/srs_player.swf" width="100%" height="100%" \
|
||||
quality="autohigh" bgcolor="#0" align="middle" allowfullscreen="true" allowscriptaccess="always" \
|
||||
type="application/x-shockwave-flash" swliveconnect="true" wmode="opaque" \
|
||||
flashvars="id=1&on_player_ready=__on_flash_ready" \
|
||||
pluginspage="http://www.macromedia.com/go/getflashplayer"> \
|
||||
</object> \
|
||||
'
|
||||
);
|
||||
$('#main_flash_hdr').show();
|
||||
|
||||
var showFlashHdr = setTimeout(function(){
|
||||
$('#main_flash_alert').show();
|
||||
}, 300);
|
||||
|
||||
__on_flash_ready = function (id) {
|
||||
clearTimeout(showFlashHdr);
|
||||
|
||||
$('#main_flash_alert').hide();
|
||||
$('#main_flash_hdr').hide();
|
||||
$('#main_content').show();
|
||||
|
||||
autoLoadPage();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var srs_player = null;
|
||||
var url = null;
|
||||
|
||||
var __active_dar = null;
|
||||
function select_dar(dar_id, num, den) {
|
||||
srs_player.set_dar(num, den);
|
||||
|
||||
if (__active_dar) {
|
||||
__active_dar.removeClass("active");
|
||||
}
|
||||
|
||||
__active_dar = $(dar_id).parent();
|
||||
__active_dar.addClass("active");
|
||||
}
|
||||
|
||||
var __active_size = null;
|
||||
function select_fs_size(size_id, refer, percent) {
|
||||
srs_player.set_fs(refer, percent);
|
||||
|
||||
if (__active_size) {
|
||||
__active_size.removeClass("active");
|
||||
}
|
||||
|
||||
__active_size = $(size_id).parent();
|
||||
__active_size.addClass("active");
|
||||
}
|
||||
|
||||
function select_buffer(buffer_time) {
|
||||
var bt = buffer_time;
|
||||
var bt_id = "#btn_bt_" + bt.toFixed(1).replace(".", "_");
|
||||
select_buffer_time(bt_id, bt);
|
||||
}
|
||||
function select_max_buffer(max_buffer_time) {
|
||||
var mbt = max_buffer_time;
|
||||
var mbt_id = "#btn_mbt_" + mbt.toFixed(1).replace(".", "_");
|
||||
select_max_buffer_time(mbt_id, mbt);
|
||||
}
|
||||
|
||||
var __active_bt = null;
|
||||
function select_buffer_time(bt_id, buffer_time) {
|
||||
srs_player.set_bt(buffer_time);
|
||||
|
||||
if (__active_bt) {
|
||||
__active_bt.removeClass("active");
|
||||
}
|
||||
|
||||
__active_bt = $(bt_id).parent();
|
||||
__active_bt.addClass("active");
|
||||
|
||||
select_max_buffer(srs_player.max_buffer_time);
|
||||
}
|
||||
|
||||
var __active_mbt = null;
|
||||
function select_max_buffer_time(mbt_id, max_buffer_time) {
|
||||
srs_player.set_mbt(max_buffer_time);
|
||||
|
||||
if (__active_mbt) {
|
||||
__active_mbt.removeClass("active");
|
||||
}
|
||||
|
||||
__active_mbt = $(mbt_id).parent();
|
||||
__active_mbt.addClass("active");
|
||||
}
|
||||
|
||||
/****
|
||||
* The parameters for this page:
|
||||
* schema, the protocol schema, rtmp or http.
|
||||
* server, the ip of the url.
|
||||
* port, the rtmp port of url.
|
||||
* vhost, the vhost of url, can equals to server.
|
||||
* app, the app of url.
|
||||
* stream, the stream of url, can endwith .flv or .mp4 or nothing for RTMP.
|
||||
* autostart, whether auto play the stream.
|
||||
* buffer, the buffer time in seconds.
|
||||
* extra params:
|
||||
* shp_identify, hls+ param.
|
||||
* for example:
|
||||
* http://localhost:8088/players/srs_player.html?vhost=ossrs.net&app=live&stream=livestream&server=ossrs.net&port=1935&autostart=true&schema=rtmp
|
||||
* http://localhost:8088/players/srs_player.html?vhost=ossrs.net&app=live&stream=livestream.flv&server=ossrs.net&port=8080&autostart=true&schema=http
|
||||
*/
|
||||
var autoLoadPage = function() {
|
||||
var query = parse_query_string();
|
||||
|
||||
// get the vhost and port to set the default url.
|
||||
// for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
|
||||
// url set to: rtmp://demo:1935/live/livestream
|
||||
srs_init_rtmp("#txt_url", "#main_modal");
|
||||
|
||||
// consts for buffer and max buffer.
|
||||
var bts = [0.1, 0.2, 0.3, 0.5, 0.8, 1, 2, 3, 4, 5, 6, 8, 10, 15, 20, 30];
|
||||
var mbts = [0.6, 0.9, 1.2, 1.5, 2.4, 3, 6, 9, 12, 15, 18, 24, 30, 45, 60, 90];
|
||||
|
||||
// the play startup time.
|
||||
var pst = new Date();
|
||||
|
||||
$("#main_modal").on("show", function(){
|
||||
if (srs_player) {
|
||||
return;
|
||||
}
|
||||
|
||||
$("#div_container").remove();
|
||||
$("#debug_info").text("");
|
||||
|
||||
var div_container = $("<div/>");
|
||||
$(div_container).attr("id", "div_container");
|
||||
$("#player").append(div_container);
|
||||
|
||||
var player = $("<div/>");
|
||||
$(player).attr("id", "player_id");
|
||||
$(div_container).append(player);
|
||||
|
||||
srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height());
|
||||
srs_player.on_player_ready = function() {
|
||||
var buffer_time = 0.5;
|
||||
if (url.indexOf('.m3u8') > 0) {
|
||||
buffer_time = 2;
|
||||
}
|
||||
|
||||
if (query.buffer) {
|
||||
for (var i = 0; i < bts.length - 1; i++) {
|
||||
var cur = bts[i];
|
||||
var next = bts[i+1];
|
||||
if (Number(query.buffer) >= cur && Number(query.buffer) < next) {
|
||||
buffer_time = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select_buffer(buffer_time);
|
||||
this.play(url);
|
||||
|
||||
pst = new Date();
|
||||
};
|
||||
srs_player.on_player_status = function(code, desc) {
|
||||
//console.log("[播放器状态] code=" + code + ", desc=" + desc);
|
||||
};
|
||||
srs_player.on_player_metadata = function(metadata) {
|
||||
$("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")");
|
||||
if (metadata.ip && metadata.pid && metadata.cid) {
|
||||
$("#debug_info").text("ID:" + metadata.ip + '/' + metadata.pid + '/' + metadata.cid + '');
|
||||
}
|
||||
select_dar("#btn_dar_original", 0, 0);
|
||||
select_fs_size("#btn_fs_size_screen_100", "screen", 100);
|
||||
};
|
||||
srs_player.on_player_timer = function(time, buffer_length, kbps, fps, rtime) {
|
||||
if (time > 0 && pst) {
|
||||
var diff = (new Date().getTime() - pst.getTime()) / 1000.0;
|
||||
$("#txt_pst").val(Number(diff).toFixed(2) + "秒");
|
||||
pst = null;
|
||||
}
|
||||
|
||||
var buffer = buffer_length / this.max_buffer_time * 100;
|
||||
$("#pb_buffer").width(Number(buffer).toFixed(1) + "%");
|
||||
|
||||
$("#pb_buffer_bg").attr("title",
|
||||
"缓冲区:" + buffer_length.toFixed(1) + "秒, 最大缓冲区:"
|
||||
+ this.max_buffer_time.toFixed(1) + "秒, 当前:"
|
||||
+ buffer.toFixed(1) + "%");
|
||||
|
||||
var bts = this.buffer_time >= 1? this.buffer_time.toFixed(0) : this.buffer_time.toFixed(1);
|
||||
var mbts = this.buffer_time >= 1? this.max_buffer_time.toFixed(0) : this.max_buffer_time.toFixed(1);
|
||||
$("#txt_buffer").val(buffer_length.toFixed(1) + "/" + bts + "/" + mbts + "s");
|
||||
|
||||
$("#txt_bitrate").val(kbps.toFixed(0) + "kbps");
|
||||
$("#txt_fps").val(fps.toFixed(1) + "fps");
|
||||
$("#txt_empty_count").val(srs_player.empty_count() + "次");
|
||||
$("#txt_fluency").val(srs_player.fluency().toFixed(2) + "%");
|
||||
|
||||
var time_str = "";
|
||||
// day
|
||||
time_str = padding(parseInt(time / 24 / 3600), 2, '0') + " ";
|
||||
// hour
|
||||
time = time % (24 * 3600);
|
||||
time_str += padding(parseInt(time / 3600), 2, '0') + ":";
|
||||
// minute
|
||||
time = time % (3600);
|
||||
time_str += padding(parseInt(time / 60), 2, '0') + ":";
|
||||
// seconds
|
||||
time = time % (60);
|
||||
time_str += padding(parseInt(time), 2, '0');
|
||||
// show
|
||||
$("#txt_time").val(time_str);
|
||||
|
||||
var clock = new Date().getTime() / 1000;
|
||||
$("#player_clock").val(absolute_seconds_to_YYYYmmdd(clock) + " " + absolute_seconds_to_HHMMSS(clock));
|
||||
};
|
||||
srs_player.start();
|
||||
});
|
||||
|
||||
$("#main_modal").on("hide", function(){
|
||||
if (srs_player) {
|
||||
// report the log to backend.
|
||||
//console.log(srs_player.dump_log());
|
||||
|
||||
srs_player.stop();
|
||||
srs_player = null;
|
||||
}
|
||||
});
|
||||
|
||||
var apply_url_change = function() {
|
||||
var rtmp = parse_rtmp_url($("#txt_url").val());
|
||||
var url = "http://" + query.host + query.pathname + "?"
|
||||
+ "app=" + rtmp.app + "&stream=" + rtmp.stream
|
||||
+ "&server=" + rtmp.server + "&port=" + rtmp.port
|
||||
+ "&autostart=true";
|
||||
if (query.shp_identify) {
|
||||
url += "&shp_identify=" + query.shp_identify;
|
||||
}
|
||||
if (rtmp.vhost == "__defaultVhost__") {
|
||||
url += "&vhost=" + rtmp.server;
|
||||
} else {
|
||||
url += "&vhost=" + rtmp.vhost;
|
||||
}
|
||||
if (rtmp.schema == "http") {
|
||||
url += "&schema=http";
|
||||
}
|
||||
if (query.buffer) {
|
||||
url += "&buffer=" + query.buffer;
|
||||
}
|
||||
|
||||
var queries = user_extra_params(query);
|
||||
if (queries && queries.length) {
|
||||
url += '&' + queries.join('&');
|
||||
}
|
||||
$("#player_url").text($("#txt_url").val()).attr("href", url);
|
||||
|
||||
$("#link_server").text(rtmp.server);
|
||||
$("#link_port").text(rtmp.port);
|
||||
$("#link_vhost").text(rtmp.vhost);
|
||||
$("#link_app").text(rtmp.app);
|
||||
$("#link_stream").text(rtmp.stream);
|
||||
$("#link_rtmp").text($("#txt_url").val());
|
||||
$("#link_url").attr("href", url);
|
||||
};
|
||||
|
||||
$("#txt_url").change(function(){
|
||||
apply_url_change();
|
||||
});
|
||||
|
||||
$("#btn_generate_link").click(function(){
|
||||
$("#link_modal").modal({show:true, keyboard:true});
|
||||
});
|
||||
|
||||
$("#btn_play").click(function(){
|
||||
url = $("#txt_url").val();
|
||||
$("#main_modal").modal({show:true, keyboard:true});
|
||||
});
|
||||
|
||||
$("#btn_fullscreen").click(function(){
|
||||
$("#fullscreen_tips").toggle();
|
||||
});
|
||||
|
||||
$("#btn_pause").click(function() {
|
||||
$("#btn_resume").toggle();
|
||||
$("#btn_pause").toggle();
|
||||
srs_player.pause();
|
||||
});
|
||||
$("#btn_resume").click(function(){
|
||||
$("#btn_resume").toggle();
|
||||
$("#btn_pause").toggle();
|
||||
srs_player.resume();
|
||||
});
|
||||
|
||||
if (true) {
|
||||
$("#srs_publish").click(function () {
|
||||
url = $("#srs_publish").text();
|
||||
$("#main_modal").modal({show: true, keyboard: false});
|
||||
});
|
||||
$("#srs_publish_ld").click(function () {
|
||||
url = $("#srs_publish_ld").text();
|
||||
$("#main_modal").modal({show: true, keyboard: false});
|
||||
});
|
||||
$("#srs_publish_sd").click(function () {
|
||||
url = $("#srs_publish_sd").text();
|
||||
$("#main_modal").modal({show: true, keyboard: false});
|
||||
});
|
||||
$("#srs_publish_fw").click(function () {
|
||||
url = $("#srs_publish_fw").text();
|
||||
$("#main_modal").modal({show: true, keyboard: false});
|
||||
});
|
||||
$("#srs_publish_fw_ld").click(function () {
|
||||
url = $("#srs_publish_fw_ld").text();
|
||||
$("#main_modal").modal({show: true, keyboard: false});
|
||||
});
|
||||
$("#srs_publish_fw_sd").click(function () {
|
||||
url = $("#srs_publish_fw_sd").text();
|
||||
$("#main_modal").modal({show: true, keyboard: false});
|
||||
});
|
||||
}
|
||||
|
||||
var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=live&hls_autostart=true";
|
||||
if (true) {
|
||||
$("#srs_publish_hls").attr("href", jwplayer_url + "&stream=livestream");
|
||||
$("#srs_publish_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
|
||||
$("#srs_publish_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
|
||||
var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=forward/live&hls_autostart=true";
|
||||
$("#srs_publish_fw_hls").attr("href", jwplayer_url + "&stream=livestream");
|
||||
$("#srs_publish_fw_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
|
||||
$("#srs_publish_fw_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
|
||||
}
|
||||
|
||||
if (true) {
|
||||
$("#btn_dar_original").click(function(){
|
||||
select_dar("#btn_dar_original", 0, 0);
|
||||
});
|
||||
$("#btn_dar_21_9").click(function(){
|
||||
select_dar("#btn_dar_21_9", 21, 9);
|
||||
});
|
||||
$("#btn_dar_16_9").click(function(){
|
||||
select_dar("#btn_dar_16_9", 16, 9);
|
||||
});
|
||||
$("#btn_dar_4_3").click(function(){
|
||||
select_dar("#btn_dar_4_3", 4, 3);
|
||||
});
|
||||
$("#btn_dar_fill").click(function(){
|
||||
select_dar("#btn_dar_fill", -1, -1);
|
||||
});
|
||||
}
|
||||
|
||||
if (true) {
|
||||
$("#btn_fs_size_video_100").click(function(){
|
||||
select_fs_size("#btn_fs_size_video_100", "video", 100);
|
||||
});
|
||||
$("#btn_fs_size_video_75").click(function(){
|
||||
select_fs_size("#btn_fs_size_video_75", "video", 75);
|
||||
});
|
||||
$("#btn_fs_size_video_50").click(function(){
|
||||
select_fs_size("#btn_fs_size_video_50", "video", 50);
|
||||
});
|
||||
$("#btn_fs_size_screen_100").click(function(){
|
||||
select_fs_size("#btn_fs_size_screen_100", "screen", 100);
|
||||
});
|
||||
$("#btn_fs_size_screen_75").click(function(){
|
||||
select_fs_size("#btn_fs_size_screen_75", "screen", 75);
|
||||
});
|
||||
$("#btn_fs_size_screen_50").click(function(){
|
||||
select_fs_size("#btn_fs_size_screen_50", "screen", 50);
|
||||
});
|
||||
}
|
||||
|
||||
if (true) {
|
||||
for (var i = 0; i < bts.length; i++) {
|
||||
var bt = bts[i];
|
||||
var bt_id = "#btn_bt_" + bt.toFixed(1).replace(".", "_");
|
||||
|
||||
var bt_fun = function(id, v){
|
||||
$(bt_id).click(function(){
|
||||
select_buffer_time(id, v);
|
||||
|
||||
// remember the chagned buffer.
|
||||
if (Number(query.buffer) != srs_player.buffer_time) {
|
||||
query.buffer = srs_player.buffer_time;
|
||||
apply_url_change();
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
bt_fun(bt_id, bt);
|
||||
}
|
||||
}
|
||||
if (true) {
|
||||
for (var i = 0; i < mbts.length; i++) {
|
||||
var mbt = mbts[i];
|
||||
var mbt_id = "#btn_mbt_" + mbt.toFixed(1).replace(".", "_");
|
||||
|
||||
var mbt_fun = function(id, v){
|
||||
$(mbt_id).click(function(){
|
||||
select_max_buffer_time(id, v);
|
||||
});
|
||||
};
|
||||
mbt_fun(mbt_id, mbt);
|
||||
}
|
||||
}
|
||||
|
||||
var query = parse_query_string();
|
||||
if (query.autostart == "true") {
|
||||
url = $("#txt_url").val();
|
||||
$("#main_modal").modal({show:true, keyboard:false});
|
||||
}
|
||||
|
||||
apply_url_change();
|
||||
};
|
||||
</script>
|
||||
</html>
|
|
@ -1,44 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<actionScriptProperties analytics="false" mainApplicationPath="srs_player.as" projectUUID="1bb41a0e-6b1f-49b5-8603-219442f9f9b3" version="10">
|
||||
<compiler additionalCompilerArguments="-locale en_US" autoRSLOrdering="true" copyDependentFiles="false" fteInMXComponents="false" generateAccessible="true" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="true" htmlPlayerVersionCheck="true" includeNetmonSwc="false" outputFolderPath="release" removeUnusedRSL="true" sourceFolderPath="src" strict="true" targetPlayerVersion="0.0.0" useApolloConfig="false" useDebugRSLSwfs="true" verifyDigests="true" warn="true">
|
||||
<compilerSourcePath/>
|
||||
<libraryPath defaultLinkType="0">
|
||||
<libraryPathEntry kind="4" path="">
|
||||
<excludedEntries>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_charts.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="1" linkType="1" path="${PROJECT_FRAMEWORKS}/locale/{locale}"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/advancedgrids.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_air.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/charts.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/framework.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/mx/mx.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/netmon.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/sparkskins.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/rpc.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/videoPlayer.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp_air.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/datavisualization.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flash-integration.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_flashflexkit.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_agent.swc" useDefaultLinkType="false"/>
|
||||
</excludedEntries>
|
||||
</libraryPathEntry>
|
||||
</libraryPath>
|
||||
<sourceAttachmentPath/>
|
||||
</compiler>
|
||||
<applications>
|
||||
<application path="srs_player.as"/>
|
||||
</applications>
|
||||
<modules/>
|
||||
<buildCSSFiles/>
|
||||
<flashCatalyst validateFlashCatalystCompatibility="false"/>
|
||||
</actionScriptProperties>
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>srs_player</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.adobe.flexbuilder.project.flexbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -1,3 +0,0 @@
|
|||
#Wed Dec 18 10:07:19 CST 2013
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=utf-8
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -1,210 +0,0 @@
|
|||
package
|
||||
{
|
||||
import flash.display.Sprite;
|
||||
import flash.display.StageAlign;
|
||||
import flash.display.StageDisplayState;
|
||||
import flash.display.StageScaleMode;
|
||||
import flash.events.Event;
|
||||
import flash.events.FullScreenEvent;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.events.NetStatusEvent;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.external.ExternalInterface;
|
||||
import flash.media.SoundTransform;
|
||||
import flash.media.Video;
|
||||
import flash.net.NetConnection;
|
||||
import flash.net.NetStream;
|
||||
import flash.net.URLVariables;
|
||||
import flash.system.Security;
|
||||
import flash.ui.ContextMenu;
|
||||
import flash.ui.ContextMenuItem;
|
||||
import flash.utils.Timer;
|
||||
import flash.utils.getTimer;
|
||||
import flash.utils.setTimeout;
|
||||
|
||||
import flashx.textLayout.formats.Float;
|
||||
|
||||
/**
|
||||
* common player to play rtmp/flv stream,
|
||||
* use system NetStream.
|
||||
*/
|
||||
public class Player
|
||||
{
|
||||
// refresh every ts_fragment_seconds*M3u8RefreshRatio
|
||||
public static var M3u8RefreshRatio:Number = 0.3;
|
||||
|
||||
// parse ts every this ms.
|
||||
public static var TsParseAsyncInterval:Number = 80;
|
||||
|
||||
private var js_id:String = null;
|
||||
|
||||
// play param url.
|
||||
private var user_url:String = null;
|
||||
|
||||
private var media_stream:NetStream = null;
|
||||
private var media_conn:NetConnection = null;
|
||||
|
||||
private var owner:srs_player = null;
|
||||
|
||||
public function Player(o:srs_player) {
|
||||
owner = o;
|
||||
}
|
||||
|
||||
public function init(flashvars:Object):void {
|
||||
this.js_id = flashvars.id;
|
||||
}
|
||||
|
||||
public function stream():NetStream {
|
||||
return this.media_stream;
|
||||
}
|
||||
|
||||
private function dumps_object(obj:Object):String {
|
||||
var smr:String = "";
|
||||
for (var k:String in obj) {
|
||||
smr += k + "=" + obj[k] + ", ";
|
||||
}
|
||||
|
||||
return smr;
|
||||
}
|
||||
|
||||
public function play(url:String):void {
|
||||
owner.on_player_status("init", "Ready to play");
|
||||
|
||||
var streamName:String;
|
||||
this.user_url = url;
|
||||
|
||||
this.media_conn = new NetConnection();
|
||||
this.media_conn.client = {};
|
||||
this.media_conn.client.onBWDone = function():void {};
|
||||
this.media_conn.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void {
|
||||
log("NetConnection: type=" + evt.type + ", bub=" + evt.bubbles + ", can=" + evt.cancelable
|
||||
+ ", info is " + dumps_object(evt.info));
|
||||
|
||||
if (evt.info.hasOwnProperty("data") && evt.info.data) {
|
||||
owner.on_player_metadata(evt.info.data);
|
||||
}
|
||||
|
||||
// reject by server, maybe redirect.
|
||||
if (evt.info.code == "NetConnection.Connect.Rejected") {
|
||||
// RTMP 302 redirect.
|
||||
if (evt.info.hasOwnProperty("ex") && evt.info.ex.code == 302) {
|
||||
streamName = url.substr(url.lastIndexOf("/") + 1);
|
||||
url = evt.info.ex.redirect + "/" + streamName;
|
||||
log("Async RTMP 302 Redirect to: " + url);
|
||||
|
||||
// notify server.
|
||||
media_conn.call("Redirected", null, evt.info.ex.redirect);
|
||||
|
||||
// do 302.
|
||||
owner.on_player_302(url);
|
||||
return;
|
||||
}
|
||||
|
||||
owner.on_player_status("rejected", "Server reject play");
|
||||
close();
|
||||
}
|
||||
|
||||
if (evt.info.code == "NetConnection.Connect.Success") {
|
||||
owner.on_player_status("connected", "Connected at server");
|
||||
}
|
||||
if (evt.info.code == "NetConnection.Connect.Closed") {
|
||||
close();
|
||||
}
|
||||
if (evt.info.code == "NetConnection.Connect.Failed") {
|
||||
owner.on_player_status("failed", "Connect to server failed.");
|
||||
close();
|
||||
}
|
||||
|
||||
// TODO: FIXME: failed event.
|
||||
if (evt.info.code != "NetConnection.Connect.Success") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.indexOf(".m3u8") > 0) {
|
||||
media_stream = new HlsNetStream(M3u8RefreshRatio, TsParseAsyncInterval, media_conn);
|
||||
} else {
|
||||
media_stream = new NetStream(media_conn);
|
||||
}
|
||||
media_stream.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void {
|
||||
log("NetStream: type=" + evt.type + ", bub=" + evt.bubbles + ", can=" + evt.cancelable
|
||||
+ ", info is " + dumps_object(evt.info));
|
||||
|
||||
if (evt.info.code == "NetStream.Play.Start") {
|
||||
owner.on_player_status("play", "Start to play stream");
|
||||
}
|
||||
if (evt.info.code == "NetStream.Play.StreamNotFound") {
|
||||
owner.on_player_status("rejected", "Stream not found");
|
||||
close();
|
||||
}
|
||||
|
||||
if (evt.info.code == "NetStream.Video.DimensionChange") {
|
||||
owner.on_player_dimension_change();
|
||||
} else if (evt.info.code == "NetStream.Buffer.Empty") {
|
||||
owner.on_player_buffer_empty();
|
||||
} else if (evt.info.code == "NetStream.Buffer.Full") {
|
||||
owner.on_player_buffer_full();
|
||||
}
|
||||
|
||||
// TODO: FIXME: failed event.
|
||||
});
|
||||
|
||||
// setup stream before play.
|
||||
owner.on_player_before_play();
|
||||
|
||||
if (url.indexOf("http") == 0) {
|
||||
media_stream.play(url);
|
||||
} else {
|
||||
streamName = url.substr(url.lastIndexOf("/") + 1);
|
||||
media_stream.play(streamName);
|
||||
}
|
||||
|
||||
owner.on_player_play();
|
||||
});
|
||||
|
||||
if (url.indexOf("http") == 0) {
|
||||
this.media_conn.connect(null);
|
||||
} else {
|
||||
var tcUrl:String = this.user_url.substr(0, this.user_url.lastIndexOf("/"));
|
||||
streamName = url.substr(url.lastIndexOf("/") + 1);
|
||||
|
||||
// parse vhost from stream query.
|
||||
if (streamName.indexOf("?") >= 0) {
|
||||
var uv:URLVariables = new URLVariables(user_url.substr(user_url.indexOf("?") + 1));
|
||||
var domain:String = uv["domain"];
|
||||
if (!domain) {
|
||||
domain = uv["vhost"];
|
||||
}
|
||||
if (domain) {
|
||||
tcUrl += "?vhost=" + domain;
|
||||
}
|
||||
}
|
||||
|
||||
this.media_conn.connect(tcUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public function close():void {
|
||||
var notify:Boolean = false;
|
||||
|
||||
if (this.media_stream) {
|
||||
this.media_stream.close();
|
||||
this.media_stream = null;
|
||||
notify = true;
|
||||
}
|
||||
|
||||
if (this.media_conn) {
|
||||
this.media_conn.close();
|
||||
this.media_conn = null;
|
||||
notify = true;
|
||||
}
|
||||
|
||||
if (notify) {
|
||||
owner.on_player_status("closed", "Server closed.");
|
||||
}
|
||||
}
|
||||
|
||||
private function log(msg:String):void {
|
||||
Utility.log(js_id, msg);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package
|
||||
{
|
||||
import flash.external.ExternalInterface;
|
||||
import flash.utils.setTimeout;
|
||||
|
||||
/**
|
||||
* the utility functions.
|
||||
*/
|
||||
public class Utility
|
||||
{
|
||||
/**
|
||||
* total log.
|
||||
*/
|
||||
public static var logData:String = "";
|
||||
|
||||
/**
|
||||
* whether string s endswith f.
|
||||
*/
|
||||
public static function stringEndswith(s:String, f:String):Boolean {
|
||||
return s && f && s.indexOf(f) == s.length - f.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether string s startswith f.
|
||||
*/
|
||||
public static function stringStartswith(s:String, f:String):Boolean {
|
||||
return s && f && s.indexOf(f) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* write log to trace and console.log.
|
||||
* @param msg the log message.
|
||||
*/
|
||||
public static function log(js_id:String, msg:String):void {
|
||||
if (js_id) {
|
||||
msg = "[" + new Date() +"][srs-player][" + js_id + "] " + msg;
|
||||
}
|
||||
|
||||
logData += msg + "\n";
|
||||
|
||||
trace(msg);
|
||||
|
||||
if (!flash.external.ExternalInterface.available) {
|
||||
flash.utils.setTimeout(log, 300, null, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ExternalInterface.call("console.log", msg);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,668 +0,0 @@
|
|||
package
|
||||
{
|
||||
import flash.display.Sprite;
|
||||
import flash.display.StageAlign;
|
||||
import flash.display.StageDisplayState;
|
||||
import flash.display.StageScaleMode;
|
||||
import flash.events.Event;
|
||||
import flash.events.FullScreenEvent;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.events.NetStatusEvent;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.external.ExternalInterface;
|
||||
import flash.media.SoundTransform;
|
||||
import flash.media.Video;
|
||||
import flash.net.NetConnection;
|
||||
import flash.net.NetStream;
|
||||
import flash.system.Security;
|
||||
import flash.ui.ContextMenu;
|
||||
import flash.ui.ContextMenuItem;
|
||||
import flash.utils.Timer;
|
||||
import flash.utils.getTimer;
|
||||
import flash.utils.setTimeout;
|
||||
|
||||
import flashx.textLayout.formats.Float;
|
||||
|
||||
public class srs_player extends Sprite
|
||||
{
|
||||
// user set id.
|
||||
private var js_id:String = null;
|
||||
// user set callback
|
||||
private var js_on_player_ready:String = null;
|
||||
private var js_on_player_metadata:String = null;
|
||||
private var js_on_player_timer:String = null;
|
||||
private var js_on_player_empty:String = null;
|
||||
private var js_on_player_full:String = null;
|
||||
private var js_on_player_status:String = null;
|
||||
|
||||
// play param, user set width and height
|
||||
private var user_w:int = 0;
|
||||
private var user_h:int = 0;
|
||||
private var user_buffer_time:Number = 0;
|
||||
private var user_max_buffer_time:Number = 0;
|
||||
private var user_volume:Number = 0;
|
||||
// user set dar den:num
|
||||
private var user_dar_den:int = 0;
|
||||
private var user_dar_num:int = 0;
|
||||
// user set fs(fullscreen) refer and percent.
|
||||
private var user_fs_refer:String = null;
|
||||
private var user_fs_percent:int = 0;
|
||||
|
||||
// media specified.
|
||||
private var media_video:Video = null;
|
||||
private var media_metadata:Object = {};
|
||||
private var media_timer:Timer = new Timer(300);
|
||||
|
||||
// controls.
|
||||
// flash donot allow js to set to fullscreen,
|
||||
// only allow user click to enter fullscreen.
|
||||
private var control_fs_mask:Sprite = new Sprite();
|
||||
|
||||
// the common player to play stream.
|
||||
private var player:Player = null;
|
||||
// the flashvars config.
|
||||
private var config:Object = null;
|
||||
|
||||
public function srs_player()
|
||||
{
|
||||
if (!this.stage) {
|
||||
this.addEventListener(Event.ADDED_TO_STAGE, this.system_on_add_to_stage);
|
||||
} else {
|
||||
this.system_on_add_to_stage(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* system event callback, when this control added to stage.
|
||||
* the main function.
|
||||
*/
|
||||
private function system_on_add_to_stage(evt:Event):void {
|
||||
this.removeEventListener(Event.ADDED_TO_STAGE, this.system_on_add_to_stage);
|
||||
|
||||
this.stage.align = StageAlign.TOP_LEFT;
|
||||
this.stage.scaleMode = StageScaleMode.NO_SCALE;
|
||||
|
||||
this.stage.addEventListener(FullScreenEvent.FULL_SCREEN, this.user_on_stage_fullscreen);
|
||||
|
||||
Security.allowDomain("*");
|
||||
|
||||
this.addChild(this.control_fs_mask);
|
||||
this.control_fs_mask.buttonMode = true;
|
||||
this.control_fs_mask.addEventListener(MouseEvent.CLICK, user_on_click_video);
|
||||
|
||||
this.contextMenu = new ContextMenu();
|
||||
this.contextMenu.hideBuiltInItems();
|
||||
|
||||
var flashvars:Object = this.root.loaderInfo.parameters;
|
||||
|
||||
if (!flashvars.hasOwnProperty("id")) {
|
||||
throw new Error("must specifies the id");
|
||||
}
|
||||
|
||||
this.config = flashvars;
|
||||
this.js_id = flashvars.id;
|
||||
this.js_on_player_ready = flashvars.on_player_ready;
|
||||
this.js_on_player_metadata = flashvars.on_player_metadata;
|
||||
this.js_on_player_timer = flashvars.on_player_timer;
|
||||
this.js_on_player_empty = flashvars.on_player_empty;
|
||||
this.js_on_player_full = flashvars.on_player_full;
|
||||
this.js_on_player_status = flashvars.on_player_status;
|
||||
|
||||
this.media_timer.addEventListener(TimerEvent.TIMER, this.system_on_timer);
|
||||
this.media_timer.start();
|
||||
|
||||
flash.utils.setTimeout(this.system_on_js_ready, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* system callack event, when js ready, register callback for js.
|
||||
* the actual main function.
|
||||
*/
|
||||
private function system_on_js_ready():void {
|
||||
if (!flash.external.ExternalInterface.available) {
|
||||
log("js not ready, try later.");
|
||||
flash.utils.setTimeout(this.system_on_js_ready, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
flash.external.ExternalInterface.addCallback("__play", this.js_call_play);
|
||||
flash.external.ExternalInterface.addCallback("__stop", this.js_call_stop);
|
||||
flash.external.ExternalInterface.addCallback("__pause", this.js_call_pause);
|
||||
flash.external.ExternalInterface.addCallback("__resume", this.js_call_resume);
|
||||
flash.external.ExternalInterface.addCallback("__set_dar", this.js_call_set_dar);
|
||||
flash.external.ExternalInterface.addCallback("__set_fs", this.js_call_set_fs_size);
|
||||
flash.external.ExternalInterface.addCallback("__set_bt", this.js_call_set_bt);
|
||||
flash.external.ExternalInterface.addCallback("__set_mbt", this.js_call_set_mbt);
|
||||
flash.external.ExternalInterface.addCallback("__dump_log", this.js_call_dump_log);
|
||||
|
||||
flash.external.ExternalInterface.call(this.js_on_player_ready, this.js_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* system callack event, timer to do some regular tasks.
|
||||
*/
|
||||
private function system_on_timer(evt:TimerEvent):void {
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
var ms:NetStream = player.stream();
|
||||
|
||||
if (!ms) {
|
||||
//log("stream is null, ignore timer event.");
|
||||
return;
|
||||
}
|
||||
|
||||
var rtime:Number = flash.utils.getTimer();
|
||||
var bitrate:Number = Number((ms.info.videoBytesPerSecond + ms.info.audioBytesPerSecond) * 8 / 1000);
|
||||
log("on timer, time=" + ms.time.toFixed(2) + "s, buffer=" + ms.bufferLength.toFixed(2) + "s"
|
||||
+ ", bitrate=" + bitrate.toFixed(1) + "kbps"
|
||||
+ ", fps=" + ms.currentFPS.toFixed(1)
|
||||
+ ", rtime=" + rtime.toFixed(0)
|
||||
);
|
||||
flash.external.ExternalInterface.call(
|
||||
this.js_on_player_timer, this.js_id, ms.time, ms.bufferLength,
|
||||
bitrate, ms.currentFPS, rtime
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* system callback event, when stream is empty.
|
||||
*/
|
||||
private function system_on_buffer_empty():void {
|
||||
var time:Number = flash.utils.getTimer();
|
||||
log("stream is empty at " + time + "ms");
|
||||
flash.external.ExternalInterface.call(this.js_on_player_empty, this.js_id, time);
|
||||
}
|
||||
private function system_on_buffer_full():void {
|
||||
var time:Number = flash.utils.getTimer();
|
||||
log("stream is full at " + time + "ms");
|
||||
flash.external.ExternalInterface.call(this.js_on_player_full, this.js_id, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* system callack event, when got metadata from stream.
|
||||
* or got video dimension change event(the DAR notification), to update the metadata manually.
|
||||
*/
|
||||
private function system_on_metadata(metadata:Object):void {
|
||||
if (!media_metadata) {
|
||||
media_metadata = {};
|
||||
}
|
||||
for (var k:String in metadata) {
|
||||
media_metadata[k] = metadata[k];
|
||||
}
|
||||
|
||||
// update the debug info.
|
||||
on_debug_info(media_metadata);
|
||||
update_context_items();
|
||||
|
||||
// for js.
|
||||
var obj:Object = __get_video_size_object();
|
||||
|
||||
obj.server = 'srs';
|
||||
obj.contributor = 'winlin';
|
||||
|
||||
if (srs_server != null) {
|
||||
obj.server = srs_server;
|
||||
}
|
||||
if (srs_primary != null) {
|
||||
obj.contributor = srs_primary;
|
||||
}
|
||||
if (srs_authors != null) {
|
||||
obj.contributor = srs_authors;
|
||||
}
|
||||
if (srs_id != null) {
|
||||
obj.cid = srs_id;
|
||||
}
|
||||
if (srs_pid != null) {
|
||||
obj.pid = srs_pid;
|
||||
}
|
||||
if (srs_server_ip != null) {
|
||||
obj.ip = srs_server_ip;
|
||||
}
|
||||
|
||||
var s:String = "";
|
||||
for (var key:String in obj) {
|
||||
s += key + "=" + obj[key] + " ";
|
||||
}
|
||||
log("metadata is " + s);
|
||||
|
||||
var code:int = flash.external.ExternalInterface.call(js_on_player_metadata, js_id, obj);
|
||||
if (code != 0) {
|
||||
throw new Error("callback on_player_metadata failed. code=" + code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* player callack event, when user click video to enter or leave fullscreen.
|
||||
*/
|
||||
private function user_on_stage_fullscreen(evt:FullScreenEvent):void {
|
||||
if (!evt.fullScreen) {
|
||||
__execute_user_set_dar();
|
||||
} else {
|
||||
__execute_user_enter_fullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* user event callback, js cannot enter the fullscreen mode, user must click to.
|
||||
*/
|
||||
private function user_on_click_video(evt:MouseEvent):void {
|
||||
if (!this.stage.allowsFullScreen) {
|
||||
log("donot allow fullscreen.");
|
||||
return;
|
||||
}
|
||||
|
||||
// enter fullscreen to get the fullscreen size correctly.
|
||||
if (this.stage.displayState == StageDisplayState.FULL_SCREEN) {
|
||||
this.stage.displayState = StageDisplayState.NORMAL;
|
||||
} else {
|
||||
this.stage.displayState = StageDisplayState.FULL_SCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function for js to call: to pause the stream. ignore if not play.
|
||||
*/
|
||||
private function js_call_pause():void {
|
||||
if (player && player.stream()) {
|
||||
player.stream().pause();
|
||||
log("user pause play");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function for js to call: to resume the stream. ignore if not play.
|
||||
*/
|
||||
private function js_call_resume():void {
|
||||
if (player && player.stream()) {
|
||||
player.stream().resume();
|
||||
log("user resume play");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dumps all log data.
|
||||
*/
|
||||
private function js_call_dump_log():String {
|
||||
return Utility.logData;
|
||||
}
|
||||
|
||||
/**
|
||||
* to set the DAR, for example, DAR=16:9 where num=16,den=9.
|
||||
* @param num, for example, 16.
|
||||
* use metadata width if 0.
|
||||
* use user specified width if -1.
|
||||
* @param den, for example, 9.
|
||||
* use metadata height if 0.
|
||||
* use user specified height if -1.
|
||||
*/
|
||||
private function js_call_set_dar(num:int, den:int):void {
|
||||
user_dar_num = num;
|
||||
user_dar_den = den;
|
||||
|
||||
flash.utils.setTimeout(__execute_user_set_dar, 0);
|
||||
log("user set dar to " + num + "/" + den);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the fullscreen size data.
|
||||
* @refer the refer fullscreen mode. it can be:
|
||||
* video: use video orignal size.
|
||||
* screen: use screen size to rescale video.
|
||||
* @param percent, the rescale percent, where
|
||||
* 100 means 100%.
|
||||
*/
|
||||
private function js_call_set_fs_size(refer:String, percent:int):void {
|
||||
user_fs_refer = refer;
|
||||
user_fs_percent = percent;
|
||||
log("user set refer to " + refer + ", percent to" + percent);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the stream buffer time in seconds.
|
||||
* @buffer_time the buffer time in seconds.
|
||||
*/
|
||||
private function js_call_set_bt(buffer_time:Number):void {
|
||||
if (player && player.stream()) {
|
||||
player.stream().bufferTime = buffer_time;
|
||||
log("user set bufferTime to " + buffer_time.toFixed(2) + "s");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the max stream buffer time in seconds.
|
||||
* @max_buffer_time the max buffer time in seconds.
|
||||
* @remark this is the key feature for realtime communication by flash.
|
||||
*/
|
||||
private function js_call_set_mbt(max_buffer_time:Number):void {
|
||||
if (player && player.stream()) {
|
||||
player.stream().bufferTimeMax = max_buffer_time;
|
||||
log("user set bufferTimeMax to " + max_buffer_time.toFixed(2) + "s");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function for js to call: to stop the stream. ignore if not play.
|
||||
*/
|
||||
private function js_call_stop():void {
|
||||
if (this.media_video) {
|
||||
this.removeChild(this.media_video);
|
||||
this.media_video = null;
|
||||
}
|
||||
|
||||
if (player) {
|
||||
player.close();
|
||||
player = null;
|
||||
}
|
||||
log("player stopped");
|
||||
}
|
||||
|
||||
// srs infos
|
||||
private var srs_server:String = null;
|
||||
private var srs_primary:String = null;
|
||||
private var srs_authors:String = null;
|
||||
private var srs_id:String = null;
|
||||
private var srs_pid:String = null;
|
||||
private var srs_server_ip:String = null;
|
||||
private function update_context_items():void {
|
||||
// for context menu
|
||||
var customItems:Array = [new ContextMenuItem("SrsPlayer")];
|
||||
if (srs_server != null) {
|
||||
customItems.push(new ContextMenuItem("Server: " + srs_server));
|
||||
}
|
||||
if (srs_primary != null) {
|
||||
customItems.push(new ContextMenuItem("Primary: " + srs_primary));
|
||||
}
|
||||
if (srs_authors != null) {
|
||||
customItems.push(new ContextMenuItem("Authors: " + srs_authors));
|
||||
}
|
||||
if (srs_server_ip != null) {
|
||||
customItems.push(new ContextMenuItem("SrsIp: " + srs_server_ip));
|
||||
}
|
||||
if (srs_pid != null) {
|
||||
customItems.push(new ContextMenuItem("SrsPid: " + srs_pid));
|
||||
}
|
||||
if (srs_id != null) {
|
||||
customItems.push(new ContextMenuItem("SrsId: " + srs_id));
|
||||
}
|
||||
contextMenu.customItems = customItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* server can set the debug info in _result of RTMP connect, or metadata.
|
||||
*/
|
||||
private function on_debug_info(data:*):void {
|
||||
if (data.hasOwnProperty("srs_server")) {
|
||||
srs_server = data.srs_server;
|
||||
}
|
||||
if (data.hasOwnProperty("srs_primary")) {
|
||||
srs_primary = data.srs_primary;
|
||||
}
|
||||
if (data.hasOwnProperty("srs_authors")) {
|
||||
srs_authors = data.srs_authors;
|
||||
}
|
||||
if (data.hasOwnProperty("srs_id")) {
|
||||
srs_id = data.srs_id;
|
||||
}
|
||||
if (data.hasOwnProperty("srs_pid")) {
|
||||
srs_pid = data.srs_pid;
|
||||
}
|
||||
if (data.hasOwnProperty("srs_server_ip")) {
|
||||
srs_server_ip = data.srs_server_ip;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function for js to call: to play the stream. stop then play.
|
||||
* @param url, the rtmp/http url to play.
|
||||
* @param _width, the player width.
|
||||
* @param _height, the player height.
|
||||
* @param buffer_time, the buffer time in seconds. recommend to >=0.5
|
||||
* @param max_buffer_time, the max buffer time in seconds. recommend to 3 x buffer_time.
|
||||
* @param volume, the volume, 0 is mute, 1 is 100%, 2 is 200%.
|
||||
*/
|
||||
private function js_call_play(url:String, _width:int, _height:int, buffer_time:Number, max_buffer_time:Number, volume:Number):void {
|
||||
this.user_w = _width;
|
||||
this.user_h = _height;
|
||||
this.user_buffer_time = buffer_time;
|
||||
this.user_max_buffer_time = max_buffer_time;
|
||||
this.user_volume = volume;
|
||||
log("start to play url: " + url + ", w=" + this.user_w + ", h=" + this.user_h
|
||||
+ ", buffer=" + buffer_time.toFixed(2) + "s, max_buffer=" + max_buffer_time.toFixed(2) + "s, volume=" + volume.toFixed(2)
|
||||
);
|
||||
|
||||
js_call_stop();
|
||||
|
||||
// trim last ?
|
||||
while (Utility.stringEndswith(url, "?")) {
|
||||
url = url.substr(0, url.length - 1);
|
||||
}
|
||||
|
||||
// create player.
|
||||
player = new Player(this);
|
||||
|
||||
// init player by config.
|
||||
player.init(config);
|
||||
|
||||
// play the url.
|
||||
player.play(url);
|
||||
}
|
||||
public function on_player_before_play():void {
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
var ms:NetStream = player.stream();
|
||||
if (!ms) {
|
||||
return;
|
||||
}
|
||||
|
||||
ms.soundTransform = new SoundTransform(user_volume);
|
||||
ms.bufferTime = user_buffer_time;
|
||||
ms.bufferTimeMax = user_max_buffer_time;
|
||||
ms.client = {};
|
||||
ms.client.onMetaData = system_on_metadata;
|
||||
}
|
||||
public function on_player_play():void {
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
media_video = new Video();
|
||||
media_video.width = user_w;
|
||||
media_video.height = user_h;
|
||||
media_video.attachNetStream(player.stream());
|
||||
media_video.smoothing = true;
|
||||
addChild(media_video);
|
||||
|
||||
__draw_black_background(user_w, user_h);
|
||||
|
||||
// lowest layer, for mask to cover it.
|
||||
setChildIndex(media_video, 0);
|
||||
}
|
||||
public function on_player_metadata(data:Object):void {
|
||||
system_on_metadata(data);
|
||||
}
|
||||
public function on_player_302(url:String):void {
|
||||
setTimeout(function():void{
|
||||
log("Async RTMP 302 Redirected.");
|
||||
js_call_play(url, user_w, user_h, user_buffer_time, user_max_buffer_time, user_volume);
|
||||
}, 1000);
|
||||
}
|
||||
public function on_player_dimension_change():void {
|
||||
system_on_metadata(media_metadata);
|
||||
}
|
||||
public function on_player_buffer_empty():void {
|
||||
system_on_buffer_empty();
|
||||
}
|
||||
public function on_player_buffer_full():void {
|
||||
system_on_buffer_full();
|
||||
}
|
||||
|
||||
public function on_player_status(code:String, desc:String):void {
|
||||
log("[STATUS] code=" + code + ", desc=" + desc);
|
||||
flash.external.ExternalInterface.call(this.js_on_player_status, this.js_id, code, desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the "right" size of video,
|
||||
* 1. initialize with the original video object size.
|
||||
* 2. override with metadata size if specified.
|
||||
* 3. override with codec size if specified.
|
||||
*/
|
||||
private function __get_video_size_object():Object {
|
||||
if (!media_video) {
|
||||
return {};
|
||||
}
|
||||
var obj:Object = {
|
||||
width: media_video.width,
|
||||
height: media_video.height
|
||||
};
|
||||
|
||||
// override with metadata size.
|
||||
if (this.media_metadata.hasOwnProperty("width")) {
|
||||
obj.width = this.media_metadata.width;
|
||||
}
|
||||
if (this.media_metadata.hasOwnProperty("height")) {
|
||||
obj.height = this.media_metadata.height;
|
||||
}
|
||||
|
||||
// override with codec size.
|
||||
if (media_video.videoWidth > 0) {
|
||||
obj.width = media_video.videoWidth;
|
||||
}
|
||||
if (media_video.videoHeight > 0) {
|
||||
obj.height = media_video.videoHeight;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* execute the enter fullscreen action.
|
||||
*/
|
||||
private function __execute_user_enter_fullscreen():void {
|
||||
if (!user_fs_refer || user_fs_percent <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// change to video size if refer to video.
|
||||
var obj:Object = __get_video_size_object();
|
||||
|
||||
// get the DAR
|
||||
var den:int = user_dar_den;
|
||||
var num:int = user_dar_num;
|
||||
|
||||
if (den == 0) {
|
||||
den = obj.height;
|
||||
}
|
||||
if (den == -1) {
|
||||
den = this.stage.fullScreenHeight;
|
||||
}
|
||||
|
||||
if (num == 0) {
|
||||
num = obj.width;
|
||||
}
|
||||
if (num == -1) {
|
||||
num = this.stage.fullScreenWidth;
|
||||
}
|
||||
|
||||
// for refer is screen.
|
||||
if (user_fs_refer == "screen") {
|
||||
obj = {
|
||||
width: this.stage.fullScreenWidth,
|
||||
height: this.stage.fullScreenHeight
|
||||
};
|
||||
}
|
||||
|
||||
// rescale to fs
|
||||
__update_video_size(num, den,
|
||||
obj.width * user_fs_percent / 100,
|
||||
obj.height * user_fs_percent / 100,
|
||||
this.stage.fullScreenWidth, this.stage.fullScreenHeight
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* for user set dar, or leave fullscreen to recover the dar.
|
||||
*/
|
||||
private function __execute_user_set_dar():void {
|
||||
// get the DAR
|
||||
var den:int = user_dar_den;
|
||||
var num:int = user_dar_num;
|
||||
|
||||
var obj:Object = __get_video_size_object();
|
||||
|
||||
if (den == 0) {
|
||||
den = obj.height;
|
||||
}
|
||||
if (den == -1) {
|
||||
den = this.user_h;
|
||||
}
|
||||
|
||||
if (num == 0) {
|
||||
num = obj.width;
|
||||
}
|
||||
if (num == -1) {
|
||||
num = this.user_w;
|
||||
}
|
||||
|
||||
__update_video_size(num, den, this.user_w, this.user_h, this.user_w, this.user_h);
|
||||
}
|
||||
|
||||
/**
|
||||
* update the video width and height,
|
||||
* according to the specifies DAR(den:num) and max size(w:h).
|
||||
* set the position of video(x,y) specifies by size(sw:sh),
|
||||
* and update the bg to size(sw:sh).
|
||||
* @param _num/_den the DAR. use to rescale the player together with paper size.
|
||||
* @param _w/_h the video draw paper size. used to rescale the player together with DAR.
|
||||
* @param _sw/_wh the stage size, >= paper size. used to center the player.
|
||||
*/
|
||||
private function __update_video_size(_num:int, _den:int, _w:int, _h:int, _sw:int, _sh:int):void {
|
||||
if (!this.media_video || _den <= 0 || _num <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set DAR.
|
||||
// calc the height by DAR
|
||||
var _height:int = _w * _den / _num;
|
||||
if (_height <= _h) {
|
||||
this.media_video.width = _w;
|
||||
this.media_video.height = _height;
|
||||
} else {
|
||||
// height overflow, calc the width by DAR
|
||||
var _width:int = _h * _num / _den;
|
||||
|
||||
this.media_video.width = _width;
|
||||
this.media_video.height = _h;
|
||||
}
|
||||
|
||||
// align center.
|
||||
this.media_video.x = (_sw - this.media_video.width) / 2;
|
||||
this.media_video.y = (_sh - this.media_video.height) / 2;
|
||||
|
||||
__draw_black_background(_sw, _sh);
|
||||
}
|
||||
|
||||
/**
|
||||
* draw black background and draw the fullscreen mask.
|
||||
*/
|
||||
private function __draw_black_background(_width:int, _height:int):void {
|
||||
// draw black bg.
|
||||
this.graphics.beginFill(0x00, 1.0);
|
||||
this.graphics.drawRect(0, 0, _width, _height);
|
||||
this.graphics.endFill();
|
||||
|
||||
// draw the fs mask.
|
||||
this.control_fs_mask.graphics.beginFill(0xff0000, 0);
|
||||
this.control_fs_mask.graphics.drawRect(0, 0, _width, _height);
|
||||
this.control_fs_mask.graphics.endFill();
|
||||
}
|
||||
|
||||
private function log(msg:String):void {
|
||||
Utility.log(js_id, msg);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
.accordion-group {
|
||||
width: 310px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/obs'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a id="srs_index" class="brand" href="#">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li class="active"><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<!-- for the log -->
|
||||
<div class="alert alert-danger fade in" id="txt_log">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><span id="txt_log_title">Warning:</span></strong>
|
||||
<span id="txt_log_msg">
|
||||
Flash推流已经很少用,建议用<a href="https://obsproject.com/" target="_blank">OBS</a>或<a href="http://ffmpeg.org/" target="_blank">FFMPEG</a>推流,
|
||||
如果一定要使用Flash推流请点<a id="https_publisher" href="srs_publisher2.html">这里</a>。
|
||||
</span>
|
||||
</div>
|
||||
<hr/>
|
||||
<footer>
|
||||
<p><a href="https://github.com/ossrs/srs">SRS Team © 2013</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
var l = window.location;
|
||||
var url = window.location.href;
|
||||
if (l.hostname !== 'localhost' && l.hostname !== '127.0.0.1' && l.protocol == 'http:') {
|
||||
// For flash publisher, must use HTTPS.
|
||||
url = window.location.href.replace('http:', 'https:');
|
||||
}
|
||||
|
||||
url = url.substr(0, url.lastIndexOf('/')) + '/srs_publisher2.html';
|
||||
$('#https_publisher').attr('href', url);
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<actionScriptProperties analytics="false" mainApplicationPath="srs_publisher.as" projectUUID="f002791f-ee2e-41b7-aa3a-a7af6c65aa58" version="10">
|
||||
<compiler additionalCompilerArguments="-locale en_US" autoRSLOrdering="true" copyDependentFiles="false" fteInMXComponents="false" generateAccessible="true" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="true" htmlPlayerVersionCheck="true" includeNetmonSwc="false" outputFolderPath="release" removeUnusedRSL="true" sourceFolderPath="src" strict="true" targetPlayerVersion="0.0.0" useApolloConfig="false" useDebugRSLSwfs="true" verifyDigests="true" warn="true">
|
||||
<compilerSourcePath/>
|
||||
<libraryPath defaultLinkType="0">
|
||||
<libraryPathEntry kind="4" path="">
|
||||
<excludedEntries>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_charts.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="1" linkType="1" path="${PROJECT_FRAMEWORKS}/locale/{locale}"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/advancedgrids.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_air.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/charts.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/framework.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/mx/mx.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/netmon.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/sparkskins.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/rpc.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/videoPlayer.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp_air.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/datavisualization.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flash-integration.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_flashflexkit.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_agent.swc" useDefaultLinkType="false"/>
|
||||
</excludedEntries>
|
||||
</libraryPathEntry>
|
||||
</libraryPath>
|
||||
<sourceAttachmentPath/>
|
||||
</compiler>
|
||||
<applications>
|
||||
<application path="srs_publisher.as"/>
|
||||
</applications>
|
||||
<modules/>
|
||||
<buildCSSFiles/>
|
||||
<flashCatalyst validateFlashCatalystCompatibility="false"/>
|
||||
</actionScriptProperties>
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>srs_publisher</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.adobe.flexbuilder.project.flexbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -1,3 +0,0 @@
|
|||
#Wed Dec 18 10:10:45 CST 2013
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=utf-8
|
Binary file not shown.
|
@ -1,462 +0,0 @@
|
|||
package
|
||||
{
|
||||
import flash.display.Sprite;
|
||||
import flash.display.StageAlign;
|
||||
import flash.display.StageScaleMode;
|
||||
import flash.events.Event;
|
||||
import flash.events.NetStatusEvent;
|
||||
import flash.external.ExternalInterface;
|
||||
import flash.media.Camera;
|
||||
import flash.media.H264Profile;
|
||||
import flash.media.H264VideoStreamSettings;
|
||||
import flash.media.Microphone;
|
||||
import flash.media.MicrophoneEnhancedMode;
|
||||
import flash.media.MicrophoneEnhancedOptions;
|
||||
import flash.media.SoundCodec;
|
||||
import flash.media.Video;
|
||||
import flash.net.NetConnection;
|
||||
import flash.net.NetStream;
|
||||
import flash.system.Security;
|
||||
import flash.system.SecurityPanel;
|
||||
import flash.ui.ContextMenu;
|
||||
import flash.ui.ContextMenuItem;
|
||||
import flash.utils.setTimeout;
|
||||
|
||||
public class srs_publisher extends Sprite
|
||||
{
|
||||
// user set id.
|
||||
private var js_id:String = null;
|
||||
// user set callback
|
||||
private var js_on_publisher_ready:String = null;
|
||||
private var js_on_publisher_error:String = null;
|
||||
private var js_on_publisher_warn:String = null;
|
||||
|
||||
// publish param url.
|
||||
private var user_url:String = null;
|
||||
// play param, user set width and height
|
||||
private var user_w:int = 0;
|
||||
private var user_h:int = 0;
|
||||
private var user_vcodec:Object = {};
|
||||
private var user_acodec:Object = {};
|
||||
|
||||
// media specified.
|
||||
private var media_conn:NetConnection = null;
|
||||
private var media_stream:NetStream = null;
|
||||
private var media_video:Video = null;
|
||||
private var media_camera:Camera = null;
|
||||
private var media_microphone:Microphone = null;
|
||||
|
||||
// error code.
|
||||
private const error_camera_get:int = 100;
|
||||
private const error_microphone_get:int = 101;
|
||||
private const error_camera_muted:int = 102;
|
||||
private const error_connection_closed:int = 103;
|
||||
private const error_connection_failed:int = 104;
|
||||
|
||||
public function srs_publisher()
|
||||
{
|
||||
if (!this.stage) {
|
||||
this.addEventListener(Event.ADDED_TO_STAGE, this.system_on_add_to_stage);
|
||||
} else {
|
||||
this.system_on_add_to_stage(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* system event callback, when this control added to stage.
|
||||
* the main function.
|
||||
*/
|
||||
private function system_on_add_to_stage(evt:Event):void {
|
||||
this.removeEventListener(Event.ADDED_TO_STAGE, this.system_on_add_to_stage);
|
||||
|
||||
this.stage.align = StageAlign.TOP_LEFT;
|
||||
this.stage.scaleMode = StageScaleMode.NO_SCALE;
|
||||
|
||||
this.contextMenu = new ContextMenu();
|
||||
this.contextMenu.hideBuiltInItems();
|
||||
|
||||
var flashvars:Object = this.root.loaderInfo.parameters;
|
||||
|
||||
if (!flashvars.hasOwnProperty("id")) {
|
||||
throw new Error("must specifies the id");
|
||||
}
|
||||
|
||||
this.js_id = flashvars.id;
|
||||
this.js_on_publisher_ready = flashvars.on_publisher_ready;
|
||||
this.js_on_publisher_error = flashvars.on_publisher_error;
|
||||
this.js_on_publisher_warn = flashvars.on_publisher_warn;
|
||||
|
||||
// initialized size.
|
||||
this.user_w = flashvars.width;
|
||||
this.user_h = flashvars.height;
|
||||
|
||||
// try to get the camera, if muted, alert the security and requires user to open it.
|
||||
var c:Camera = Camera.getCamera();
|
||||
if (c.muted) {
|
||||
Security.showSettings(SecurityPanel.PRIVACY);
|
||||
}
|
||||
|
||||
__show_local_camera(c);
|
||||
|
||||
flash.utils.setTimeout(this.system_on_js_ready, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* system callack event, when js ready, register callback for js.
|
||||
* the actual main function.
|
||||
*/
|
||||
private function system_on_js_ready():void {
|
||||
if (!flash.external.ExternalInterface.available) {
|
||||
trace("js not ready, try later.");
|
||||
flash.utils.setTimeout(this.system_on_js_ready, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
flash.external.ExternalInterface.addCallback("__publish", this.js_call_publish);
|
||||
flash.external.ExternalInterface.addCallback("__stop", this.js_call_stop);
|
||||
|
||||
var cameras:Array = Camera.names;
|
||||
var microphones:Array = Microphone.names;
|
||||
trace("retrieve system cameras(" + cameras + ") and microphones(" + microphones + ")");
|
||||
|
||||
flash.external.ExternalInterface.call(this.js_on_publisher_ready, this.js_id, cameras, microphones);
|
||||
}
|
||||
|
||||
/**
|
||||
* notify the js an error occur.
|
||||
*/
|
||||
private function system_error(code:int, desc:String):void {
|
||||
trace("system error, code=" + code + ", error=" + desc);
|
||||
flash.external.ExternalInterface.call(this.js_on_publisher_error, this.js_id, code);
|
||||
}
|
||||
private function system_warn(code:int, desc:String):void {
|
||||
trace("system warn, code=" + code + ", error=" + desc);
|
||||
flash.external.ExternalInterface.call(this.js_on_publisher_warn, this.js_id, code);
|
||||
}
|
||||
|
||||
// srs infos
|
||||
private var srs_server:String = null;
|
||||
private var srs_primary:String = null;
|
||||
private var srs_authors:String = null;
|
||||
private var srs_id:String = null;
|
||||
private var srs_pid:String = null;
|
||||
private var srs_server_ip:String = null;
|
||||
private function update_context_items():void {
|
||||
// for context menu
|
||||
var customItems:Array = [new ContextMenuItem("SrsPlayer")];
|
||||
if (srs_server != null) {
|
||||
customItems.push(new ContextMenuItem("Server: " + srs_server));
|
||||
}
|
||||
if (srs_primary != null) {
|
||||
customItems.push(new ContextMenuItem("Primary: " + srs_primary));
|
||||
}
|
||||
if (srs_authors != null) {
|
||||
customItems.push(new ContextMenuItem("Authors: " + srs_authors));
|
||||
}
|
||||
if (srs_server_ip != null) {
|
||||
customItems.push(new ContextMenuItem("SrsIp: " + srs_server_ip));
|
||||
}
|
||||
if (srs_pid != null) {
|
||||
customItems.push(new ContextMenuItem("SrsPid: " + srs_pid));
|
||||
}
|
||||
if (srs_id != null) {
|
||||
customItems.push(new ContextMenuItem("SrsId: " + srs_id));
|
||||
}
|
||||
contextMenu.customItems = customItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* publish stream to server.
|
||||
* @param url a string indicates the rtmp url to publish.
|
||||
* @param _width, the player width.
|
||||
* @param _height, the player height.
|
||||
* @param vcodec an object contains the video codec info.
|
||||
* @param acodec an object contains the audio codec info.
|
||||
*/
|
||||
private function js_call_publish(url:String, _width:int, _height:int, vcodec:Object, acodec:Object):void {
|
||||
trace("start to publish to " + url + ", vcodec " + JSON.stringify(vcodec) + ", acodec " + JSON.stringify(acodec));
|
||||
|
||||
this.user_url = url;
|
||||
this.user_w = _width;
|
||||
this.user_h = _height;
|
||||
this.user_vcodec = vcodec;
|
||||
this.user_acodec = acodec;
|
||||
|
||||
this.js_call_stop();
|
||||
|
||||
// microphone and camera
|
||||
var microphone:Microphone = null;
|
||||
//microphone = Microphone.getEnhancedMicrophone(acodec.device_code);
|
||||
if (!microphone) {
|
||||
microphone = Microphone.getMicrophone(acodec.device_code);
|
||||
}
|
||||
if(microphone == null){
|
||||
this.system_error(this.error_microphone_get, "failed to open microphone " + acodec.device_code + "(" + acodec.device_name + ")");
|
||||
return;
|
||||
}
|
||||
// ignore muted, for flash will require user to access it.
|
||||
|
||||
// Remark: the name is the index!
|
||||
var camera:Camera = Camera.getCamera(vcodec.device_code);
|
||||
if(camera == null){
|
||||
this.system_error(this.error_camera_get, "failed to open camera " + vcodec.device_code + "(" + vcodec.device_name + ")");
|
||||
return;
|
||||
}
|
||||
// ignore muted, for flash will require user to access it.
|
||||
// but we still warn user.
|
||||
if(camera && camera.muted){
|
||||
this.system_warn(this.error_camera_muted, "Access Denied, camera " + vcodec.device_code + "(" + vcodec.device_name + ") is muted");
|
||||
}
|
||||
|
||||
this.media_camera = camera;
|
||||
this.media_microphone = microphone;
|
||||
|
||||
this.media_conn = new NetConnection();
|
||||
this.media_conn.client = {};
|
||||
this.media_conn.client.onBWDone = function():void {};
|
||||
this.media_conn.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void {
|
||||
trace ("NetConnection: code=" + evt.info.code);
|
||||
|
||||
if (evt.info.hasOwnProperty("data") && evt.info.data) {
|
||||
if (evt.info.data.hasOwnProperty("srs_server")) {
|
||||
srs_server = evt.info.data.srs_server;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_primary")) {
|
||||
srs_primary = evt.info.data.srs_primary;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_authors")) {
|
||||
srs_authors = evt.info.data.srs_authors;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_id")) {
|
||||
srs_id = evt.info.data.srs_id;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_pid")) {
|
||||
srs_pid = evt.info.data.srs_pid;
|
||||
}
|
||||
if (evt.info.data.hasOwnProperty("srs_server_ip")) {
|
||||
srs_server_ip = evt.info.data.srs_server_ip;
|
||||
}
|
||||
update_context_items();
|
||||
}
|
||||
|
||||
if (evt.info.code == "NetConnection.Connect.Closed") {
|
||||
js_call_stop();
|
||||
system_error(error_connection_closed, "server closed the connection");
|
||||
return;
|
||||
}
|
||||
if (evt.info.code == "NetConnection.Connect.Failed") {
|
||||
js_call_stop();
|
||||
system_error(error_connection_failed, "connect to server failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: FIXME: failed event.
|
||||
if (evt.info.code != "NetConnection.Connect.Success") {
|
||||
return;
|
||||
}
|
||||
|
||||
media_stream = new NetStream(media_conn);
|
||||
media_stream.client = {};
|
||||
media_stream.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void {
|
||||
trace ("NetStream: code=" + evt.info.code);
|
||||
|
||||
// TODO: FIXME: failed event.
|
||||
});
|
||||
|
||||
__build_video_codec(media_stream, camera, vcodec);
|
||||
__build_audio_codec(media_stream, microphone, acodec);
|
||||
|
||||
if (media_microphone) {
|
||||
media_stream.attachAudio(microphone);
|
||||
}
|
||||
if (media_camera) {
|
||||
media_stream.attachCamera(camera);
|
||||
}
|
||||
|
||||
var streamName:String = url.substr(url.lastIndexOf("/"));
|
||||
media_stream.publish(streamName);
|
||||
|
||||
__show_local_camera(media_camera);
|
||||
});
|
||||
|
||||
var tcUrl:String = this.user_url.substr(0, this.user_url.lastIndexOf("/"));
|
||||
this.media_conn.connect(tcUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* function for js to call: to stop the stream. ignore if not publish.
|
||||
*/
|
||||
private function js_call_stop():void {
|
||||
if (this.media_stream) {
|
||||
this.media_stream.attachAudio(null);
|
||||
this.media_stream.attachCamera(null);
|
||||
this.media_stream.close();
|
||||
this.media_stream = null;
|
||||
}
|
||||
if (this.media_conn) {
|
||||
this.media_conn.close();
|
||||
this.media_conn = null;
|
||||
}
|
||||
}
|
||||
|
||||
private function __build_audio_codec(stream:NetStream, m:Microphone, acodec:Object):void {
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if no microphone, donot set the params.
|
||||
if(m == null){
|
||||
return;
|
||||
}
|
||||
|
||||
// use default values.
|
||||
var microEncodeQuality:int = 8;
|
||||
var microRate:int = 22; // 22 === 22050 Hz
|
||||
|
||||
trace("[Publish] audio encoding parameters: "
|
||||
+ "audio(microphone) codec=" + acodec.codec + "encodeQuality=" + microEncodeQuality
|
||||
+ ", rate=" + microRate + "(22050Hz)"
|
||||
);
|
||||
|
||||
// The encoded speech quality when using the Speex codec. Possible values are from 0 to 10. The default value is 6. Higher numbers
|
||||
// represent higher quality but require more bandwidth, as shown in the following table. The bit rate values that are listed represent
|
||||
// net bit rates and do not include packetization overhead.
|
||||
m.encodeQuality = microEncodeQuality;
|
||||
|
||||
// The rate at which the microphone is capturing sound, in kHz. Acceptable values are 5, 8, 11, 22, and 44. The default value is 8 kHz
|
||||
// if your sound capture device supports this value. Otherwise, the default value is the next available capture level above 8 kHz that
|
||||
// your sound capture device supports, usually 11 kHz.
|
||||
m.rate = microRate;
|
||||
|
||||
// see: http://www.adobe.com/cn/devnet/flashplayer/articles/acoustic-echo-cancellation.html
|
||||
if (acodec.codec == "nellymoser") {
|
||||
m.codec = SoundCodec.NELLYMOSER;
|
||||
} else if (acodec.codec == "pcma") {
|
||||
m.codec = SoundCodec.PCMA;
|
||||
} else if (acodec.codec == "pcmu") {
|
||||
m.codec = SoundCodec.PCMU;
|
||||
} else {
|
||||
m.codec = SoundCodec.SPEEX;
|
||||
}
|
||||
m.framesPerPacket = 1;
|
||||
}
|
||||
private function __build_video_codec(stream:NetStream, c:Camera, vcodec:Object):void {
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(vcodec.codec == "vp6"){
|
||||
trace("use VP6, donot use H.264 publish encoding.");
|
||||
return;
|
||||
}
|
||||
|
||||
var x264profile:String = (vcodec.profile == "main") ? H264Profile.MAIN : H264Profile.BASELINE;
|
||||
var x264level:String = vcodec.level;
|
||||
var cameraFps:Number = Number(vcodec.fps);
|
||||
var x264KeyFrameInterval:int = int(vcodec.gop * cameraFps);
|
||||
var cameraWidth:int = String(vcodec.size).split("x")[0];
|
||||
var cameraHeight:int = String(vcodec.size).split("x")[1];
|
||||
var cameraBitrate:int = int(vcodec.bitrate);
|
||||
|
||||
// use default values.
|
||||
var cameraQuality:int = 85;
|
||||
|
||||
trace("[Publish] video h.264(x264) encoding parameters: "
|
||||
+ "profile=" + x264profile
|
||||
+ ", level=" + x264level
|
||||
+ ", keyFrameInterval(gop)=" + x264KeyFrameInterval
|
||||
+ "; video(camera) width=" + cameraWidth
|
||||
+ ", height=" + cameraHeight
|
||||
+ ", fps=" + cameraFps
|
||||
+ ", bitrate=" + cameraBitrate
|
||||
+ ", quality=" + cameraQuality
|
||||
);
|
||||
|
||||
var h264Settings:H264VideoStreamSettings = new H264VideoStreamSettings();
|
||||
// we MUST set its values first, then set the NetStream.videoStreamSettings, or it will keep the origin values.
|
||||
h264Settings.setProfileLevel(x264profile, x264level);
|
||||
stream.videoStreamSettings = h264Settings;
|
||||
// the setKeyFrameInterval/setMode/setQuality use the camera settings.
|
||||
// http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/VideoStreamSettings.html
|
||||
// Note This feature will be supported in future releases of Flash Player and AIR, for now, Camera parameters are used.
|
||||
//
|
||||
//h264Settings.setKeyFrameInterval(4);
|
||||
//h264Settings.setMode(800, 600, 15);
|
||||
//h264Settings.setQuality(500, 0);
|
||||
|
||||
// set the camera and microphone.
|
||||
|
||||
// setKeyFrameInterval(keyFrameInterval:int):void
|
||||
// keyFrameInterval:int — A value that specifies which video frames are transmitted in full (as keyframes) instead of being
|
||||
// interpolated by the video compression algorithm. A value of 1 means that every frame is a keyframe, a value of 3 means
|
||||
// that every third frame is a keyframe, and so on. Acceptable values are 1 through 48.
|
||||
c.setKeyFrameInterval(x264KeyFrameInterval);
|
||||
|
||||
// setMode(width:int, height:int, fps:Number, favorArea:Boolean = true):void
|
||||
// width:int — The requested capture width, in pixels. The default value is 160.
|
||||
// height:int — The requested capture height, in pixels. The default value is 120.
|
||||
// fps:Number — The requested rate at which the camera should capture data, in frames per second. The default value is 15.
|
||||
c.setMode(cameraWidth, cameraHeight, cameraFps);
|
||||
|
||||
// setQuality(bandwidth:int, quality:int):void
|
||||
// bandwidth:int — Specifies the maximum amount of bandwidth that the current outgoing video feed can use, in bytes per second.
|
||||
// To specify that the video can use as much bandwidth as needed to maintain the value of quality, pass 0 for bandwidth.
|
||||
// The default value is 16384.
|
||||
// quality:int — An integer that specifies the required level of picture quality, as determined by the amount of compression
|
||||
// being applied to each video frame. Acceptable values range from 1 (lowest quality, maximum compression) to 100
|
||||
// (highest quality, no compression). To specify that picture quality can vary as needed to avoid exceeding bandwidth,
|
||||
// pass 0 for quality.
|
||||
// winlin:
|
||||
// bandwidth is in Bps not kbps.
|
||||
// quality=1 is lowest quality, 100 is highest quality.
|
||||
c.setQuality(cameraBitrate / 8.0 * 1000, cameraQuality);
|
||||
}
|
||||
|
||||
private function __show_local_camera(c:Camera):void {
|
||||
if (this.media_video) {
|
||||
this.media_video.attachCamera(null);
|
||||
this.removeChild(this.media_video);
|
||||
this.media_video = null;
|
||||
}
|
||||
|
||||
// show local camera
|
||||
media_video = new Video();
|
||||
media_video.attachCamera(c);
|
||||
media_video.smoothing = true;
|
||||
addChild(media_video);
|
||||
|
||||
// rescale the local camera.
|
||||
var cw:Number = user_h * c.width / c.height;
|
||||
if (cw > user_w) {
|
||||
var ch:Number = user_w * c.height / c.width;
|
||||
media_video.width = user_w;
|
||||
media_video.height = ch;
|
||||
} else {
|
||||
media_video.width = cw;
|
||||
media_video.height = user_h;
|
||||
}
|
||||
media_video.x = (user_w - media_video.width) / 2;
|
||||
media_video.y = (user_h - media_video.height) / 2;
|
||||
|
||||
__draw_black_background(user_w, user_h);
|
||||
|
||||
// lowest layer, for mask to cover it.
|
||||
setChildIndex(media_video, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* draw black background and draw the fullscreen mask.
|
||||
*/
|
||||
private function __draw_black_background(_width:int, _height:int):void {
|
||||
// draw black bg.
|
||||
this.graphics.beginFill(0x00, 1.0);
|
||||
this.graphics.drawRect(0, 0, _width, _height);
|
||||
this.graphics.endFill();
|
||||
|
||||
// draw the fs mask.
|
||||
//this.control_fs_mask.graphics.beginFill(0xff0000, 0);
|
||||
//this.control_fs_mask.graphics.drawRect(0, 0, _width, _height);
|
||||
//this.control_fs_mask.graphics.endFill();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,450 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/srspublisher'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a id="srs_index" class="brand" href="#">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li class="active"><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div name="detect_flash">
|
||||
<div id="main_flash_alert" class="alert alert-danger fade in hide">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><p>Usage:</p></strong>
|
||||
<p>
|
||||
请点击下面的图标,启用Flash
|
||||
</p>
|
||||
<p>
|
||||
若没有见到这个图标,Chrome浏览器请打开
|
||||
<span class="text-info">chrome://settings/content/flash</span> 并修改为"Ask first"。
|
||||
</p>
|
||||
</div>
|
||||
<div id="main_flash_hdr" class="hide">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main_content" class="hide">
|
||||
<div class="alert alert-danger fade in">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><span>Remark:</span></strong>
|
||||
<span>Flash推流只支持H.264+Speex,音频不支持AAC,所以无法输出HLS</span>
|
||||
</div>
|
||||
<div class="alert alert-info fade in" id="txt_log">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<strong><span id="txt_log_title">Usage:</span></strong>
|
||||
<span id="txt_log_msg">设置编码参数,点“发布视频”,允许Flash访问摄像头即可推流</span>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="form-inline">
|
||||
<button class="btn" id="btn_video_settings">视频编码配置</button>
|
||||
<button class="btn" id="btn_audio_settings">音频编码配置</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="form-inline">
|
||||
发布地址:
|
||||
<input type="text" id="txt_url" class="input-xxlarge" value=""></input>
|
||||
<button class="btn btn-primary" id="btn_publish">发布视频</button>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="cb_preview" checked>预览
|
||||
</label>
|
||||
<a id="txt_play_realtime" class="input-xxlarge" href="#">RTMP播放地址(请发布视频)</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="video_modal" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>视频编码</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_cameras">
|
||||
摄像头
|
||||
<a id="sl_cameras_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span4" id="sl_cameras"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_vcodec">
|
||||
Codec
|
||||
<a id="sl_cameras_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span2" id="sl_vcodec"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_profile">
|
||||
Profile
|
||||
<a id="sl_profile_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span2" id="sl_profile"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_level">
|
||||
Level
|
||||
<a id="sl_level_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span2" id="sl_level"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_gop">
|
||||
GOP
|
||||
<a id="sl_gop_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span2" id="sl_gop"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_size">
|
||||
尺寸
|
||||
<a id="sl_size_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span2" id="sl_size"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_fps">
|
||||
帧率
|
||||
<a id="sl_fps_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span2" id="sl_fps"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_bitrate">
|
||||
码率
|
||||
<a id="sl_bitrate_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span2" id="sl_bitrate"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">设置</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="audio_modal" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>音频编码</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_microphones">
|
||||
麦克风
|
||||
<a id="worker_id_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span4" id="sl_microphones"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="sl_acodec">
|
||||
编码
|
||||
<a id="sl_acodec_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
|
||||
<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<select class="span2" id="sl_acodec"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">设置</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<span class="accordion-toggle">
|
||||
<strong>本地摄像头</strong>
|
||||
</span>
|
||||
</div>
|
||||
<div class="accordion-body collapse in">
|
||||
<div class="accordion-inner">
|
||||
<div id="local_publisher"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<span class="accordion-toggle">
|
||||
<strong>远程服务器</strong>
|
||||
<a id="low_latecy_tips" href="#" data-toggle="tooltip" data-placement="top" title="">
|
||||
低延时<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
<a id="realtime_player_url" href="#" data-toggle="tooltip" data-placement="top" title="">
|
||||
播放地址<img src="img/tooltip.png"/>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="accordion-body collapse in">
|
||||
<div class="accordion-inner">
|
||||
<div id="realtime_player"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p></p>
|
||||
<p><a href="https://github.com/ossrs/srs">SRS Team © 2013</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||
<script type="text/javascript" src="js/json2.js"></script>
|
||||
<script type="text/javascript" src="js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="js/srs.log.js"></script>
|
||||
<script type="text/javascript" src="js/srs.player.js"></script>
|
||||
<script type="text/javascript" src="js/srs.publisher.js"></script>
|
||||
<script type="text/javascript" src="js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="js/winlin.utility.js"></script>
|
||||
<script type="text/javascript">
|
||||
var __on_flash_ready = null;
|
||||
|
||||
$(function(){
|
||||
// 探测Flash是否正常启用。
|
||||
$('#main_flash_hdr').html(
|
||||
'\
|
||||
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="100%" height="100%"> \
|
||||
<param name="movie" value="srs_player/release/srs_player.swf"> \
|
||||
<param name="quality" value="autohigh"> \
|
||||
<param name="swliveconnect" value="true"> \
|
||||
<param name="allowScriptAccess" value="always"> \
|
||||
<param name="bgcolor" value="#0"> \
|
||||
<param name="allowFullScreen" value="true"> \
|
||||
<param name="wmode" value="opaque"> \
|
||||
<param name="FlashVars" value="log=1"> \
|
||||
<param name="flashvars" value="id=1&on_player_ready=__on_flash_ready"> \
|
||||
<embed src="srs_player/release/srs_player.swf" width="100%" height="100%" \
|
||||
quality="autohigh" bgcolor="#0" align="middle" allowfullscreen="true" allowscriptaccess="always" \
|
||||
type="application/x-shockwave-flash" swliveconnect="true" wmode="opaque" \
|
||||
flashvars="id=1&on_player_ready=__on_flash_ready" \
|
||||
pluginspage="http://www.macromedia.com/go/getflashplayer"> \
|
||||
</object> \
|
||||
'
|
||||
);
|
||||
$('#main_flash_hdr').show();
|
||||
|
||||
var showFlashHdr = setTimeout(function(){
|
||||
$('#main_flash_alert').show();
|
||||
}, 300);
|
||||
|
||||
__on_flash_ready = function (id) {
|
||||
clearTimeout(showFlashHdr);
|
||||
|
||||
$('#main_flash_alert').hide();
|
||||
$('#main_flash_hdr').hide();
|
||||
$('#main_content').show();
|
||||
|
||||
autoLoadPage();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var srs_publisher = null;
|
||||
var realtime_player = null;
|
||||
|
||||
var query = parse_query_string();
|
||||
var autoLoadPage = function() {
|
||||
// get the vhost and port to set the default url.
|
||||
// for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
|
||||
// url set to: rtmp://demo:1935/live/livestream
|
||||
srs_init_rtmp("#txt_url", null);
|
||||
|
||||
if (query.agent == "true") {
|
||||
document.write(navigator.userAgent);
|
||||
return;
|
||||
}
|
||||
|
||||
$("#btn_video_settings").click(function(){
|
||||
$("#video_modal").modal({show:true});
|
||||
});
|
||||
$("#btn_audio_settings").click(function(){
|
||||
$("#audio_modal").modal({show:true});
|
||||
});
|
||||
|
||||
$("#low_latecy_tips").tooltip({
|
||||
title: "服务器不转码直接转发FLASH编码器的流,所以延迟比支持HLS的流要低很多"
|
||||
});
|
||||
$("#realtime_player_url").tooltip({
|
||||
title: "右键复制RTMP地址"
|
||||
});
|
||||
|
||||
$("#btn_publish").click(on_user_publish);
|
||||
|
||||
// for publish, we use randome stream name.
|
||||
$("#txt_url").val($("#txt_url").val() + "." + new Date().getTime());
|
||||
|
||||
// start the publisher.
|
||||
srs_publisher = new SrsPublisher("local_publisher", 430, 185);
|
||||
srs_publisher.on_publisher_ready = function(cameras, microphones) {
|
||||
srs_publisher_initialize_page(
|
||||
cameras, microphones,
|
||||
"#sl_cameras", "#sl_microphones",
|
||||
"#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",
|
||||
"#sl_fps", "#sl_bitrate",
|
||||
"#sl_acodec"
|
||||
);
|
||||
};
|
||||
srs_publisher.on_publisher_error = function(code, desc) {
|
||||
if (!on_publish_stop()) {
|
||||
return;
|
||||
}
|
||||
error(code, desc + "请重试。");
|
||||
};
|
||||
srs_publisher.on_publisher_warn = function(code, desc) {
|
||||
warn(code, desc);
|
||||
};
|
||||
srs_publisher.start();
|
||||
|
||||
// if no play specified, donot show the player, for debug the publisher.
|
||||
if (query.no_play != "true") {
|
||||
// start the realtime player.
|
||||
realtime_player = new SrsPlayer("realtime_player", 430, 185);
|
||||
realtime_player.on_player_ready = function() {
|
||||
this.set_bt(0.8);
|
||||
};
|
||||
realtime_player.on_player_metadata = function(metadata) {
|
||||
this.set_dar(0, 0);
|
||||
this.set_fs("screen", 100);
|
||||
}
|
||||
realtime_player.start();
|
||||
}
|
||||
};
|
||||
|
||||
function on_publish_stop() {
|
||||
if (!srs_can_republish()) {
|
||||
$("#btn_join").attr("disabled", true);
|
||||
error(0, "您使用的浏览器很弱,请关闭页面后重新打开页面(刷新也不管用)。<br/>推荐使用Chrome浏览器,支持重试");
|
||||
|
||||
srs_log_disabled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function update_play_url() {
|
||||
var url = $("#txt_url").val();
|
||||
var ret = srs_parse_rtmp_url(url);
|
||||
|
||||
var remote_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app + "/" + ret.stream + '?vhost=' + ret.vhost;
|
||||
$("#realtime_player_url").attr("href", url).attr("target", "_blank");
|
||||
|
||||
var srs_player_rt_url = "http://" + query.host + query.dir + "/srs_player.html?";
|
||||
srs_player_rt_url += "vhost=" + ret.vhost + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
|
||||
srs_player_rt_url += "&autostart=true";
|
||||
|
||||
$("#txt_play_realtime").text("RTMP播放地址").attr("href", srs_player_rt_url).attr("target", "_blank");
|
||||
}
|
||||
function on_user_publish() {
|
||||
if ($("#btn_publish").text() == "停止发布") {
|
||||
srs_publisher.stop();
|
||||
$("#btn_publish").text("发布视频");
|
||||
|
||||
if (!on_publish_stop()) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$("#btn_publish").text("停止发布");
|
||||
|
||||
update_play_url();
|
||||
|
||||
var url = $("#txt_url").val();
|
||||
var vcodec = {};
|
||||
var acodec = {};
|
||||
srs_publiser_get_codec(
|
||||
vcodec, acodec,
|
||||
"#sl_cameras", "#sl_microphones",
|
||||
"#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",
|
||||
"#sl_fps", "#sl_bitrate",
|
||||
"#sl_acodec"
|
||||
);
|
||||
|
||||
info("开始推流到服务器");
|
||||
srs_publisher.publish(url, vcodec, acodec);
|
||||
|
||||
if (!$("#cb_preview").is(":checked")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (realtime_player) {
|
||||
// directly play the url for the realtime player.
|
||||
realtime_player.stop();
|
||||
realtime_player.play(url);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<actionScriptProperties analytics="false" mainApplicationPath="srs_reuse_conn.as" projectUUID="ccfd5c0a-9963-467a-8739-75ac79faaef5" version="10">
|
||||
<compiler additionalCompilerArguments="-locale en_US" autoRSLOrdering="true" copyDependentFiles="true" fteInMXComponents="false" generateAccessible="true" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="true" htmlPlayerVersionCheck="true" includeNetmonSwc="false" outputFolderPath="release" removeUnusedRSL="true" sourceFolderPath="src" strict="true" targetPlayerVersion="0.0.0" useApolloConfig="false" useDebugRSLSwfs="true" verifyDigests="true" warn="true">
|
||||
<compilerSourcePath/>
|
||||
<libraryPath defaultLinkType="0">
|
||||
<libraryPathEntry kind="4" path="">
|
||||
<excludedEntries>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_charts.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="1" linkType="1" path="${PROJECT_FRAMEWORKS}/locale/{locale}"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/advancedgrids.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_air.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/charts.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/framework.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/mx/mx.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/netmon.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/sparkskins.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/rpc.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/videoPlayer.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp_air.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/datavisualization.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/spark_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flash-integration.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_flashflexkit.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_agent.swc" useDefaultLinkType="false"/>
|
||||
</excludedEntries>
|
||||
</libraryPathEntry>
|
||||
<libraryPathEntry kind="3" linkType="1" path="FlashCS5UI.swc" useDefaultLinkType="false"/>
|
||||
</libraryPath>
|
||||
<sourceAttachmentPath/>
|
||||
</compiler>
|
||||
<applications>
|
||||
<application path="srs_reuse_conn.as"/>
|
||||
</applications>
|
||||
<modules/>
|
||||
<buildCSSFiles/>
|
||||
<flashCatalyst validateFlashCatalystCompatibility="false"/>
|
||||
</actionScriptProperties>
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>srs_reuse_conn</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.adobe.flexbuilder.project.flexbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -1,3 +0,0 @@
|
|||
#Sat Nov 22 18:40:22 CST 2014
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=utf-8
|
Binary file not shown.
Binary file not shown.
|
@ -1,123 +0,0 @@
|
|||
package
|
||||
{
|
||||
import fl.controls.Button;
|
||||
import fl.controls.TextInput;
|
||||
|
||||
import flash.display.Sprite;
|
||||
import flash.display.StageAlign;
|
||||
import flash.display.StageScaleMode;
|
||||
import flash.events.Event;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.events.NetStatusEvent;
|
||||
import flash.media.Video;
|
||||
import flash.net.NetConnection;
|
||||
import flash.net.NetStream;
|
||||
|
||||
[SWF(backgroundColor="0xEEEEEE",frameRate="30",width="1024",height="576")]
|
||||
public class srs_reuse_conn extends Sprite
|
||||
{
|
||||
public function srs_reuse_conn()
|
||||
{
|
||||
if (stage) {
|
||||
onAddedToStage(null);
|
||||
} else {
|
||||
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
|
||||
}
|
||||
}
|
||||
|
||||
private function onAddedToStage(evt:Event):void
|
||||
{
|
||||
stage.align = StageAlign.TOP_LEFT;
|
||||
stage.scaleMode = StageScaleMode.NO_SCALE;
|
||||
|
||||
var txtUrl:TextInput = new TextInput();
|
||||
var btnConn:Button = new Button();
|
||||
var btnPlay:Button = new Button();
|
||||
|
||||
txtUrl.x = 10;
|
||||
txtUrl.y = 10;
|
||||
txtUrl.width = 400;
|
||||
txtUrl.text = "rtmp://dev/live/livestream";
|
||||
addChild(txtUrl);
|
||||
|
||||
btnConn.label = "Connect";
|
||||
btnConn.x = txtUrl.x + txtUrl.width + 10;
|
||||
btnConn.y = txtUrl.y;
|
||||
btnConn.width = 100;
|
||||
addChild(btnConn);
|
||||
|
||||
btnPlay.label = "Play";
|
||||
btnPlay.x = btnConn.x + btnConn.width + 10;
|
||||
btnPlay.y = btnConn.y;
|
||||
btnPlay.width = 100;
|
||||
addChild(btnPlay);
|
||||
|
||||
var video:Video = new Video();
|
||||
video.x = txtUrl.x;
|
||||
video.y = txtUrl.y + txtUrl.height + 10;
|
||||
addChild(video);
|
||||
|
||||
var conn:NetConnection = null;
|
||||
var stream:NetStream = null;
|
||||
|
||||
var tcUrl:Function = function():String {
|
||||
var url:String = txtUrl.text;
|
||||
return url.substr(0, url.lastIndexOf("/"));
|
||||
}
|
||||
var streamName:Function = function():String {
|
||||
var url:String = txtUrl.text;
|
||||
return url.substr(tcUrl().length + 1);
|
||||
}
|
||||
|
||||
var closeConnection:Function = function():void {
|
||||
if (stream) {
|
||||
stream.close();
|
||||
stream = null;
|
||||
}
|
||||
if (conn) {
|
||||
conn.close();
|
||||
conn = null;
|
||||
}
|
||||
btnConn.label = "Connect";
|
||||
btnPlay.visible = false;
|
||||
};
|
||||
|
||||
btnPlay.visible = false;
|
||||
btnConn.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
|
||||
if (btnConn.label == "Connect") {
|
||||
conn = new NetConnection();
|
||||
conn.client = {
|
||||
onBWDone: function():void{}
|
||||
};
|
||||
conn.addEventListener(NetStatusEvent.NET_STATUS, function(ne:NetStatusEvent):void {
|
||||
if (ne.info.code == "NetConnection.Connect.Success") {
|
||||
btnPlay.visible = true;
|
||||
} else if (ne.info.code == "NetConnection.Connect.Closed") {
|
||||
closeConnection();
|
||||
}
|
||||
trace(ne.info.code);
|
||||
});
|
||||
conn.connect(tcUrl());
|
||||
btnConn.label = "Close";
|
||||
} else {
|
||||
closeConnection();
|
||||
}
|
||||
});
|
||||
btnPlay.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
|
||||
if (stream) {
|
||||
stream.close();
|
||||
stream = null;
|
||||
}
|
||||
stream = new NetStream(conn);
|
||||
stream.client = {
|
||||
onMetaData: function(metadata:Object):void {
|
||||
video.width = metadata.width;
|
||||
video.height = metadata.height;
|
||||
}
|
||||
};
|
||||
video.attachNetStream(stream);
|
||||
stream.play(streamName());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SRS</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
|
||||
<style>
|
||||
body{
|
||||
padding-top: 55px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/vlc'/>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a id="srs_index" class="brand" href="#">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li class="active"><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<iframe id="main_frame" width="100%" height="600" frameBorder="0"></iframe>
|
||||
</div>
|
||||
<div class="container">
|
||||
<hr>
|
||||
<footer>
|
||||
<p><a href="https://github.com/ossrs/srs">SRS Team © 2013</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||
<script type="text/javascript" src="js/srs.page.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
update_nav();
|
||||
$("#main_frame").attr("src", "http://www.videolan.org/vlc/");
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Netscape Portable Runtime library.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Silicon Graphics, Inc.
|
||||
#
|
||||
# Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
# Graphics, Inc. All Rights Reserved.
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU General Public License Version 2 or later (the
|
||||
# "GPL"), in which case the provisions of the GPL are applicable
|
||||
# instead of those above. If you wish to allow use of your
|
||||
# version of this file only under the terms of the GPL and not to
|
||||
# allow others to use your version of this file under the MPL,
|
||||
# indicate your decision by deleting the provisions above and
|
||||
# replace them with the notice and other provisions required by
|
||||
# the GPL. If you do not delete the provisions above, a recipient
|
||||
# may use your version of this file under either the MPL or the
|
||||
# GPL.
|
||||
|
||||
##########################
|
||||
# Target dir and cc:
|
||||
CC = cc
|
||||
TARGETDIR = objs
|
||||
|
||||
##########################
|
||||
# Supported OSes:
|
||||
OS = LINUX
|
||||
|
||||
ifneq ($(shell test -f /usr/include/sys/epoll.h && echo yes), yes)
|
||||
default:
|
||||
@echo "epoll not found"
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
EXTRA_OBJS = $(TARGETDIR)/md.o
|
||||
|
||||
CFLAGS =
|
||||
OTHER_FLAGS += -Wall -g -O0
|
||||
DEFINES = -D$(OS) -DDEBUG -DMD_HAVE_EPOLL -DMALLOC_STACK
|
||||
|
||||
##########################
|
||||
# Other possible defines:
|
||||
# To use malloc(3) instead of mmap(2) for stack allocation:
|
||||
# DEFINES += -DMALLOC_STACK
|
||||
#
|
||||
# To provision more than the default 16 thread-specific-data keys
|
||||
# (but not too many!):
|
||||
# DEFINES += -DST_KEYS_MAX=<n>
|
||||
#
|
||||
# Note that you can also add these defines by specifying them as
|
||||
# make/gmake arguments (without editing this Makefile). For example:
|
||||
#
|
||||
# make EXTRA_CFLAGS=-UMD_HAVE_EPOLL <target>
|
||||
#
|
||||
##########################
|
||||
|
||||
CFLAGS += $(DEFINES) $(OTHER_FLAGS) $(EXTRA_CFLAGS)
|
||||
|
||||
OBJS = $(TARGETDIR)/sched.o \
|
||||
$(TARGETDIR)/stk.o \
|
||||
$(TARGETDIR)/sync.o \
|
||||
$(TARGETDIR)/key.o \
|
||||
$(TARGETDIR)/io.o \
|
||||
$(TARGETDIR)/event.o \
|
||||
$(TARGETDIR)/srs.o
|
||||
OBJS += $(EXTRA_OBJS)
|
||||
SRS = $(TARGETDIR)/srs
|
||||
|
||||
linux-debug: all
|
||||
all: $(TARGETDIR) $(SRS)
|
||||
|
||||
$(TARGETDIR):
|
||||
if [ ! -d $(TARGETDIR) ]; then mkdir $(TARGETDIR); fi
|
||||
|
||||
$(SRS): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS)
|
||||
|
||||
$(TARGETDIR)/md.o: md.S
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(TARGETDIR)/%.o: %.c common.h md.h Makefile
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(TARGETDIR)
|
|
@ -1,445 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#ifndef __ST_COMMON_H__
|
||||
#define __ST_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
/* Enable assertions only if DEBUG is defined */
|
||||
#ifndef DEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#define ST_ASSERT(expr) assert(expr)
|
||||
|
||||
#define ST_BEGIN_MACRO {
|
||||
#define ST_END_MACRO }
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ST_HIDDEN /*nothing*/
|
||||
#else
|
||||
#define ST_HIDDEN static
|
||||
#endif
|
||||
|
||||
#include "public.h"
|
||||
#include "md.h"
|
||||
|
||||
/*****************************************
|
||||
* Circular linked list definitions
|
||||
*/
|
||||
|
||||
typedef struct _st_clist {
|
||||
struct _st_clist *next;
|
||||
struct _st_clist *prev;
|
||||
} _st_clist_t;
|
||||
|
||||
/* Insert element "_e" into the list, before "_l" */
|
||||
#define ST_INSERT_BEFORE(_e,_l) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_e)->next = (_l); \
|
||||
(_e)->prev = (_l)->prev; \
|
||||
(_l)->prev->next = (_e); \
|
||||
(_l)->prev = (_e); \
|
||||
ST_END_MACRO
|
||||
|
||||
/* Insert element "_e" into the list, after "_l" */
|
||||
#define ST_INSERT_AFTER(_e,_l) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_e)->next = (_l)->next; \
|
||||
(_e)->prev = (_l); \
|
||||
(_l)->next->prev = (_e); \
|
||||
(_l)->next = (_e); \
|
||||
ST_END_MACRO
|
||||
|
||||
/* Return the element following element "_e" */
|
||||
#define ST_NEXT_LINK(_e) ((_e)->next)
|
||||
|
||||
/* Append an element "_e" to the end of the list "_l" */
|
||||
#define ST_APPEND_LINK(_e,_l) ST_INSERT_BEFORE(_e,_l)
|
||||
|
||||
/* Insert an element "_e" at the head of the list "_l" */
|
||||
#define ST_INSERT_LINK(_e,_l) ST_INSERT_AFTER(_e,_l)
|
||||
|
||||
/* Return the head/tail of the list */
|
||||
#define ST_LIST_HEAD(_l) (_l)->next
|
||||
#define ST_LIST_TAIL(_l) (_l)->prev
|
||||
|
||||
/* Remove the element "_e" from it's circular list */
|
||||
#define ST_REMOVE_LINK(_e) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_e)->prev->next = (_e)->next; \
|
||||
(_e)->next->prev = (_e)->prev; \
|
||||
ST_END_MACRO
|
||||
|
||||
/* Return non-zero if the given circular list "_l" is empty, */
|
||||
/* zero if the circular list is not empty */
|
||||
#define ST_CLIST_IS_EMPTY(_l) \
|
||||
((_l)->next == (_l))
|
||||
|
||||
/* Initialize a circular list */
|
||||
#define ST_INIT_CLIST(_l) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_l)->next = (_l); \
|
||||
(_l)->prev = (_l); \
|
||||
ST_END_MACRO
|
||||
|
||||
#define ST_INIT_STATIC_CLIST(_l) \
|
||||
{(_l), (_l)}
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Basic types definitions
|
||||
*/
|
||||
|
||||
typedef void (*_st_destructor_t)(void *);
|
||||
|
||||
typedef struct _st_stack {
|
||||
_st_clist_t links;
|
||||
char *vaddr; /* Base of stack's allocated memory */
|
||||
int vaddr_size; /* Size of stack's allocated memory */
|
||||
int stk_size; /* Size of usable portion of the stack */
|
||||
char *stk_bottom; /* Lowest address of stack's usable portion */
|
||||
char *stk_top; /* Highest address of stack's usable portion */
|
||||
void *sp; /* Stack pointer from C's point of view */
|
||||
} _st_stack_t;
|
||||
|
||||
|
||||
typedef struct _st_cond {
|
||||
_st_clist_t wait_q; /* Condition variable wait queue */
|
||||
} _st_cond_t;
|
||||
|
||||
|
||||
typedef struct _st_thread _st_thread_t;
|
||||
|
||||
struct _st_thread {
|
||||
int state; /* Thread's state */
|
||||
int flags; /* Thread's flags */
|
||||
|
||||
void *(*start)(void *arg); /* The start function of the thread */
|
||||
void *arg; /* Argument of the start function */
|
||||
void *retval; /* Return value of the start function */
|
||||
|
||||
_st_stack_t *stack; /* Info about thread's stack */
|
||||
|
||||
_st_clist_t links; /* For putting on run/sleep/zombie queue */
|
||||
_st_clist_t wait_links; /* For putting on mutex/condvar wait queue */
|
||||
#ifdef DEBUG
|
||||
_st_clist_t tlink; /* For putting on thread queue */
|
||||
#endif
|
||||
|
||||
st_utime_t due; /* Wakeup time when thread is sleeping */
|
||||
_st_thread_t *left; /* For putting in timeout heap */
|
||||
_st_thread_t *right; /* -- see docs/timeout_heap.txt for details */
|
||||
int heap_index;
|
||||
|
||||
void **private_data; /* Per thread private data */
|
||||
|
||||
_st_cond_t *term; /* Termination condition variable for join */
|
||||
|
||||
jmp_buf context; /* Thread's context */
|
||||
};
|
||||
|
||||
|
||||
typedef struct _st_mutex {
|
||||
_st_thread_t *owner; /* Current mutex owner */
|
||||
_st_clist_t wait_q; /* Mutex wait queue */
|
||||
} _st_mutex_t;
|
||||
|
||||
|
||||
typedef struct _st_pollq {
|
||||
_st_clist_t links; /* For putting on io queue */
|
||||
_st_thread_t *thread; /* Polling thread */
|
||||
struct pollfd *pds; /* Array of poll descriptors */
|
||||
int npds; /* Length of the array */
|
||||
int on_ioq; /* Is it on ioq? */
|
||||
} _st_pollq_t;
|
||||
|
||||
|
||||
typedef struct _st_eventsys_ops {
|
||||
const char *name; /* Name of this event system */
|
||||
int val; /* Type of this event system */
|
||||
int (*init)(void); /* Initialization */
|
||||
void (*dispatch)(void); /* Dispatch function */
|
||||
int (*pollset_add)(struct pollfd *, int); /* Add descriptor set */
|
||||
void (*pollset_del)(struct pollfd *, int); /* Delete descriptor set */
|
||||
int (*fd_new)(int); /* New descriptor allocated */
|
||||
int (*fd_close)(int); /* Descriptor closed */
|
||||
int (*fd_getlimit)(void); /* Descriptor hard limit */
|
||||
} _st_eventsys_t;
|
||||
|
||||
|
||||
typedef struct _st_vp {
|
||||
_st_thread_t *idle_thread; /* Idle thread for this vp */
|
||||
st_utime_t last_clock; /* The last time we went into vp_check_clock() */
|
||||
|
||||
_st_clist_t run_q; /* run queue for this vp */
|
||||
_st_clist_t io_q; /* io queue for this vp */
|
||||
_st_clist_t zombie_q; /* zombie queue for this vp */
|
||||
#ifdef DEBUG
|
||||
_st_clist_t thread_q; /* all threads of this vp */
|
||||
#endif
|
||||
int pagesize;
|
||||
|
||||
_st_thread_t *sleep_q; /* sleep queue for this vp */
|
||||
int sleepq_size; /* number of threads on sleep queue */
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
st_switch_cb_t switch_out_cb; /* called when a thread is switched out */
|
||||
st_switch_cb_t switch_in_cb; /* called when a thread is switched in */
|
||||
#endif
|
||||
} _st_vp_t;
|
||||
|
||||
|
||||
typedef struct _st_netfd {
|
||||
int osfd; /* Underlying OS file descriptor */
|
||||
int inuse; /* In-use flag */
|
||||
void *private_data; /* Per descriptor private data */
|
||||
_st_destructor_t destructor; /* Private data destructor function */
|
||||
void *aux_data; /* Auxiliary data for internal use */
|
||||
struct _st_netfd *next; /* For putting on the free list */
|
||||
} _st_netfd_t;
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Current vp, thread, and event system
|
||||
*/
|
||||
|
||||
extern _st_vp_t _st_this_vp;
|
||||
extern _st_thread_t *_st_this_thread;
|
||||
extern _st_eventsys_t *_st_eventsys;
|
||||
|
||||
#define _ST_CURRENT_THREAD() (_st_this_thread)
|
||||
#define _ST_SET_CURRENT_THREAD(_thread) (_st_this_thread = (_thread))
|
||||
|
||||
#define _ST_LAST_CLOCK (_st_this_vp.last_clock)
|
||||
|
||||
#define _ST_RUNQ (_st_this_vp.run_q)
|
||||
#define _ST_IOQ (_st_this_vp.io_q)
|
||||
#define _ST_ZOMBIEQ (_st_this_vp.zombie_q)
|
||||
#ifdef DEBUG
|
||||
#define _ST_THREADQ (_st_this_vp.thread_q)
|
||||
#endif
|
||||
|
||||
#define _ST_PAGE_SIZE (_st_this_vp.pagesize)
|
||||
|
||||
#define _ST_SLEEPQ (_st_this_vp.sleep_q)
|
||||
#define _ST_SLEEPQ_SIZE (_st_this_vp.sleepq_size)
|
||||
|
||||
#define _ST_VP_IDLE() (*_st_eventsys->dispatch)()
|
||||
|
||||
|
||||
/*****************************************
|
||||
* vp queues operations
|
||||
*/
|
||||
|
||||
#define _ST_ADD_IOQ(_pq) ST_APPEND_LINK(&_pq.links, &_ST_IOQ)
|
||||
#define _ST_DEL_IOQ(_pq) ST_REMOVE_LINK(&_pq.links)
|
||||
|
||||
#define _ST_ADD_RUNQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_RUNQ)
|
||||
#define _ST_DEL_RUNQ(_thr) ST_REMOVE_LINK(&(_thr)->links)
|
||||
|
||||
#define _ST_ADD_SLEEPQ(_thr, _timeout) _st_add_sleep_q(_thr, _timeout)
|
||||
#define _ST_DEL_SLEEPQ(_thr) _st_del_sleep_q(_thr)
|
||||
|
||||
#define _ST_ADD_ZOMBIEQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_ZOMBIEQ)
|
||||
#define _ST_DEL_ZOMBIEQ(_thr) ST_REMOVE_LINK(&(_thr)->links)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define _ST_ADD_THREADQ(_thr) ST_APPEND_LINK(&(_thr)->tlink, &_ST_THREADQ)
|
||||
#define _ST_DEL_THREADQ(_thr) ST_REMOVE_LINK(&(_thr)->tlink)
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Thread states and flags
|
||||
*/
|
||||
|
||||
#define _ST_ST_RUNNING 0
|
||||
#define _ST_ST_RUNNABLE 1
|
||||
#define _ST_ST_IO_WAIT 2
|
||||
#define _ST_ST_LOCK_WAIT 3
|
||||
#define _ST_ST_COND_WAIT 4
|
||||
#define _ST_ST_SLEEPING 5
|
||||
#define _ST_ST_ZOMBIE 6
|
||||
#define _ST_ST_SUSPENDED 7
|
||||
|
||||
#define _ST_FL_PRIMORDIAL 0x01
|
||||
#define _ST_FL_IDLE_THREAD 0x02
|
||||
#define _ST_FL_ON_SLEEPQ 0x04
|
||||
#define _ST_FL_INTERRUPT 0x08
|
||||
#define _ST_FL_TIMEDOUT 0x10
|
||||
|
||||
/*****************************************
|
||||
* Pointer conversion
|
||||
*/
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier))
|
||||
#endif
|
||||
|
||||
#define _ST_THREAD_PTR(_qp) \
|
||||
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, links)))
|
||||
|
||||
#define _ST_THREAD_WAITQ_PTR(_qp) \
|
||||
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, wait_links)))
|
||||
|
||||
#define _ST_THREAD_STACK_PTR(_qp) \
|
||||
((_st_stack_t *)((char*)(_qp) - offsetof(_st_stack_t, links)))
|
||||
|
||||
#define _ST_POLLQUEUE_PTR(_qp) \
|
||||
((_st_pollq_t *)((char *)(_qp) - offsetof(_st_pollq_t, links)))
|
||||
|
||||
#ifdef DEBUG
|
||||
#define _ST_THREAD_THREADQ_PTR(_qp) \
|
||||
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, tlink)))
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Constants
|
||||
*/
|
||||
|
||||
#ifndef ST_UTIME_NO_TIMEOUT
|
||||
#define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL)
|
||||
#endif
|
||||
|
||||
#define ST_DEFAULT_STACK_SIZE (64*1024)
|
||||
|
||||
#ifndef ST_KEYS_MAX
|
||||
#define ST_KEYS_MAX 16
|
||||
#endif
|
||||
|
||||
#ifndef ST_MIN_POLLFDS_SIZE
|
||||
#define ST_MIN_POLLFDS_SIZE 64
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Threads context switching
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
void _st_iterate_threads(void);
|
||||
#define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads()
|
||||
#else
|
||||
#define ST_DEBUG_ITERATE_THREADS()
|
||||
#endif
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
#define ST_SWITCH_OUT_CB(_thread) \
|
||||
if (_st_this_vp.switch_out_cb != NULL && \
|
||||
_thread != _st_this_vp.idle_thread && \
|
||||
_thread->state != _ST_ST_ZOMBIE) { \
|
||||
_st_this_vp.switch_out_cb(); \
|
||||
}
|
||||
#define ST_SWITCH_IN_CB(_thread) \
|
||||
if (_st_this_vp.switch_in_cb != NULL && \
|
||||
_thread != _st_this_vp.idle_thread && \
|
||||
_thread->state != _ST_ST_ZOMBIE) { \
|
||||
_st_this_vp.switch_in_cb(); \
|
||||
}
|
||||
#else
|
||||
#define ST_SWITCH_OUT_CB(_thread)
|
||||
#define ST_SWITCH_IN_CB(_thread)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Switch away from the current thread context by saving its state and
|
||||
* calling the thread scheduler
|
||||
*/
|
||||
#define _ST_SWITCH_CONTEXT(_thread) \
|
||||
ST_BEGIN_MACRO \
|
||||
ST_SWITCH_OUT_CB(_thread); \
|
||||
if (!MD_SETJMP((_thread)->context)) { \
|
||||
_st_vp_schedule(); \
|
||||
} \
|
||||
ST_DEBUG_ITERATE_THREADS(); \
|
||||
ST_SWITCH_IN_CB(_thread); \
|
||||
ST_END_MACRO
|
||||
|
||||
/*
|
||||
* Restore a thread context that was saved by _ST_SWITCH_CONTEXT or
|
||||
* initialized by _ST_INIT_CONTEXT
|
||||
*/
|
||||
#define _ST_RESTORE_CONTEXT(_thread) \
|
||||
ST_BEGIN_MACRO \
|
||||
_ST_SET_CURRENT_THREAD(_thread); \
|
||||
MD_LONGJMP((_thread)->context, 1); \
|
||||
ST_END_MACRO
|
||||
|
||||
/*
|
||||
* Number of bytes reserved under the stack "bottom"
|
||||
*/
|
||||
#define _ST_STACK_PAD_SIZE MD_STACK_PAD_SIZE
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Forward declarations
|
||||
*/
|
||||
|
||||
void _st_vp_schedule(void);
|
||||
void _st_vp_check_clock(void);
|
||||
void *_st_idle_thread_start(void *arg);
|
||||
void _st_thread_main(void);
|
||||
void _st_thread_cleanup(_st_thread_t *thread);
|
||||
void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout);
|
||||
void _st_del_sleep_q(_st_thread_t *thread);
|
||||
_st_stack_t *_st_stack_new(int stack_size);
|
||||
void _st_stack_free(_st_stack_t *ts);
|
||||
int _st_io_init(void);
|
||||
|
||||
st_utime_t st_utime(void);
|
||||
_st_cond_t *st_cond_new(void);
|
||||
int st_cond_destroy(_st_cond_t *cvar);
|
||||
int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout);
|
||||
int st_cond_signal(_st_cond_t *cvar);
|
||||
ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout);
|
||||
ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout);
|
||||
int st_poll(struct pollfd *pds, int npds, st_utime_t timeout);
|
||||
_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size);
|
||||
|
||||
#endif /* !__ST_COMMON_H__ */
|
||||
|
|
@ -1,483 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
* Yahoo! Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
#ifdef USE_POLL
|
||||
#error "Not support USE_POLL"
|
||||
#endif
|
||||
#ifdef MD_HAVE_KQUEUE
|
||||
#error "Not support MD_HAVE_KQUEUE"
|
||||
#endif
|
||||
#ifdef MD_HAVE_POLL
|
||||
#error "Not support MD_HAVE_POLL"
|
||||
#endif
|
||||
#ifndef MD_HAVE_EPOLL
|
||||
#error "Only support MD_HAVE_EPOLL"
|
||||
#endif
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
typedef struct _epoll_fd_data {
|
||||
int rd_ref_cnt;
|
||||
int wr_ref_cnt;
|
||||
int ex_ref_cnt;
|
||||
int revents;
|
||||
} _epoll_fd_data_t;
|
||||
|
||||
static struct _st_epolldata {
|
||||
_epoll_fd_data_t *fd_data;
|
||||
struct epoll_event *evtlist;
|
||||
int fd_data_size;
|
||||
int evtlist_size;
|
||||
int evtlist_cnt;
|
||||
int fd_hint;
|
||||
int epfd;
|
||||
pid_t pid;
|
||||
} *_st_epoll_data;
|
||||
|
||||
#ifndef ST_EPOLL_EVTLIST_SIZE
|
||||
/* Not a limit, just a hint */
|
||||
#define ST_EPOLL_EVTLIST_SIZE 4096
|
||||
#endif
|
||||
|
||||
#define _ST_EPOLL_READ_CNT(fd) (_st_epoll_data->fd_data[fd].rd_ref_cnt)
|
||||
#define _ST_EPOLL_WRITE_CNT(fd) (_st_epoll_data->fd_data[fd].wr_ref_cnt)
|
||||
#define _ST_EPOLL_EXCEP_CNT(fd) (_st_epoll_data->fd_data[fd].ex_ref_cnt)
|
||||
#define _ST_EPOLL_REVENTS(fd) (_st_epoll_data->fd_data[fd].revents)
|
||||
|
||||
#define _ST_EPOLL_READ_BIT(fd) (_ST_EPOLL_READ_CNT(fd) ? EPOLLIN : 0)
|
||||
#define _ST_EPOLL_WRITE_BIT(fd) (_ST_EPOLL_WRITE_CNT(fd) ? EPOLLOUT : 0)
|
||||
#define _ST_EPOLL_EXCEP_BIT(fd) (_ST_EPOLL_EXCEP_CNT(fd) ? EPOLLPRI : 0)
|
||||
#define _ST_EPOLL_EVENTS(fd) \
|
||||
(_ST_EPOLL_READ_BIT(fd)|_ST_EPOLL_WRITE_BIT(fd)|_ST_EPOLL_EXCEP_BIT(fd))
|
||||
|
||||
_st_eventsys_t *_st_eventsys = NULL;
|
||||
|
||||
/*****************************************
|
||||
* epoll event system
|
||||
*/
|
||||
|
||||
ST_HIDDEN int _st_epoll_init(void)
|
||||
{
|
||||
int fdlim;
|
||||
int err = 0;
|
||||
int rv = 0;
|
||||
|
||||
_st_epoll_data = (struct _st_epolldata *) calloc(1, sizeof(*_st_epoll_data));
|
||||
if (!_st_epoll_data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdlim = st_getfdlimit();
|
||||
_st_epoll_data->fd_hint = (fdlim > 0 && fdlim < ST_EPOLL_EVTLIST_SIZE) ? fdlim : ST_EPOLL_EVTLIST_SIZE;
|
||||
|
||||
if ((_st_epoll_data->epfd = epoll_create(_st_epoll_data->fd_hint)) < 0) {
|
||||
err = errno;
|
||||
rv = -1;
|
||||
goto cleanup_epoll;
|
||||
}
|
||||
fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC);
|
||||
_st_epoll_data->pid = getpid();
|
||||
|
||||
/* Allocate file descriptor data array */
|
||||
_st_epoll_data->fd_data_size = _st_epoll_data->fd_hint;
|
||||
_st_epoll_data->fd_data = (_epoll_fd_data_t *)calloc(_st_epoll_data->fd_data_size, sizeof(_epoll_fd_data_t));
|
||||
if (!_st_epoll_data->fd_data) {
|
||||
err = errno;
|
||||
rv = -1;
|
||||
goto cleanup_epoll;
|
||||
}
|
||||
|
||||
/* Allocate event lists */
|
||||
_st_epoll_data->evtlist_size = _st_epoll_data->fd_hint;
|
||||
_st_epoll_data->evtlist = (struct epoll_event *)malloc(_st_epoll_data->evtlist_size * sizeof(struct epoll_event));
|
||||
if (!_st_epoll_data->evtlist) {
|
||||
err = errno;
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
cleanup_epoll:
|
||||
if (rv < 0) {
|
||||
if (_st_epoll_data->epfd >= 0) {
|
||||
close(_st_epoll_data->epfd);
|
||||
}
|
||||
free(_st_epoll_data->fd_data);
|
||||
free(_st_epoll_data->evtlist);
|
||||
free(_st_epoll_data);
|
||||
_st_epoll_data = NULL;
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_fd_data_expand(int maxfd)
|
||||
{
|
||||
_epoll_fd_data_t *ptr;
|
||||
int n = _st_epoll_data->fd_data_size;
|
||||
|
||||
while (maxfd >= n) {
|
||||
n <<= 1;
|
||||
}
|
||||
|
||||
ptr = (_epoll_fd_data_t *)realloc(_st_epoll_data->fd_data, n * sizeof(_epoll_fd_data_t));
|
||||
if (!ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(ptr + _st_epoll_data->fd_data_size, 0, (n - _st_epoll_data->fd_data_size) * sizeof(_epoll_fd_data_t));
|
||||
|
||||
_st_epoll_data->fd_data = ptr;
|
||||
_st_epoll_data->fd_data_size = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ST_HIDDEN void _st_epoll_evtlist_expand(void)
|
||||
{
|
||||
struct epoll_event *ptr;
|
||||
int n = _st_epoll_data->evtlist_size;
|
||||
|
||||
while (_st_epoll_data->evtlist_cnt > n) {
|
||||
n <<= 1;
|
||||
}
|
||||
|
||||
ptr = (struct epoll_event *)realloc(_st_epoll_data->evtlist, n * sizeof(struct epoll_event));
|
||||
if (ptr) {
|
||||
_st_epoll_data->evtlist = ptr;
|
||||
_st_epoll_data->evtlist_size = n;
|
||||
}
|
||||
}
|
||||
|
||||
ST_HIDDEN void _st_epoll_pollset_del(struct pollfd *pds, int npds)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
struct pollfd *pd;
|
||||
struct pollfd *epd = pds + npds;
|
||||
int old_events, events, op;
|
||||
|
||||
/*
|
||||
* It's more or less OK if deleting fails because a descriptor
|
||||
* will either be closed or deleted in dispatch function after
|
||||
* it fires.
|
||||
*/
|
||||
for (pd = pds; pd < epd; pd++) {
|
||||
old_events = _ST_EPOLL_EVENTS(pd->fd);
|
||||
|
||||
if (pd->events & POLLIN) {
|
||||
_ST_EPOLL_READ_CNT(pd->fd)--;
|
||||
}
|
||||
if (pd->events & POLLOUT) {
|
||||
_ST_EPOLL_WRITE_CNT(pd->fd)--;
|
||||
}
|
||||
if (pd->events & POLLPRI) {
|
||||
_ST_EPOLL_EXCEP_CNT(pd->fd)--;
|
||||
}
|
||||
|
||||
events = _ST_EPOLL_EVENTS(pd->fd);
|
||||
/*
|
||||
* The _ST_EPOLL_REVENTS check below is needed so we can use
|
||||
* this function inside dispatch(). Outside of dispatch()
|
||||
* _ST_EPOLL_REVENTS is always zero for all descriptors.
|
||||
*/
|
||||
if (events != old_events && _ST_EPOLL_REVENTS(pd->fd) == 0) {
|
||||
op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
|
||||
ev.events = events;
|
||||
ev.data.fd = pd->fd;
|
||||
if (epoll_ctl(_st_epoll_data->epfd, op, pd->fd, &ev) == 0 && op == EPOLL_CTL_DEL) {
|
||||
_st_epoll_data->evtlist_cnt--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_pollset_add(struct pollfd *pds, int npds)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int i, fd;
|
||||
int old_events, events, op;
|
||||
|
||||
/* Do as many checks as possible up front */
|
||||
for (i = 0; i < npds; i++) {
|
||||
fd = pds[i].fd;
|
||||
if (fd < 0 || !pds[i].events || (pds[i].events & ~(POLLIN | POLLOUT | POLLPRI))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (fd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(fd) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < npds; i++) {
|
||||
fd = pds[i].fd;
|
||||
old_events = _ST_EPOLL_EVENTS(fd);
|
||||
|
||||
if (pds[i].events & POLLIN) {
|
||||
_ST_EPOLL_READ_CNT(fd)++;
|
||||
}
|
||||
if (pds[i].events & POLLOUT) {
|
||||
_ST_EPOLL_WRITE_CNT(fd)++;
|
||||
}
|
||||
if (pds[i].events & POLLPRI) {
|
||||
_ST_EPOLL_EXCEP_CNT(fd)++;
|
||||
}
|
||||
|
||||
events = _ST_EPOLL_EVENTS(fd);
|
||||
if (events != old_events) {
|
||||
op = old_events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
|
||||
ev.events = events;
|
||||
ev.data.fd = fd;
|
||||
if (epoll_ctl(_st_epoll_data->epfd, op, fd, &ev) < 0 && (op != EPOLL_CTL_ADD || errno != EEXIST)) {
|
||||
break;
|
||||
}
|
||||
if (op == EPOLL_CTL_ADD) {
|
||||
_st_epoll_data->evtlist_cnt++;
|
||||
if (_st_epoll_data->evtlist_cnt > _st_epoll_data->evtlist_size) {
|
||||
_st_epoll_evtlist_expand();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i < npds) {
|
||||
/* Error */
|
||||
int err = errno;
|
||||
/* Unroll the state */
|
||||
_st_epoll_pollset_del(pds, i + 1);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ST_HIDDEN void _st_epoll_dispatch(void)
|
||||
{
|
||||
st_utime_t min_timeout;
|
||||
_st_clist_t *q;
|
||||
_st_pollq_t *pq;
|
||||
struct pollfd *pds, *epds;
|
||||
struct epoll_event ev;
|
||||
int timeout, nfd, i, osfd, notify;
|
||||
int events, op;
|
||||
short revents;
|
||||
|
||||
if (_ST_SLEEPQ == NULL) {
|
||||
timeout = -1;
|
||||
} else {
|
||||
min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : (_ST_SLEEPQ->due - _ST_LAST_CLOCK);
|
||||
timeout = (int) (min_timeout / 1000);
|
||||
}
|
||||
|
||||
if (_st_epoll_data->pid != getpid()) {
|
||||
// WINLIN: remove it for bug introduced.
|
||||
// @see: https://github.com/ossrs/srs/issues/193
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Check for I/O operations */
|
||||
nfd = epoll_wait(_st_epoll_data->epfd, _st_epoll_data->evtlist, _st_epoll_data->evtlist_size, timeout);
|
||||
|
||||
if (nfd > 0) {
|
||||
for (i = 0; i < nfd; i++) {
|
||||
osfd = _st_epoll_data->evtlist[i].data.fd;
|
||||
_ST_EPOLL_REVENTS(osfd) = _st_epoll_data->evtlist[i].events;
|
||||
if (_ST_EPOLL_REVENTS(osfd) & (EPOLLERR | EPOLLHUP)) {
|
||||
/* Also set I/O bits on error */
|
||||
_ST_EPOLL_REVENTS(osfd) |= _ST_EPOLL_EVENTS(osfd);
|
||||
}
|
||||
}
|
||||
|
||||
for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) {
|
||||
pq = _ST_POLLQUEUE_PTR(q);
|
||||
notify = 0;
|
||||
epds = pq->pds + pq->npds;
|
||||
|
||||
for (pds = pq->pds; pds < epds; pds++) {
|
||||
if (_ST_EPOLL_REVENTS(pds->fd) == 0) {
|
||||
pds->revents = 0;
|
||||
continue;
|
||||
}
|
||||
osfd = pds->fd;
|
||||
events = pds->events;
|
||||
revents = 0;
|
||||
if ((events & POLLIN) && (_ST_EPOLL_REVENTS(osfd) & EPOLLIN)) {
|
||||
revents |= POLLIN;
|
||||
}
|
||||
if ((events & POLLOUT) && (_ST_EPOLL_REVENTS(osfd) & EPOLLOUT)) {
|
||||
revents |= POLLOUT;
|
||||
}
|
||||
if ((events & POLLPRI) && (_ST_EPOLL_REVENTS(osfd) & EPOLLPRI)) {
|
||||
revents |= POLLPRI;
|
||||
}
|
||||
if (_ST_EPOLL_REVENTS(osfd) & EPOLLERR) {
|
||||
revents |= POLLERR;
|
||||
}
|
||||
if (_ST_EPOLL_REVENTS(osfd) & EPOLLHUP) {
|
||||
revents |= POLLHUP;
|
||||
}
|
||||
|
||||
pds->revents = revents;
|
||||
if (revents) {
|
||||
notify = 1;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
ST_REMOVE_LINK(&pq->links);
|
||||
pq->on_ioq = 0;
|
||||
/*
|
||||
* Here we will only delete/modify descriptors that
|
||||
* didn't fire (see comments in _st_epoll_pollset_del()).
|
||||
*/
|
||||
_st_epoll_pollset_del(pq->pds, pq->npds);
|
||||
|
||||
if (pq->thread->flags & _ST_FL_ON_SLEEPQ) {
|
||||
_ST_DEL_SLEEPQ(pq->thread);
|
||||
}
|
||||
pq->thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(pq->thread);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nfd; i++) {
|
||||
/* Delete/modify descriptors that fired */
|
||||
osfd = _st_epoll_data->evtlist[i].data.fd;
|
||||
_ST_EPOLL_REVENTS(osfd) = 0;
|
||||
events = _ST_EPOLL_EVENTS(osfd);
|
||||
op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
|
||||
ev.events = events;
|
||||
ev.data.fd = osfd;
|
||||
if (epoll_ctl(_st_epoll_data->epfd, op, osfd, &ev) == 0 && op == EPOLL_CTL_DEL) {
|
||||
_st_epoll_data->evtlist_cnt--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_fd_new(int osfd)
|
||||
{
|
||||
if (osfd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(osfd) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_fd_close(int osfd)
|
||||
{
|
||||
if (_ST_EPOLL_READ_CNT(osfd) || _ST_EPOLL_WRITE_CNT(osfd) || _ST_EPOLL_EXCEP_CNT(osfd)) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_fd_getlimit(void)
|
||||
{
|
||||
/* zero means no specific limit */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if epoll functions are just stubs.
|
||||
*/
|
||||
ST_HIDDEN int _st_epoll_is_supported(void)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.ptr = NULL;
|
||||
/* Guaranteed to fail */
|
||||
epoll_ctl(-1, EPOLL_CTL_ADD, -1, &ev);
|
||||
|
||||
return (errno != ENOSYS);
|
||||
}
|
||||
|
||||
static _st_eventsys_t _st_epoll_eventsys = {
|
||||
"epoll",
|
||||
ST_EVENTSYS_ALT,
|
||||
_st_epoll_init,
|
||||
_st_epoll_dispatch,
|
||||
_st_epoll_pollset_add,
|
||||
_st_epoll_pollset_del,
|
||||
_st_epoll_fd_new,
|
||||
_st_epoll_fd_close,
|
||||
_st_epoll_fd_getlimit
|
||||
};
|
||||
|
||||
/*****************************************
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
int st_set_eventsys(int eventsys)
|
||||
{
|
||||
if (_st_eventsys) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (eventsys) {
|
||||
case ST_EVENTSYS_DEFAULT:
|
||||
case ST_EVENTSYS_ALT:
|
||||
default:
|
||||
if (_st_epoll_is_supported()) {
|
||||
_st_eventsys = &_st_epoll_eventsys;
|
||||
break;
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_get_eventsys(void)
|
||||
{
|
||||
return _st_eventsys ? _st_eventsys->val : -1;
|
||||
}
|
||||
|
||||
const char *st_get_eventsys_name(void)
|
||||
{
|
||||
return _st_eventsys ? _st_eventsys->name : "";
|
||||
}
|
||||
|
|
@ -1,792 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
#if EAGAIN != EWOULDBLOCK
|
||||
#define _IO_NOT_READY_ERROR ((errno == EAGAIN) || (errno == EWOULDBLOCK))
|
||||
#else
|
||||
#define _IO_NOT_READY_ERROR (errno == EAGAIN)
|
||||
#endif
|
||||
|
||||
#define _LOCAL_MAXIOV 16
|
||||
|
||||
/* File descriptor object free list */
|
||||
static _st_netfd_t *_st_netfd_freelist = NULL;
|
||||
/* Maximum number of file descriptors that the process can open */
|
||||
static int _st_osfd_limit = -1;
|
||||
|
||||
static void _st_netfd_free_aux_data(_st_netfd_t *fd);
|
||||
|
||||
int _st_io_init(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
struct rlimit rlim;
|
||||
int fdlim;
|
||||
|
||||
/* Ignore SIGPIPE */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set maximum number of open file descriptors */
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdlim = (*_st_eventsys->fd_getlimit)();
|
||||
if (fdlim > 0 && rlim.rlim_max > (rlim_t) fdlim) {
|
||||
rlim.rlim_max = fdlim;
|
||||
}
|
||||
rlim.rlim_cur = rlim.rlim_max;
|
||||
if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
||||
return -1;
|
||||
}
|
||||
_st_osfd_limit = (int) rlim.rlim_max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_getfdlimit(void)
|
||||
{
|
||||
return _st_osfd_limit;
|
||||
}
|
||||
|
||||
void st_netfd_free(_st_netfd_t *fd)
|
||||
{
|
||||
if (!fd->inuse) {
|
||||
return;
|
||||
}
|
||||
|
||||
fd->inuse = 0;
|
||||
if (fd->aux_data) {
|
||||
_st_netfd_free_aux_data(fd);
|
||||
}
|
||||
if (fd->private_data && fd->destructor) {
|
||||
(*(fd->destructor))(fd->private_data);
|
||||
}
|
||||
fd->private_data = NULL;
|
||||
fd->destructor = NULL;
|
||||
fd->next = _st_netfd_freelist;
|
||||
_st_netfd_freelist = fd;
|
||||
}
|
||||
|
||||
static _st_netfd_t *_st_netfd_new(int osfd, int nonblock, int is_socket)
|
||||
{
|
||||
_st_netfd_t *fd;
|
||||
int flags = 1;
|
||||
|
||||
if ((*_st_eventsys->fd_new)(osfd) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_st_netfd_freelist) {
|
||||
fd = _st_netfd_freelist;
|
||||
_st_netfd_freelist = _st_netfd_freelist->next;
|
||||
} else {
|
||||
fd = calloc(1, sizeof(_st_netfd_t));
|
||||
if (!fd) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fd->osfd = osfd;
|
||||
fd->inuse = 1;
|
||||
fd->next = NULL;
|
||||
|
||||
if (nonblock) {
|
||||
/* Use just one system call */
|
||||
if (is_socket && ioctl(osfd, FIONBIO, &flags) != -1) {
|
||||
return fd;
|
||||
}
|
||||
/* Do it the Posix way */
|
||||
if ((flags = fcntl(osfd, F_GETFL, 0)) < 0 || fcntl(osfd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
st_netfd_free(fd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
_st_netfd_t *st_netfd_open(int osfd)
|
||||
{
|
||||
return _st_netfd_new(osfd, 1, 0);
|
||||
}
|
||||
|
||||
_st_netfd_t *st_netfd_open_socket(int osfd)
|
||||
{
|
||||
return _st_netfd_new(osfd, 1, 1);
|
||||
}
|
||||
|
||||
int st_netfd_close(_st_netfd_t *fd)
|
||||
{
|
||||
if ((*_st_eventsys->fd_close)(fd->osfd) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
st_netfd_free(fd);
|
||||
return close(fd->osfd);
|
||||
}
|
||||
|
||||
int st_netfd_fileno(_st_netfd_t *fd)
|
||||
{
|
||||
return (fd->osfd);
|
||||
}
|
||||
|
||||
void st_netfd_setspecific(_st_netfd_t *fd, void *value, _st_destructor_t destructor)
|
||||
{
|
||||
if (value != fd->private_data) {
|
||||
/* Free up previously set non-NULL data value */
|
||||
if (fd->private_data && fd->destructor) {
|
||||
(*(fd->destructor))(fd->private_data);
|
||||
}
|
||||
}
|
||||
fd->private_data = value;
|
||||
fd->destructor = destructor;
|
||||
}
|
||||
|
||||
void *st_netfd_getspecific(_st_netfd_t *fd)
|
||||
{
|
||||
return (fd->private_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for I/O on a single descriptor.
|
||||
*/
|
||||
int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout)
|
||||
{
|
||||
struct pollfd pd;
|
||||
int n;
|
||||
|
||||
pd.fd = fd->osfd;
|
||||
pd.events = (short) how;
|
||||
pd.revents = 0;
|
||||
|
||||
if ((n = st_poll(&pd, 1, timeout)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (n == 0) {
|
||||
/* Timed out */
|
||||
errno = ETIME;
|
||||
return -1;
|
||||
}
|
||||
if (pd.revents & POLLNVAL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MD_ALWAYS_UNSERIALIZED_ACCEPT
|
||||
/* No-op */
|
||||
int st_netfd_serialize_accept(_st_netfd_t *fd)
|
||||
{
|
||||
fd->aux_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No-op */
|
||||
static void _st_netfd_free_aux_data(_st_netfd_t *fd)
|
||||
{
|
||||
fd->aux_data = NULL;
|
||||
}
|
||||
|
||||
_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout)
|
||||
{
|
||||
int osfd, err;
|
||||
_st_netfd_t *newfd;
|
||||
|
||||
while ((osfd = accept(fd->osfd, addr, (socklen_t *)addrlen)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* On some platforms the new socket created by accept() inherits */
|
||||
/* the nonblocking attribute of the listening socket */
|
||||
#if defined (MD_ACCEPT_NB_INHERITED)
|
||||
newfd = _st_netfd_new(osfd, 0, 1);
|
||||
#elif defined (MD_ACCEPT_NB_NOT_INHERITED)
|
||||
newfd = _st_netfd_new(osfd, 1, 1);
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
|
||||
if (!newfd) {
|
||||
err = errno;
|
||||
close(osfd);
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
||||
#else /* MD_ALWAYS_UNSERIALIZED_ACCEPT */
|
||||
/*
|
||||
* On some platforms accept() calls from different processes
|
||||
* on the same listen socket must be serialized.
|
||||
* The following code serializes accept()'s without process blocking.
|
||||
* A pipe is used as an inter-process semaphore.
|
||||
*/
|
||||
int st_netfd_serialize_accept(_st_netfd_t *fd)
|
||||
{
|
||||
_st_netfd_t **p;
|
||||
int osfd[2], err;
|
||||
|
||||
if (fd->aux_data) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ((p = (_st_netfd_t **)calloc(2, sizeof(_st_netfd_t *))) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (pipe(osfd) < 0) {
|
||||
free(p);
|
||||
return -1;
|
||||
}
|
||||
if ((p[0] = st_netfd_open(osfd[0])) != NULL && (p[1] = st_netfd_open(osfd[1])) != NULL && write(osfd[1], " ", 1) == 1) {
|
||||
fd->aux_data = p;
|
||||
return 0;
|
||||
}
|
||||
/* Error */
|
||||
err = errno;
|
||||
if (p[0]) {
|
||||
st_netfd_free(p[0]);
|
||||
}
|
||||
if (p[1]) {
|
||||
st_netfd_free(p[1]);
|
||||
}
|
||||
close(osfd[0]);
|
||||
close(osfd[1]);
|
||||
free(p);
|
||||
errno = err;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _st_netfd_free_aux_data(_st_netfd_t *fd)
|
||||
{
|
||||
_st_netfd_t **p = (_st_netfd_t **) fd->aux_data;
|
||||
|
||||
st_netfd_close(p[0]);
|
||||
st_netfd_close(p[1]);
|
||||
free(p);
|
||||
fd->aux_data = NULL;
|
||||
}
|
||||
|
||||
_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout)
|
||||
{
|
||||
int osfd, err;
|
||||
_st_netfd_t *newfd;
|
||||
_st_netfd_t **p = (_st_netfd_t **) fd->aux_data;
|
||||
ssize_t n;
|
||||
char c;
|
||||
|
||||
for ( ; ; ) {
|
||||
if (p == NULL) {
|
||||
osfd = accept(fd->osfd, addr, (socklen_t *)addrlen);
|
||||
} else {
|
||||
/* Get the lock */
|
||||
n = st_read(p[0], &c, 1, timeout);
|
||||
if (n < 0) {
|
||||
return NULL;
|
||||
}
|
||||
ST_ASSERT(n == 1);
|
||||
/* Got the lock */
|
||||
osfd = accept(fd->osfd, addr, (socklen_t *)addrlen);
|
||||
/* Unlock */
|
||||
err = errno;
|
||||
n = st_write(p[1], &c, 1, timeout);
|
||||
ST_ASSERT(n == 1);
|
||||
errno = err;
|
||||
}
|
||||
if (osfd >= 0) {
|
||||
break;
|
||||
}
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* On some platforms the new socket created by accept() inherits */
|
||||
/* the nonblocking attribute of the listening socket */
|
||||
#if defined (MD_ACCEPT_NB_INHERITED)
|
||||
newfd = _st_netfd_new(osfd, 0, 1);
|
||||
#elif defined (MD_ACCEPT_NB_NOT_INHERITED)
|
||||
newfd = _st_netfd_new(osfd, 1, 1);
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
|
||||
if (!newfd) {
|
||||
err = errno;
|
||||
close(osfd);
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
#endif /* MD_ALWAYS_UNSERIALIZED_ACCEPT */
|
||||
|
||||
int st_connect(_st_netfd_t *fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout)
|
||||
{
|
||||
int n, err = 0;
|
||||
|
||||
while (connect(fd->osfd, addr, addrlen) < 0) {
|
||||
if (errno != EINTR) {
|
||||
/*
|
||||
* On some platforms, if connect() is interrupted (errno == EINTR)
|
||||
* after the kernel binds the socket, a subsequent connect()
|
||||
* attempt will fail with errno == EADDRINUSE. Ignore EADDRINUSE
|
||||
* iff connect() was previously interrupted. See Rich Stevens'
|
||||
* "UNIX Network Programming," Vol. 1, 2nd edition, p. 413
|
||||
* ("Interrupted connect").
|
||||
*/
|
||||
if (errno != EINPROGRESS && (errno != EADDRINUSE || err == 0)) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
/* Try to find out whether the connection setup succeeded or failed */
|
||||
n = sizeof(int);
|
||||
if (getsockopt(fd->osfd, SOL_SOCKET, SO_ERROR, (char *)&err, (socklen_t *)&n) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (err) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
err = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while ((n = read(fd->osfd, buf, nbyte)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_read_resid(_st_netfd_t *fd, void *buf, size_t *resid, st_utime_t timeout)
|
||||
{
|
||||
struct iovec iov, *riov;
|
||||
int riov_size, rv;
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = *resid;
|
||||
riov = &iov;
|
||||
riov_size = 1;
|
||||
rv = st_readv_resid(fd, &riov, &riov_size, timeout);
|
||||
*resid = iov.iov_len;
|
||||
return rv;
|
||||
}
|
||||
|
||||
ssize_t st_readv(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while ((n = readv(fd->osfd, iov, iov_size)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_readv_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while (*iov_size > 0) {
|
||||
if (*iov_size == 1) {
|
||||
n = read(fd->osfd, (*iov)->iov_base, (*iov)->iov_len);
|
||||
} else {
|
||||
n = readv(fd->osfd, *iov, *iov_size);
|
||||
}
|
||||
if (n < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
} else if (n == 0) {
|
||||
break;
|
||||
} else {
|
||||
while ((size_t) n >= (*iov)->iov_len) {
|
||||
n -= (*iov)->iov_len;
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len;
|
||||
(*iov)->iov_len = 0;
|
||||
(*iov)++;
|
||||
(*iov_size)--;
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*iov_size == 0) {
|
||||
break;
|
||||
}
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + n;
|
||||
(*iov)->iov_len -= n;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t st_read_fully(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout)
|
||||
{
|
||||
size_t resid = nbyte;
|
||||
return st_read_resid(fd, buf, &resid, timeout) == 0 ? (ssize_t) (nbyte - resid) : -1;
|
||||
}
|
||||
|
||||
int st_write_resid(_st_netfd_t *fd, const void *buf, size_t *resid, st_utime_t timeout)
|
||||
{
|
||||
struct iovec iov, *riov;
|
||||
int riov_size, rv;
|
||||
|
||||
iov.iov_base = (void *) buf; /* we promise not to modify buf */
|
||||
iov.iov_len = *resid;
|
||||
riov = &iov;
|
||||
riov_size = 1;
|
||||
rv = st_writev_resid(fd, &riov, &riov_size, timeout);
|
||||
*resid = iov.iov_len;
|
||||
return rv;
|
||||
}
|
||||
|
||||
ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout)
|
||||
{
|
||||
size_t resid = nbyte;
|
||||
return st_write_resid(fd, buf, &resid, timeout) == 0 ? (ssize_t) (nbyte - resid) : -1;
|
||||
}
|
||||
|
||||
ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n, rv;
|
||||
size_t nleft, nbyte;
|
||||
int index, iov_cnt;
|
||||
struct iovec *tmp_iov;
|
||||
struct iovec local_iov[_LOCAL_MAXIOV];
|
||||
|
||||
/* Calculate the total number of bytes to be sent */
|
||||
nbyte = 0;
|
||||
for (index = 0; index < iov_size; index++) {
|
||||
nbyte += iov[index].iov_len;
|
||||
}
|
||||
|
||||
rv = (ssize_t)nbyte;
|
||||
nleft = nbyte;
|
||||
tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */
|
||||
iov_cnt = iov_size;
|
||||
|
||||
while (nleft > 0) {
|
||||
if (iov_cnt == 1) {
|
||||
if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft) {
|
||||
rv = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ((size_t) n == nleft) {
|
||||
break;
|
||||
}
|
||||
nleft -= n;
|
||||
/* Find the next unwritten vector */
|
||||
n = (ssize_t)(nbyte - nleft);
|
||||
for (index = 0; (size_t) n >= iov[index].iov_len; index++) {
|
||||
n -= iov[index].iov_len;
|
||||
}
|
||||
|
||||
if (tmp_iov == iov) {
|
||||
/* Must copy iov's around */
|
||||
if (iov_size - index <= _LOCAL_MAXIOV) {
|
||||
tmp_iov = local_iov;
|
||||
} else {
|
||||
tmp_iov = calloc(1, (iov_size - index) * sizeof(struct iovec));
|
||||
if (tmp_iov == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in the first partial read */
|
||||
tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[n]);
|
||||
tmp_iov[0].iov_len = iov[index].iov_len - n;
|
||||
index++;
|
||||
/* Copy the remaining vectors */
|
||||
for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) {
|
||||
tmp_iov[iov_cnt].iov_base = iov[index].iov_base;
|
||||
tmp_iov[iov_cnt].iov_len = iov[index].iov_len;
|
||||
}
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_iov != iov && tmp_iov != local_iov) {
|
||||
free(tmp_iov);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int st_writev_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while (*iov_size > 0) {
|
||||
if (*iov_size == 1) {
|
||||
n = write(fd->osfd, (*iov)->iov_base, (*iov)->iov_len);
|
||||
} else {
|
||||
n = writev(fd->osfd, *iov, *iov_size);
|
||||
}
|
||||
if (n < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
while ((size_t) n >= (*iov)->iov_len) {
|
||||
n -= (*iov)->iov_len;
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len;
|
||||
(*iov)->iov_len = 0;
|
||||
(*iov)++;
|
||||
(*iov_size)--;
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*iov_size == 0) {
|
||||
break;
|
||||
}
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + n;
|
||||
(*iov)->iov_len -= n;
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple I/O functions for UDP.
|
||||
*/
|
||||
int st_recvfrom(_st_netfd_t *fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = recvfrom(fd->osfd, buf, len, 0, from, (socklen_t *)fromlen)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_sendto(_st_netfd_t *fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = sendto(fd->osfd, msg, len, 0, to, tolen)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_recvmsg(_st_netfd_t *fd, struct msghdr *msg, int flags, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = recvmsg(fd->osfd, msg, flags)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = sendmsg(fd->osfd, msg, flags)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* To open FIFOs or other special files.
|
||||
*/
|
||||
_st_netfd_t *st_open(const char *path, int oflags, mode_t mode)
|
||||
{
|
||||
int osfd, err;
|
||||
_st_netfd_t *newfd;
|
||||
|
||||
while ((osfd = open(path, oflags | O_NONBLOCK, mode)) < 0) {
|
||||
if (errno != EINTR) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
newfd = _st_netfd_new(osfd, 0, 0);
|
||||
if (!newfd) {
|
||||
err = errno;
|
||||
close(osfd);
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* Destructor table for per-thread private data
|
||||
*/
|
||||
static _st_destructor_t _st_destructors[ST_KEYS_MAX];
|
||||
static int key_max = 0;
|
||||
|
||||
/*
|
||||
* Return a key to be used for thread specific data
|
||||
*/
|
||||
int st_key_create(int *keyp, _st_destructor_t destructor)
|
||||
{
|
||||
if (key_max >= ST_KEYS_MAX) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*keyp = key_max++;
|
||||
_st_destructors[*keyp] = destructor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_key_getlimit(void)
|
||||
{
|
||||
return ST_KEYS_MAX;
|
||||
}
|
||||
|
||||
int st_thread_setspecific(int key, void *value)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
if (key < 0 || key >= key_max) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value != me->private_data[key]) {
|
||||
/* free up previously set non-NULL data value */
|
||||
if (me->private_data[key] && _st_destructors[key]) {
|
||||
(*_st_destructors[key])(me->private_data[key]);
|
||||
}
|
||||
me->private_data[key] = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *st_thread_getspecific(int key)
|
||||
{
|
||||
if (key < 0 || key >= key_max) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ((_ST_CURRENT_THREAD())->private_data[key]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up all per-thread private data
|
||||
*/
|
||||
void _st_thread_cleanup(_st_thread_t *thread)
|
||||
{
|
||||
int key;
|
||||
|
||||
for (key = 0; key < key_max; key++) {
|
||||
if (thread->private_data[key] && _st_destructors[key]) {
|
||||
(*_st_destructors[key])(thread->private_data[key]);
|
||||
thread->private_data[key] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
/*
|
||||
* Internal __jmp_buf layout
|
||||
*/
|
||||
#define JB_BX 0
|
||||
#define JB_SI 1
|
||||
#define JB_DI 2
|
||||
#define JB_BP 3
|
||||
#define JB_SP 4
|
||||
#define JB_PC 5
|
||||
|
||||
.file "md.S"
|
||||
.text
|
||||
|
||||
/* _st_md_cxt_save(__jmp_buf env) */
|
||||
.globl _st_md_cxt_save
|
||||
.type _st_md_cxt_save, @function
|
||||
.align 16
|
||||
_st_md_cxt_save:
|
||||
movl 4(%esp), %eax
|
||||
|
||||
/*
|
||||
* Save registers.
|
||||
*/
|
||||
movl %ebx, (JB_BX*4)(%eax)
|
||||
movl %esi, (JB_SI*4)(%eax)
|
||||
movl %edi, (JB_DI*4)(%eax)
|
||||
/* Save SP */
|
||||
leal 4(%esp), %ecx
|
||||
movl %ecx, (JB_SP*4)(%eax)
|
||||
/* Save PC we are returning to */
|
||||
movl 0(%esp), %ecx
|
||||
movl %ecx, (JB_PC*4)(%eax)
|
||||
/* Save caller frame pointer */
|
||||
movl %ebp, (JB_BP*4)(%eax)
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
.size _st_md_cxt_save, .-_st_md_cxt_save
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
/* _st_md_cxt_restore(__jmp_buf env, int val) */
|
||||
.globl _st_md_cxt_restore
|
||||
.type _st_md_cxt_restore, @function
|
||||
.align 16
|
||||
_st_md_cxt_restore:
|
||||
/* First argument is jmp_buf */
|
||||
movl 4(%esp), %ecx
|
||||
/* Second argument is return value */
|
||||
movl 8(%esp), %eax
|
||||
/* Set the return address */
|
||||
movl (JB_PC*4)(%ecx), %edx
|
||||
/*
|
||||
* Restore registers.
|
||||
*/
|
||||
movl (JB_BX*4)(%ecx), %ebx
|
||||
movl (JB_SI*4)(%ecx), %esi
|
||||
movl (JB_DI*4)(%ecx), %edi
|
||||
movl (JB_BP*4)(%ecx), %ebp
|
||||
movl (JB_SP*4)(%ecx), %esp
|
||||
testl %eax, %eax
|
||||
jnz 1f
|
||||
incl %eax
|
||||
/* Jump to saved PC */
|
||||
1: jmp *%edx
|
||||
.size _st_md_cxt_restore, .-_st_md_cxt_restore
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
#elif defined(__amd64__) || defined(__x86_64__)
|
||||
|
||||
/*
|
||||
* Internal __jmp_buf layout
|
||||
*/
|
||||
#define JB_RBX 0
|
||||
#define JB_RBP 1
|
||||
#define JB_R12 2
|
||||
#define JB_R13 3
|
||||
#define JB_R14 4
|
||||
#define JB_R15 5
|
||||
#define JB_RSP 6
|
||||
#define JB_PC 7
|
||||
|
||||
.file "md.S"
|
||||
.text
|
||||
|
||||
/* _st_md_cxt_save(__jmp_buf env) */
|
||||
.globl _st_md_cxt_save
|
||||
.type _st_md_cxt_save, @function
|
||||
.align 16
|
||||
_st_md_cxt_save:
|
||||
/*
|
||||
* Save registers.
|
||||
*/
|
||||
movq %rbx, (JB_RBX*8)(%rdi)
|
||||
movq %rbp, (JB_RBP*8)(%rdi)
|
||||
movq %r12, (JB_R12*8)(%rdi)
|
||||
movq %r13, (JB_R13*8)(%rdi)
|
||||
movq %r14, (JB_R14*8)(%rdi)
|
||||
movq %r15, (JB_R15*8)(%rdi)
|
||||
/* Save SP */
|
||||
leaq 8(%rsp), %rdx
|
||||
movq %rdx, (JB_RSP*8)(%rdi)
|
||||
/* Save PC we are returning to */
|
||||
movq (%rsp), %rax
|
||||
movq %rax, (JB_PC*8)(%rdi)
|
||||
xorq %rax, %rax
|
||||
ret
|
||||
.size _st_md_cxt_save, .-_st_md_cxt_save
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
/* _st_md_cxt_restore(__jmp_buf env, int val) */
|
||||
.globl _st_md_cxt_restore
|
||||
.type _st_md_cxt_restore, @function
|
||||
.align 16
|
||||
_st_md_cxt_restore:
|
||||
/*
|
||||
* Restore registers.
|
||||
*/
|
||||
movq (JB_RBX*8)(%rdi), %rbx
|
||||
movq (JB_RBP*8)(%rdi), %rbp
|
||||
movq (JB_R12*8)(%rdi), %r12
|
||||
movq (JB_R13*8)(%rdi), %r13
|
||||
movq (JB_R14*8)(%rdi), %r14
|
||||
movq (JB_R15*8)(%rdi), %r15
|
||||
/* Set return value */
|
||||
test %esi, %esi
|
||||
mov $01, %eax
|
||||
cmove %eax, %esi
|
||||
mov %esi, %eax
|
||||
movq (JB_PC*8)(%rdi), %rdx
|
||||
movq (JB_RSP*8)(%rdi), %rsp
|
||||
/* Jump to saved PC */
|
||||
jmpq *%rdx
|
||||
.size _st_md_cxt_restore, .-_st_md_cxt_restore
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#ifndef __ST_MD_H__
|
||||
#define __ST_MD_H__
|
||||
|
||||
#if defined(ETIMEDOUT) && !defined(ETIME)
|
||||
#define ETIME ETIMEDOUT
|
||||
#endif
|
||||
|
||||
#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
#endif
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED -1
|
||||
#endif
|
||||
|
||||
/*****************************************
|
||||
* Platform specifics
|
||||
*/
|
||||
#if defined (LINUX)
|
||||
/* linux ok, defined bellow */
|
||||
#elif defined (AIX)
|
||||
#error "AIX not supported"
|
||||
#elif defined (CYGWIN)
|
||||
#error "CYGWIN not supported"
|
||||
#elif defined (DARWIN)
|
||||
#error "DARWIN not supported"
|
||||
#elif defined (FREEBSD)
|
||||
#error "FREEBSD not supported"
|
||||
#elif defined (HPUX)
|
||||
#error "HPUX not supported"
|
||||
#elif defined (IRIX)
|
||||
#error "IRIX not supported"
|
||||
#elif defined (NETBSD)
|
||||
#error "NETBSD not supported"
|
||||
#elif defined (OPENBSD)
|
||||
#error "OPENBSD not supported"
|
||||
#elif defined (OSF1)
|
||||
#error "OSF1 not supported"
|
||||
#elif defined (SOLARIS)
|
||||
#error "SOLARIS not supported"
|
||||
#else
|
||||
#error "Unknown OS"
|
||||
#endif /* OS */
|
||||
|
||||
/* linux only, defined bellow */
|
||||
/*
|
||||
* These are properties of the linux kernel and are the same on every
|
||||
* flavor and architecture.
|
||||
*/
|
||||
#define MD_USE_BSD_ANON_MMAP
|
||||
#define MD_ACCEPT_NB_NOT_INHERITED
|
||||
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
|
||||
/*
|
||||
* Modern GNU/Linux is Posix.1g compliant.
|
||||
*/
|
||||
#define MD_HAVE_SOCKLEN_T
|
||||
|
||||
/*
|
||||
* All architectures and flavors of linux have the gettimeofday
|
||||
* function but if you know of a faster way, use it.
|
||||
*/
|
||||
#define MD_GET_UTIME() \
|
||||
struct timeval tv; \
|
||||
(void) gettimeofday(&tv, NULL); \
|
||||
return (tv.tv_sec * 1000000LL + tv.tv_usec)
|
||||
|
||||
#if defined(__mips__)
|
||||
#define MD_STACK_GROWS_DOWN
|
||||
#else /* Not or mips */
|
||||
/*
|
||||
* On linux, there are a few styles of jmpbuf format. These vary based
|
||||
* on architecture/glibc combination.
|
||||
*
|
||||
* Most of the glibc based toggles were lifted from:
|
||||
* mozilla/nsprpub/pr/include/md/_linux.h
|
||||
*/
|
||||
/*
|
||||
* Starting with glibc 2.4, JB_SP definitions are not public anymore.
|
||||
* They, however, can still be found in glibc source tree in
|
||||
* architecture-specific "jmpbuf-offsets.h" files.
|
||||
* Most importantly, the content of jmp_buf is mangled by setjmp to make
|
||||
* it completely opaque (the mangling can be disabled by setting the
|
||||
* LD_POINTER_GUARD environment variable before application execution).
|
||||
* Therefore we will use built-in _st_md_cxt_save/_st_md_cxt_restore
|
||||
* functions as a setjmp/longjmp replacement wherever they are available
|
||||
* unless USE_LIBC_SETJMP is defined.
|
||||
*/
|
||||
#if defined(__i386__)
|
||||
#define MD_STACK_GROWS_DOWN
|
||||
#define MD_USE_BUILTIN_SETJMP
|
||||
|
||||
#if defined(__GLIBC__) && __GLIBC__ >= 2
|
||||
#ifndef JB_SP
|
||||
#define JB_SP 4
|
||||
#endif
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP]
|
||||
#else
|
||||
/* not an error but certainly cause for caution */
|
||||
#error "Untested use of old glibc on i386"
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp
|
||||
#endif
|
||||
#elif defined(__amd64__) || defined(__x86_64__)
|
||||
#define MD_STACK_GROWS_DOWN
|
||||
#define MD_USE_BUILTIN_SETJMP
|
||||
|
||||
#ifndef JB_RSP
|
||||
#define JB_RSP 6
|
||||
#endif
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_RSP]
|
||||
#elif defined(__arm__)
|
||||
#define MD_STACK_GROWS_DOWN
|
||||
|
||||
#if defined(__GLIBC__) && __GLIBC__ >= 2
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[8]
|
||||
#else
|
||||
#error "ARM/Linux pre-glibc2 not supported yet"
|
||||
#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */
|
||||
#else
|
||||
#error "Unknown CPU architecture"
|
||||
#endif /* Cases with common MD_INIT_CONTEXT and different SP locations */
|
||||
#endif /* Cases with different MD_INIT_CONTEXT */
|
||||
|
||||
#if defined(MD_USE_BUILTIN_SETJMP) && !defined(USE_LIBC_SETJMP)
|
||||
/* i386/x86_64 */
|
||||
#define MD_SETJMP(env) _st_md_cxt_save(env)
|
||||
#define MD_LONGJMP(env, val) _st_md_cxt_restore(env, val)
|
||||
|
||||
extern int _st_md_cxt_save(jmp_buf env);
|
||||
extern void _st_md_cxt_restore(jmp_buf env, int val);
|
||||
#else
|
||||
/* arm/mips */
|
||||
#define MD_SETJMP(env) setjmp(env)
|
||||
#define MD_LONGJMP(env, val) longjmp(env, val)
|
||||
#endif
|
||||
|
||||
/*****************************************
|
||||
* Other defines
|
||||
*/
|
||||
#ifndef MD_STACK_PAD_SIZE
|
||||
#define MD_STACK_PAD_SIZE 128
|
||||
#endif
|
||||
|
||||
#if !defined(MD_HAVE_SOCKLEN_T) && !defined(socklen_t)
|
||||
#define socklen_t int
|
||||
#endif
|
||||
|
||||
#ifndef MD_CAP_STACK
|
||||
#define MD_CAP_STACK(var_addr)
|
||||
#endif
|
||||
|
||||
#endif /* !__ST_MD_H__ */
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#ifndef __ST_THREAD_H__
|
||||
#define __ST_THREAD_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
|
||||
#define ST_VERSION "1.9"
|
||||
#define ST_VERSION_MAJOR 1
|
||||
#define ST_VERSION_MINOR 9
|
||||
|
||||
/* Undefine this to remove the context switch callback feature. */
|
||||
#define ST_SWITCH_CB
|
||||
|
||||
#ifndef ETIME
|
||||
#define ETIME ETIMEDOUT
|
||||
#endif
|
||||
|
||||
#ifndef ST_UTIME_NO_TIMEOUT
|
||||
#define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL)
|
||||
#endif
|
||||
|
||||
#ifndef ST_UTIME_NO_WAIT
|
||||
#define ST_UTIME_NO_WAIT 0
|
||||
#endif
|
||||
|
||||
#define ST_EVENTSYS_DEFAULT 0
|
||||
#define ST_EVENTSYS_SELECT 1
|
||||
#define ST_EVENTSYS_POLL 2
|
||||
#define ST_EVENTSYS_ALT 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef unsigned long long st_utime_t;
|
||||
typedef struct _st_thread * st_thread_t;
|
||||
typedef struct _st_cond * st_cond_t;
|
||||
typedef struct _st_mutex * st_mutex_t;
|
||||
typedef struct _st_netfd * st_netfd_t;
|
||||
#ifdef ST_SWITCH_CB
|
||||
typedef void (*st_switch_cb_t)(void);
|
||||
#endif
|
||||
|
||||
extern int st_init(void);
|
||||
extern int st_getfdlimit(void);
|
||||
|
||||
extern int st_set_eventsys(int eventsys);
|
||||
extern int st_get_eventsys(void);
|
||||
extern const char *st_get_eventsys_name(void);
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
extern st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb);
|
||||
extern st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb);
|
||||
#endif
|
||||
|
||||
extern st_thread_t st_thread_self(void);
|
||||
extern void st_thread_exit(void *retval);
|
||||
extern int st_thread_join(st_thread_t trd, void **retvalp);
|
||||
extern void st_thread_interrupt(st_thread_t trd);
|
||||
extern st_thread_t st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stack_size);
|
||||
extern int st_randomize_stacks(int on);
|
||||
extern int st_set_utime_function(st_utime_t (*func)(void));
|
||||
|
||||
extern st_utime_t st_utime(void);
|
||||
extern st_utime_t st_utime_last_clock(void);
|
||||
extern int st_timecache_set(int on);
|
||||
extern time_t st_time(void);
|
||||
extern int st_usleep(st_utime_t usecs);
|
||||
extern int st_sleep(int secs);
|
||||
extern st_cond_t st_cond_new(void);
|
||||
extern int st_cond_destroy(st_cond_t cvar);
|
||||
extern int st_cond_timedwait(st_cond_t cvar, st_utime_t timeout);
|
||||
extern int st_cond_wait(st_cond_t cvar);
|
||||
extern int st_cond_signal(st_cond_t cvar);
|
||||
extern int st_cond_broadcast(st_cond_t cvar);
|
||||
extern st_mutex_t st_mutex_new(void);
|
||||
extern int st_mutex_destroy(st_mutex_t lock);
|
||||
extern int st_mutex_lock(st_mutex_t lock);
|
||||
extern int st_mutex_unlock(st_mutex_t lock);
|
||||
extern int st_mutex_trylock(st_mutex_t lock);
|
||||
|
||||
extern int st_key_create(int *keyp, void (*destructor)(void *));
|
||||
extern int st_key_getlimit(void);
|
||||
extern int st_thread_setspecific(int key, void *value);
|
||||
extern void *st_thread_getspecific(int key);
|
||||
|
||||
extern st_netfd_t st_netfd_open(int osfd);
|
||||
extern st_netfd_t st_netfd_open_socket(int osfd);
|
||||
extern void st_netfd_free(st_netfd_t fd);
|
||||
extern int st_netfd_close(st_netfd_t fd);
|
||||
extern int st_netfd_fileno(st_netfd_t fd);
|
||||
extern void st_netfd_setspecific(st_netfd_t fd, void *value, void (*destructor)(void *));
|
||||
extern void *st_netfd_getspecific(st_netfd_t fd);
|
||||
extern int st_netfd_serialize_accept(st_netfd_t fd);
|
||||
extern int st_netfd_poll(st_netfd_t fd, int how, st_utime_t timeout);
|
||||
|
||||
extern int st_poll(struct pollfd *pds, int npds, st_utime_t timeout);
|
||||
extern st_netfd_t st_accept(st_netfd_t fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout);
|
||||
extern int st_connect(st_netfd_t fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout);
|
||||
extern ssize_t st_read(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout);
|
||||
extern ssize_t st_read_fully(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout);
|
||||
extern int st_read_resid(st_netfd_t fd, void *buf, size_t *resid, st_utime_t timeout);
|
||||
extern ssize_t st_readv(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout);
|
||||
extern int st_readv_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout);
|
||||
extern ssize_t st_write(st_netfd_t fd, const void *buf, size_t nbyte, st_utime_t timeout);
|
||||
extern int st_write_resid(st_netfd_t fd, const void *buf, size_t *resid, st_utime_t timeout);
|
||||
extern ssize_t st_writev(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout);
|
||||
extern int st_writev_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout);
|
||||
extern int st_recvfrom(st_netfd_t fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout);
|
||||
extern int st_sendto(st_netfd_t fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout);
|
||||
extern int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags, st_utime_t timeout);
|
||||
extern int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags, st_utime_t timeout);
|
||||
extern st_netfd_t st_open(const char *path, int oflags, mode_t mode);
|
||||
|
||||
#ifdef DEBUG
|
||||
extern void _st_show_thread_stack(st_thread_t thread, const char *messg);
|
||||
extern void _st_iterate_threads(void);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !__ST_THREAD_H__ */
|
||||
|
|
@ -1,680 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
/* Global data */
|
||||
_st_vp_t _st_this_vp; /* This VP */
|
||||
_st_thread_t *_st_this_thread; /* Current thread */
|
||||
int _st_active_count = 0; /* Active thread count */
|
||||
|
||||
time_t _st_curr_time = 0; /* Current time as returned by time(2) */
|
||||
st_utime_t _st_last_tset; /* Last time it was fetched */
|
||||
|
||||
int st_poll(struct pollfd *pds, int npds, st_utime_t timeout)
|
||||
{
|
||||
struct pollfd *pd;
|
||||
struct pollfd *epd = pds + npds;
|
||||
_st_pollq_t pq;
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
int n;
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*_st_eventsys->pollset_add)(pds, npds) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pq.pds = pds;
|
||||
pq.npds = npds;
|
||||
pq.thread = me;
|
||||
pq.on_ioq = 1;
|
||||
_ST_ADD_IOQ(pq);
|
||||
if (timeout != ST_UTIME_NO_TIMEOUT) {
|
||||
_ST_ADD_SLEEPQ(me, timeout);
|
||||
}
|
||||
me->state = _ST_ST_IO_WAIT;
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
n = 0;
|
||||
if (pq.on_ioq) {
|
||||
/* If we timed out, the pollq might still be on the ioq. Remove it */
|
||||
_ST_DEL_IOQ(pq);
|
||||
(*_st_eventsys->pollset_del)(pds, npds);
|
||||
} else {
|
||||
/* Count the number of ready descriptors */
|
||||
for (pd = pds; pd < epd; pd++) {
|
||||
if (pd->revents) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void _st_vp_schedule(void)
|
||||
{
|
||||
_st_thread_t *trd;
|
||||
|
||||
if (_ST_RUNQ.next != &_ST_RUNQ) {
|
||||
/* Pull thread off of the run queue */
|
||||
trd = _ST_THREAD_PTR(_ST_RUNQ.next);
|
||||
_ST_DEL_RUNQ(trd);
|
||||
} else {
|
||||
/* If there are no threads to run, switch to the idle thread */
|
||||
trd = _st_this_vp.idle_thread;
|
||||
}
|
||||
ST_ASSERT(trd->state == _ST_ST_RUNNABLE);
|
||||
|
||||
/* Resume the thread */
|
||||
trd->state = _ST_ST_RUNNING;
|
||||
_ST_RESTORE_CONTEXT(trd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize this Virtual Processor
|
||||
*/
|
||||
int st_init(void)
|
||||
{
|
||||
_st_thread_t *trd;
|
||||
|
||||
if (_st_active_count) {
|
||||
/* Already initialized */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We can ignore return value here */
|
||||
st_set_eventsys(ST_EVENTSYS_DEFAULT);
|
||||
|
||||
if (_st_io_init() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&_st_this_vp, 0, sizeof(_st_vp_t));
|
||||
|
||||
ST_INIT_CLIST(&_ST_RUNQ);
|
||||
ST_INIT_CLIST(&_ST_IOQ);
|
||||
ST_INIT_CLIST(&_ST_ZOMBIEQ);
|
||||
#ifdef DEBUG
|
||||
ST_INIT_CLIST(&_ST_THREADQ);
|
||||
#endif
|
||||
|
||||
if ((*_st_eventsys->init)() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_st_this_vp.pagesize = getpagesize();
|
||||
_st_this_vp.last_clock = st_utime();
|
||||
|
||||
/*
|
||||
* Create idle thread
|
||||
*/
|
||||
_st_this_vp.idle_thread = st_thread_create(_st_idle_thread_start, NULL, 0, 0);
|
||||
if (!_st_this_vp.idle_thread) {
|
||||
return -1;
|
||||
}
|
||||
_st_this_vp.idle_thread->flags = _ST_FL_IDLE_THREAD;
|
||||
_st_active_count--;
|
||||
_ST_DEL_RUNQ(_st_this_vp.idle_thread);
|
||||
|
||||
/*
|
||||
* Initialize primordial thread
|
||||
*/
|
||||
trd = (_st_thread_t *) calloc(1, sizeof(_st_thread_t) +
|
||||
(ST_KEYS_MAX * sizeof(void *)));
|
||||
if (!trd) {
|
||||
return -1;
|
||||
}
|
||||
trd->private_data = (void **) (trd + 1);
|
||||
trd->state = _ST_ST_RUNNING;
|
||||
trd->flags = _ST_FL_PRIMORDIAL;
|
||||
_ST_SET_CURRENT_THREAD(trd);
|
||||
_st_active_count++;
|
||||
#ifdef DEBUG
|
||||
_ST_ADD_THREADQ(trd);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb)
|
||||
{
|
||||
st_switch_cb_t ocb = _st_this_vp.switch_in_cb;
|
||||
_st_this_vp.switch_in_cb = cb;
|
||||
return ocb;
|
||||
}
|
||||
|
||||
st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb)
|
||||
{
|
||||
st_switch_cb_t ocb = _st_this_vp.switch_out_cb;
|
||||
_st_this_vp.switch_out_cb = cb;
|
||||
return ocb;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start function for the idle thread
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
void *_st_idle_thread_start(void *arg)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
while (_st_active_count > 0) {
|
||||
/* Idle vp till I/O is ready or the smallest timeout expired */
|
||||
_ST_VP_IDLE();
|
||||
|
||||
/* Check sleep queue for expired threads */
|
||||
_st_vp_check_clock();
|
||||
|
||||
me->state = _ST_ST_RUNNABLE;
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
}
|
||||
|
||||
/* No more threads */
|
||||
exit(0);
|
||||
|
||||
/* NOTREACHED */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void st_thread_exit(void *retval)
|
||||
{
|
||||
_st_thread_t *trd = _ST_CURRENT_THREAD();
|
||||
|
||||
trd->retval = retval;
|
||||
_st_thread_cleanup(trd);
|
||||
_st_active_count--;
|
||||
if (trd->term) {
|
||||
/* Put thread on the zombie queue */
|
||||
trd->state = _ST_ST_ZOMBIE;
|
||||
_ST_ADD_ZOMBIEQ(trd);
|
||||
|
||||
/* Notify on our termination condition variable */
|
||||
st_cond_signal(trd->term);
|
||||
|
||||
/* Switch context and come back later */
|
||||
_ST_SWITCH_CONTEXT(trd);
|
||||
|
||||
/* Continue the cleanup */
|
||||
st_cond_destroy(trd->term);
|
||||
trd->term = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
_ST_DEL_THREADQ(trd);
|
||||
#endif
|
||||
|
||||
if (!(trd->flags & _ST_FL_PRIMORDIAL)) {
|
||||
_st_stack_free(trd->stack);
|
||||
}
|
||||
|
||||
/* Find another thread to run */
|
||||
_ST_SWITCH_CONTEXT(trd);
|
||||
/* Not going to land here */
|
||||
}
|
||||
|
||||
int st_thread_join(_st_thread_t *trd, void **retvalp)
|
||||
{
|
||||
_st_cond_t *term = trd->term;
|
||||
|
||||
/* Can't join a non-joinable thread */
|
||||
if (term == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_ST_CURRENT_THREAD() == trd) {
|
||||
errno = EDEADLK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Multiple threads can't wait on the same joinable thread */
|
||||
if (term->wait_q.next != &term->wait_q) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (trd->state != _ST_ST_ZOMBIE) {
|
||||
if (st_cond_timedwait(term, ST_UTIME_NO_TIMEOUT) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (retvalp) {
|
||||
*retvalp = trd->retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove target thread from the zombie queue and make it runnable.
|
||||
* When it gets scheduled later, it will do the clean up.
|
||||
*/
|
||||
trd->state = _ST_ST_RUNNABLE;
|
||||
_ST_DEL_ZOMBIEQ(trd);
|
||||
_ST_ADD_RUNQ(trd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _st_thread_main(void)
|
||||
{
|
||||
_st_thread_t *trd = _ST_CURRENT_THREAD();
|
||||
|
||||
/*
|
||||
* Cap the stack by zeroing out the saved return address register
|
||||
* value. This allows some debugging/profiling tools to know when
|
||||
* to stop unwinding the stack. It's a no-op on most platforms.
|
||||
*/
|
||||
MD_CAP_STACK(&trd);
|
||||
|
||||
/* Run thread main */
|
||||
trd->retval = (*trd->start)(trd->arg);
|
||||
|
||||
/* All done, time to go away */
|
||||
st_thread_exit(trd->retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert "thread" into the timeout heap, in the position
|
||||
* specified by thread->heap_index. See docs/timeout_heap.txt
|
||||
* for details about the timeout heap.
|
||||
*/
|
||||
static _st_thread_t **heap_insert(_st_thread_t *trd)
|
||||
{
|
||||
int target = trd->heap_index;
|
||||
int s = target;
|
||||
_st_thread_t **p = &_ST_SLEEPQ;
|
||||
int bits = 0;
|
||||
int bit;
|
||||
int index = 1;
|
||||
|
||||
while (s) {
|
||||
s >>= 1;
|
||||
bits++;
|
||||
}
|
||||
|
||||
for (bit = bits - 2; bit >= 0; bit--) {
|
||||
if (trd->due < (*p)->due) {
|
||||
_st_thread_t *t = *p;
|
||||
trd->left = t->left;
|
||||
trd->right = t->right;
|
||||
*p = trd;
|
||||
trd->heap_index = index;
|
||||
trd = t;
|
||||
}
|
||||
index <<= 1;
|
||||
if (target & (1 << bit)) {
|
||||
p = &((*p)->right);
|
||||
index |= 1;
|
||||
} else {
|
||||
p = &((*p)->left);
|
||||
}
|
||||
}
|
||||
|
||||
trd->heap_index = index;
|
||||
*p = trd;
|
||||
trd->left = trd->right = NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete "thread" from the timeout heap.
|
||||
*/
|
||||
static void heap_delete(_st_thread_t *trd)
|
||||
{
|
||||
_st_thread_t *t, **p;
|
||||
int bits = 0;
|
||||
int s, bit;
|
||||
|
||||
/* First find and unlink the last heap element */
|
||||
p = &_ST_SLEEPQ;
|
||||
s = _ST_SLEEPQ_SIZE;
|
||||
while (s) {
|
||||
s >>= 1;
|
||||
bits++;
|
||||
}
|
||||
|
||||
for (bit = bits - 2; bit >= 0; bit--) {
|
||||
if (_ST_SLEEPQ_SIZE & (1 << bit)) {
|
||||
p = &((*p)->right);
|
||||
} else {
|
||||
p = &((*p)->left);
|
||||
}
|
||||
}
|
||||
|
||||
t = *p;
|
||||
*p = NULL;
|
||||
--_ST_SLEEPQ_SIZE;
|
||||
if (t != trd) {
|
||||
/*
|
||||
* Insert the unlinked last element in place of the element we are deleting
|
||||
*/
|
||||
t->heap_index = trd->heap_index;
|
||||
p = heap_insert(t);
|
||||
t = *p;
|
||||
t->left = trd->left;
|
||||
t->right = trd->right;
|
||||
|
||||
/*
|
||||
* Reestablish the heap invariant.
|
||||
*/
|
||||
for (;;) {
|
||||
_st_thread_t *y; /* The younger child */
|
||||
int index_tmp;
|
||||
|
||||
if (t->left == NULL) {
|
||||
break;
|
||||
} else if (t->right == NULL) {
|
||||
y = t->left;
|
||||
} else if (t->left->due < t->right->due) {
|
||||
y = t->left;
|
||||
} else {
|
||||
y = t->right;
|
||||
}
|
||||
|
||||
if (t->due > y->due) {
|
||||
_st_thread_t *tl = y->left;
|
||||
_st_thread_t *tr = y->right;
|
||||
*p = y;
|
||||
if (y == t->left) {
|
||||
y->left = t;
|
||||
y->right = t->right;
|
||||
p = &y->left;
|
||||
} else {
|
||||
y->left = t->left;
|
||||
y->right = t;
|
||||
p = &y->right;
|
||||
}
|
||||
t->left = tl;
|
||||
t->right = tr;
|
||||
index_tmp = t->heap_index;
|
||||
t->heap_index = y->heap_index;
|
||||
y->heap_index = index_tmp;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trd->left = trd->right = NULL;
|
||||
}
|
||||
|
||||
void _st_add_sleep_q(_st_thread_t *trd, st_utime_t timeout)
|
||||
{
|
||||
trd->due = _ST_LAST_CLOCK + timeout;
|
||||
trd->flags |= _ST_FL_ON_SLEEPQ;
|
||||
trd->heap_index = ++_ST_SLEEPQ_SIZE;
|
||||
heap_insert(trd);
|
||||
}
|
||||
|
||||
void _st_del_sleep_q(_st_thread_t *trd)
|
||||
{
|
||||
heap_delete(trd);
|
||||
trd->flags &= ~_ST_FL_ON_SLEEPQ;
|
||||
}
|
||||
|
||||
void _st_vp_check_clock(void)
|
||||
{
|
||||
_st_thread_t *trd;
|
||||
st_utime_t elapsed, now;
|
||||
|
||||
now = st_utime();
|
||||
elapsed = now - _ST_LAST_CLOCK;
|
||||
_ST_LAST_CLOCK = now;
|
||||
|
||||
if (_st_curr_time && now - _st_last_tset > 999000) {
|
||||
_st_curr_time = time(NULL);
|
||||
_st_last_tset = now;
|
||||
}
|
||||
|
||||
while (_ST_SLEEPQ != NULL) {
|
||||
trd = _ST_SLEEPQ;
|
||||
ST_ASSERT(trd->flags & _ST_FL_ON_SLEEPQ);
|
||||
if (trd->due > now) {
|
||||
break;
|
||||
}
|
||||
_ST_DEL_SLEEPQ(trd);
|
||||
|
||||
/* If thread is waiting on condition variable, set the time out flag */
|
||||
if (trd->state == _ST_ST_COND_WAIT) {
|
||||
trd->flags |= _ST_FL_TIMEDOUT;
|
||||
}
|
||||
|
||||
/* Make thread runnable */
|
||||
ST_ASSERT(!(trd->flags & _ST_FL_IDLE_THREAD));
|
||||
trd->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(trd);
|
||||
}
|
||||
}
|
||||
|
||||
void st_thread_interrupt(_st_thread_t* trd)
|
||||
{
|
||||
/* If thread is already dead */
|
||||
if (trd->state == _ST_ST_ZOMBIE) {
|
||||
return;
|
||||
}
|
||||
|
||||
trd->flags |= _ST_FL_INTERRUPT;
|
||||
|
||||
if (trd->state == _ST_ST_RUNNING || trd->state == _ST_ST_RUNNABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (trd->flags & _ST_FL_ON_SLEEPQ) {
|
||||
_ST_DEL_SLEEPQ(trd);
|
||||
}
|
||||
|
||||
/* Make thread runnable */
|
||||
trd->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(trd);
|
||||
}
|
||||
|
||||
_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size)
|
||||
{
|
||||
_st_thread_t *trd;
|
||||
_st_stack_t *stack;
|
||||
void **ptds;
|
||||
char *sp;
|
||||
|
||||
/* Adjust stack size */
|
||||
if (stk_size == 0) {
|
||||
stk_size = ST_DEFAULT_STACK_SIZE;
|
||||
}
|
||||
stk_size = ((stk_size + _ST_PAGE_SIZE - 1) / _ST_PAGE_SIZE) * _ST_PAGE_SIZE;
|
||||
stack = _st_stack_new(stk_size);
|
||||
if (!stack) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate thread object and per-thread data off the stack */
|
||||
#if defined (MD_STACK_GROWS_DOWN)
|
||||
sp = stack->stk_top;
|
||||
/*
|
||||
* The stack segment is split in the middle. The upper half is used
|
||||
* as backing store for the register stack which grows upward.
|
||||
* The lower half is used for the traditional memory stack which
|
||||
* grows downward. Both stacks start in the middle and grow outward
|
||||
* from each other.
|
||||
*/
|
||||
/**
|
||||
The below comments is by winlin:
|
||||
The Stack public structure:
|
||||
+--------------------------------------------------------------+
|
||||
| stack |
|
||||
+--------------------------------------------------------------+
|
||||
bottom top
|
||||
The code bellow use the stack as:
|
||||
+-----------------+-----------------+-------------+------------+
|
||||
| stack of thread |pad+align(128B+) |thread(336B) | keys(128B) |
|
||||
+-----------------+-----------------+-------------+------------+
|
||||
bottom sp trd ptds top
|
||||
(context[0].__jmpbuf.sp) (private_data)
|
||||
*/
|
||||
sp = sp - (ST_KEYS_MAX * sizeof(void *));
|
||||
ptds = (void **) sp;
|
||||
sp = sp - sizeof(_st_thread_t);
|
||||
trd = (_st_thread_t *) sp;
|
||||
|
||||
/* Make stack 64-byte aligned */
|
||||
if ((unsigned long)sp & 0x3f) {
|
||||
sp = sp - ((unsigned long)sp & 0x3f);
|
||||
}
|
||||
stack->sp = sp - _ST_STACK_PAD_SIZE;
|
||||
#else
|
||||
#error "Only Supports Stack Grown Down"
|
||||
#endif
|
||||
|
||||
memset(trd, 0, sizeof(_st_thread_t));
|
||||
memset(ptds, 0, ST_KEYS_MAX * sizeof(void *));
|
||||
|
||||
/* Initialize thread */
|
||||
trd->private_data = ptds;
|
||||
trd->stack = stack;
|
||||
trd->start = start;
|
||||
trd->arg = arg;
|
||||
|
||||
// by winlin, expand macro MD_INIT_CONTEXT
|
||||
#if defined(__mips__)
|
||||
MD_SETJMP((trd)->context);
|
||||
trd->context[0].__jmpbuf[0].__pc = (__ptr_t) _st_thread_main;
|
||||
trd->context[0].__jmpbuf[0].__sp = stack->sp;
|
||||
#else
|
||||
if (MD_SETJMP((trd)->context)) {
|
||||
_st_thread_main();
|
||||
}
|
||||
MD_GET_SP(trd) = (long) (stack->sp);
|
||||
#endif
|
||||
|
||||
/* If thread is joinable, allocate a termination condition variable */
|
||||
if (joinable) {
|
||||
trd->term = st_cond_new();
|
||||
if (trd->term == NULL) {
|
||||
_st_stack_free(trd->stack);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make thread runnable */
|
||||
trd->state = _ST_ST_RUNNABLE;
|
||||
_st_active_count++;
|
||||
_ST_ADD_RUNQ(trd);
|
||||
#ifdef DEBUG
|
||||
_ST_ADD_THREADQ(trd);
|
||||
#endif
|
||||
|
||||
return trd;
|
||||
}
|
||||
|
||||
_st_thread_t *st_thread_self(void)
|
||||
{
|
||||
return _ST_CURRENT_THREAD();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* ARGSUSED */
|
||||
void _st_show_thread_stack(_st_thread_t *trd, const char *messg)
|
||||
{
|
||||
}
|
||||
|
||||
/* To be set from debugger */
|
||||
int _st_iterate_threads_flag = 0;
|
||||
|
||||
void _st_iterate_threads(void)
|
||||
{
|
||||
static _st_thread_t *trd = NULL;
|
||||
static jmp_buf orig_jb, save_jb;
|
||||
_st_clist_t *q;
|
||||
|
||||
if (!_st_iterate_threads_flag) {
|
||||
if (trd) {
|
||||
memcpy(trd->context, save_jb, sizeof(jmp_buf));
|
||||
MD_LONGJMP(orig_jb, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (trd) {
|
||||
memcpy(trd->context, save_jb, sizeof(jmp_buf));
|
||||
_st_show_thread_stack(trd, NULL);
|
||||
} else {
|
||||
if (MD_SETJMP(orig_jb)) {
|
||||
_st_iterate_threads_flag = 0;
|
||||
trd = NULL;
|
||||
_st_show_thread_stack(trd, "Iteration completed");
|
||||
return;
|
||||
}
|
||||
trd = _ST_CURRENT_THREAD();
|
||||
_st_show_thread_stack(trd, "Iteration started");
|
||||
}
|
||||
|
||||
q = trd->tlink.next;
|
||||
if (q == &_ST_THREADQ) {
|
||||
q = q->next;
|
||||
}
|
||||
ST_ASSERT(q != &_ST_THREADQ);
|
||||
trd = _ST_THREAD_THREADQ_PTR(q);
|
||||
if (trd == _ST_CURRENT_THREAD()) {
|
||||
MD_LONGJMP(orig_jb, 1);
|
||||
}
|
||||
memcpy(save_jb, trd->context, sizeof(jmp_buf));
|
||||
MD_LONGJMP(trd->context, 1);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
|
@ -1,497 +0,0 @@
|
|||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "public.h"
|
||||
|
||||
#define srs_trace(msg, ...) printf(msg, ##__VA_ARGS__);printf("\n")
|
||||
|
||||
int io_port = 1990;
|
||||
int sleep_ms = 100;
|
||||
|
||||
void stack_print(long int previous_sp, int level)
|
||||
{
|
||||
if (level <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
register long int rsp asm("sp");
|
||||
char buf[level * 1024];
|
||||
|
||||
stack_print(rsp, level - 1);
|
||||
|
||||
srs_trace("%d. psp=%#lx, sp=%#lx, size=%dB(%dB+%dKB)",
|
||||
level, previous_sp, rsp, (int)(previous_sp - rsp),
|
||||
(int)(previous_sp - rsp - sizeof(buf)), (int)(sizeof(buf) / 1024));
|
||||
}
|
||||
|
||||
int huge_stack_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("huge_stack test: start");
|
||||
|
||||
register long int rsp asm("sp");
|
||||
stack_print(rsp, 10);
|
||||
|
||||
srs_trace("huge_stack test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sleep_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("sleep test: start");
|
||||
|
||||
srs_trace("1. sleep...");
|
||||
st_utime_t start = st_utime();
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_utime_t end = st_utime();
|
||||
|
||||
srs_trace("2. sleep ok, sleep=%dus, deviation=%dus",
|
||||
(int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000));
|
||||
|
||||
srs_trace("sleep test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* sleep2_func0(void* arg)
|
||||
{
|
||||
int sleep_ms = 100;
|
||||
st_utime_t start = st_utime();
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_utime_t end = st_utime();
|
||||
|
||||
srs_trace("sleep ok, sleep=%dus, deviation=%dus",
|
||||
(int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sleep2_func1(void* arg)
|
||||
{
|
||||
int sleep_ms = 250;
|
||||
st_utime_t start = st_utime();
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_utime_t end = st_utime();
|
||||
|
||||
srs_trace("sleep ok, sleep=%dus, deviation=%dus",
|
||||
(int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sleep2_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("sleep2 test: start");
|
||||
|
||||
st_thread_t trd0 = st_thread_create(sleep2_func0, NULL, 1, 0);
|
||||
st_thread_t trd1 = st_thread_create(sleep2_func1, NULL, 1, 0);
|
||||
st_thread_join(trd0, NULL);
|
||||
st_thread_join(trd1, NULL);
|
||||
|
||||
srs_trace("sleep test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
st_mutex_t sleep_work_cond = NULL;
|
||||
void* sleep_deviation_func(void* arg)
|
||||
{
|
||||
st_mutex_lock(sleep_work_cond);
|
||||
srs_trace("2. work thread start.");
|
||||
|
||||
int64_t i;
|
||||
for (i = 0; i < 3000000000ULL; i++) {
|
||||
}
|
||||
|
||||
st_mutex_unlock(sleep_work_cond);
|
||||
srs_trace("3. work thread end.");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sleep_deviation_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("sleep deviation test: start");
|
||||
|
||||
sleep_work_cond = st_mutex_new();
|
||||
|
||||
st_thread_create(sleep_deviation_func, NULL, 0, 0);
|
||||
st_mutex_lock(sleep_work_cond);
|
||||
|
||||
srs_trace("1. sleep...");
|
||||
st_utime_t start = st_utime();
|
||||
|
||||
// other thread to do some complex work.
|
||||
st_mutex_unlock(sleep_work_cond);
|
||||
st_usleep(1000 * 1000);
|
||||
|
||||
st_utime_t end = st_utime();
|
||||
|
||||
srs_trace("4. sleep ok, sleep=%dus, deviation=%dus",
|
||||
(int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000));
|
||||
|
||||
st_mutex_lock(sleep_work_cond);
|
||||
srs_trace("sleep deviation test: end");
|
||||
|
||||
st_mutex_destroy(sleep_work_cond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* thread_func(void* arg)
|
||||
{
|
||||
srs_trace("1. thread run");
|
||||
st_usleep(sleep_ms * 1000);
|
||||
srs_trace("2. thread completed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int thread_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("thread test: start");
|
||||
|
||||
st_thread_t trd = st_thread_create(thread_func, NULL, 1, 0);
|
||||
if (trd == NULL) {
|
||||
srs_trace("st_thread_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
st_thread_join(trd, NULL);
|
||||
srs_trace("3. thread joined");
|
||||
|
||||
srs_trace("thread test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
st_mutex_t sync_start = NULL;
|
||||
st_cond_t sync_cond = NULL;
|
||||
st_mutex_t sync_mutex = NULL;
|
||||
st_cond_t sync_end = NULL;
|
||||
|
||||
void* sync_master(void* arg)
|
||||
{
|
||||
// wait for main to sync_start this thread.
|
||||
st_mutex_lock(sync_start);
|
||||
st_mutex_unlock(sync_start);
|
||||
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_cond_signal(sync_cond);
|
||||
|
||||
st_mutex_lock(sync_mutex);
|
||||
srs_trace("2. st mutex is ok");
|
||||
st_mutex_unlock(sync_mutex);
|
||||
|
||||
st_usleep(sleep_ms * 1000);
|
||||
srs_trace("3. st thread is ok");
|
||||
st_cond_signal(sync_cond);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sync_slave(void* arg)
|
||||
{
|
||||
// lock mutex to control thread.
|
||||
st_mutex_lock(sync_mutex);
|
||||
|
||||
// wait for main to sync_start this thread.
|
||||
st_mutex_lock(sync_start);
|
||||
st_mutex_unlock(sync_start);
|
||||
|
||||
// wait thread to ready.
|
||||
st_cond_wait(sync_cond);
|
||||
srs_trace("1. st cond is ok");
|
||||
|
||||
// release mutex to control thread
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_mutex_unlock(sync_mutex);
|
||||
|
||||
// wait thread to exit.
|
||||
st_cond_wait(sync_cond);
|
||||
srs_trace("4. st is ok");
|
||||
|
||||
st_cond_signal(sync_end);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sync_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("sync test: start");
|
||||
|
||||
if ((sync_start = st_mutex_new()) == NULL) {
|
||||
srs_trace("st_mutex_new sync_start failed");
|
||||
return -1;
|
||||
}
|
||||
st_mutex_lock(sync_start);
|
||||
|
||||
if ((sync_cond = st_cond_new()) == NULL) {
|
||||
srs_trace("st_cond_new cond failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sync_end = st_cond_new()) == NULL) {
|
||||
srs_trace("st_cond_new end failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sync_mutex = st_mutex_new()) == NULL) {
|
||||
srs_trace("st_mutex_new mutex failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!st_thread_create(sync_master, NULL, 0, 0)) {
|
||||
srs_trace("st_thread_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!st_thread_create(sync_slave, NULL, 0, 0)) {
|
||||
srs_trace("st_thread_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// run all threads.
|
||||
st_mutex_unlock(sync_start);
|
||||
|
||||
st_cond_wait(sync_end);
|
||||
srs_trace("sync test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* io_client(void* arg)
|
||||
{
|
||||
|
||||
int fd;
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
srs_trace("create linux socket error.");
|
||||
return NULL;
|
||||
}
|
||||
srs_trace("6. client create linux socket success. fd=%d", fd);
|
||||
|
||||
st_netfd_t stfd;
|
||||
if ((stfd = st_netfd_open_socket(fd)) == NULL){
|
||||
srs_trace("st_netfd_open_socket open socket failed.");
|
||||
return NULL;
|
||||
}
|
||||
srs_trace("7. client st open socket success. fd=%d", fd);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(io_port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (st_connect(stfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_in), ST_UTIME_NO_TIMEOUT) == -1) {
|
||||
srs_trace("bind socket error.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
if (st_read_fully(stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) {
|
||||
srs_trace("st_read_fully failed");
|
||||
return NULL;
|
||||
}
|
||||
if (st_write(stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) {
|
||||
srs_trace("st_write failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
st_netfd_close(stfd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int io_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("io test: start, port=%d", io_port);
|
||||
|
||||
int fd;
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
srs_trace("create linux socket error.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("1. server create linux socket success. fd=%d", fd);
|
||||
|
||||
int reuse_socket = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {
|
||||
srs_trace("setsockopt reuse-addr error.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("2. server setsockopt reuse-addr success. fd=%d", fd);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(io_port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(fd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) {
|
||||
srs_trace("bind socket error.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("3. server bind socket success. fd=%d", fd);
|
||||
|
||||
if (listen(fd, 10) == -1) {
|
||||
srs_trace("listen socket error.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("4. server listen socket success. fd=%d", fd);
|
||||
|
||||
st_netfd_t stfd;
|
||||
if ((stfd = st_netfd_open_socket(fd)) == NULL){
|
||||
srs_trace("st_netfd_open_socket open socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("5. server st open socket success. fd=%d", fd);
|
||||
|
||||
if (!st_thread_create(io_client, NULL, 0, 0)) {
|
||||
srs_trace("st_thread_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);
|
||||
srs_trace("8. server get a client. fd=%d", st_netfd_fileno(client_stfd));
|
||||
|
||||
char buf[1024];
|
||||
if (st_write(client_stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) {
|
||||
srs_trace("st_write failed");
|
||||
return -1;
|
||||
}
|
||||
if (st_read_fully(client_stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) {
|
||||
srs_trace("st_read_fully failed");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("9. server io completed.");
|
||||
|
||||
st_netfd_close(stfd);
|
||||
st_netfd_close(client_stfd);
|
||||
|
||||
srs_trace("io test: end");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pipe_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("pipe test: start");
|
||||
|
||||
int fds[2];
|
||||
if (pipe(fds) < 0) {
|
||||
srs_trace("pipe failed");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("1. pipe ok, %d=>%d", fds[1], fds[0]);
|
||||
|
||||
st_netfd_t fdw;
|
||||
if ((fdw = st_netfd_open_socket(fds[1])) == NULL) {
|
||||
srs_trace("st_netfd_open_socket open socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("2. open write fd ok");
|
||||
|
||||
st_netfd_t fdr;
|
||||
if ((fdr = st_netfd_open_socket(fds[0])) == NULL) {
|
||||
srs_trace("st_netfd_open_socket open socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("3. open read fd ok");
|
||||
|
||||
char buf[1024];
|
||||
if (st_write(fdw, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) < 0) {
|
||||
srs_trace("st_write socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("4. write to pipe ok");
|
||||
|
||||
if (st_read(fdr, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) < 0) {
|
||||
srs_trace("st_read socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("5. read from pipe ok");
|
||||
|
||||
st_netfd_close(fdw);
|
||||
st_netfd_close(fdr);
|
||||
|
||||
srs_trace("pipe test: end");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
srs_trace("ETIME=%d", ETIME);
|
||||
|
||||
if (st_set_eventsys(ST_EVENTSYS_ALT) < 0) {
|
||||
srs_trace("st_set_eventsys failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (st_init() < 0) {
|
||||
srs_trace("st_init failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sleep2_test() < 0) {
|
||||
srs_trace("sleep2_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sleep_test() < 0) {
|
||||
srs_trace("sleep_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sleep_deviation_test() < 0) {
|
||||
srs_trace("sleep_deviation_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (huge_stack_test() < 0) {
|
||||
srs_trace("huge_stack_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (thread_test() < 0) {
|
||||
srs_trace("thread_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sync_test() < 0) {
|
||||
srs_trace("sync_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (io_test() < 0) {
|
||||
srs_trace("io_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pipe_test() < 0) {
|
||||
srs_trace("pipe_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// cleanup.
|
||||
srs_trace("wait for all thread completed");
|
||||
st_thread_exit(NULL);
|
||||
// the following never enter,
|
||||
// the above code will exit when all thread exit,
|
||||
// current is a primordial st-thread, when all thread exit,
|
||||
// the st idle thread will exit(0), see _st_idle_thread_start()
|
||||
srs_trace("all thread completed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#ifndef _st_icpp_init_stub
|
||||
#define _st_icpp_init_stub
|
||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||
file
|
||||
main readonly separator,
|
||||
..\srs.c,
|
||||
st readonly separator,
|
||||
..\common.h,
|
||||
..\event.c,
|
||||
..\io.c,
|
||||
..\key.c,
|
||||
..\md.h,
|
||||
..\md.S,
|
||||
..\public.h,
|
||||
..\sched.c,
|
||||
..\stk.c,
|
||||
..\sync.c;
|
||||
|
||||
mainconfig
|
||||
"" = "MAIN";
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include "common.h"
|
||||
|
||||
/* How much space to leave between the stacks, at each end */
|
||||
#define REDZONE _ST_PAGE_SIZE
|
||||
|
||||
_st_clist_t _st_free_stacks = ST_INIT_STATIC_CLIST(&_st_free_stacks);
|
||||
int _st_num_free_stacks = 0;
|
||||
int _st_randomize_stacks = 0;
|
||||
|
||||
static char *_st_new_stk_segment(int size);
|
||||
|
||||
/**
|
||||
The below comments is by winlin:
|
||||
The stack memory struct:
|
||||
| REDZONE | stack | extra | REDZONE |
|
||||
+---------+------------------------+---------+---------+
|
||||
| 4k | | 4k/0 | 4k |
|
||||
+---------+------------------------+---------+---------+
|
||||
vaddr bottom top
|
||||
When _st_randomize_stacks is on, by st_randomize_stacks(),
|
||||
the bottom and top will random movided in the extra:
|
||||
long offset = (random() % extra) & ~0xf;
|
||||
ts->stk_bottom += offset;
|
||||
ts->stk_top += offset;
|
||||
Both REDZONE are protected by mprotect when DEBUG is on.
|
||||
*/
|
||||
_st_stack_t *_st_stack_new(int stack_size)
|
||||
{
|
||||
_st_clist_t *qp;
|
||||
_st_stack_t *ts;
|
||||
int extra;
|
||||
|
||||
// TODO: WINLIN: remove the stack reuse.
|
||||
for (qp = _st_free_stacks.next; qp != &_st_free_stacks; qp = qp->next) {
|
||||
ts = _ST_THREAD_STACK_PTR(qp);
|
||||
if (ts->stk_size >= stack_size) {
|
||||
/* Found a stack that is big enough */
|
||||
ST_REMOVE_LINK(&ts->links);
|
||||
_st_num_free_stacks--;
|
||||
ts->links.next = NULL;
|
||||
ts->links.prev = NULL;
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a new thread stack object. */
|
||||
if ((ts = (_st_stack_t *)calloc(1, sizeof(_st_stack_t))) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
extra = _st_randomize_stacks ? _ST_PAGE_SIZE : 0;
|
||||
ts->vaddr_size = stack_size + 2*REDZONE + extra;
|
||||
ts->vaddr = _st_new_stk_segment(ts->vaddr_size);
|
||||
if (!ts->vaddr) {
|
||||
free(ts);
|
||||
return NULL;
|
||||
}
|
||||
ts->stk_size = stack_size;
|
||||
ts->stk_bottom = ts->vaddr + REDZONE;
|
||||
ts->stk_top = ts->stk_bottom + stack_size;
|
||||
|
||||
#ifdef DEBUG
|
||||
mprotect(ts->vaddr, REDZONE, PROT_NONE);
|
||||
mprotect(ts->stk_top + extra, REDZONE, PROT_NONE);
|
||||
#endif
|
||||
|
||||
if (extra) {
|
||||
long offset = (random() % extra) & ~0xf;
|
||||
|
||||
ts->stk_bottom += offset;
|
||||
ts->stk_top += offset;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the stack for the current thread
|
||||
*/
|
||||
void _st_stack_free(_st_stack_t *ts)
|
||||
{
|
||||
if (!ts) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Put the stack on the free list */
|
||||
ST_APPEND_LINK(&ts->links, _st_free_stacks.prev);
|
||||
_st_num_free_stacks++;
|
||||
}
|
||||
|
||||
static char *_st_new_stk_segment(int size)
|
||||
{
|
||||
#ifdef MALLOC_STACK
|
||||
void *vaddr = malloc(size);
|
||||
#else
|
||||
#error "Only Supports Malloc Stack"
|
||||
#endif
|
||||
|
||||
return (char *)vaddr;
|
||||
}
|
||||
|
||||
/* Not used */
|
||||
#if 0
|
||||
void _st_delete_stk_segment(char *vaddr, int size)
|
||||
{
|
||||
#ifdef MALLOC_STACK
|
||||
free(vaddr);
|
||||
#else
|
||||
#error Unknown Stack Malloc
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int st_randomize_stacks(int on)
|
||||
{
|
||||
int wason = _st_randomize_stacks;
|
||||
|
||||
_st_randomize_stacks = on;
|
||||
if (on) {
|
||||
srandom((unsigned int) st_utime());
|
||||
}
|
||||
|
||||
return wason;
|
||||
}
|
|
@ -1,352 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
extern time_t _st_curr_time;
|
||||
extern st_utime_t _st_last_tset;
|
||||
extern int _st_active_count;
|
||||
|
||||
static st_utime_t (*_st_utime)(void) = NULL;
|
||||
|
||||
/*****************************************
|
||||
* Time functions
|
||||
*/
|
||||
|
||||
st_utime_t st_utime(void)
|
||||
{
|
||||
if (_st_utime == NULL) {
|
||||
#ifdef MD_GET_UTIME
|
||||
MD_GET_UTIME();
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
}
|
||||
|
||||
return (*_st_utime)();
|
||||
}
|
||||
|
||||
int st_set_utime_function(st_utime_t (*func)(void))
|
||||
{
|
||||
if (_st_active_count) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_st_utime = func;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
st_utime_t st_utime_last_clock(void)
|
||||
{
|
||||
return _ST_LAST_CLOCK;
|
||||
}
|
||||
|
||||
int st_timecache_set(int on)
|
||||
{
|
||||
int wason = (_st_curr_time) ? 1 : 0;
|
||||
|
||||
if (on) {
|
||||
_st_curr_time = time(NULL);
|
||||
_st_last_tset = st_utime();
|
||||
} else {
|
||||
_st_curr_time = 0;
|
||||
}
|
||||
|
||||
return wason;
|
||||
}
|
||||
|
||||
time_t st_time(void)
|
||||
{
|
||||
if (_st_curr_time) {
|
||||
return _st_curr_time;
|
||||
}
|
||||
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
int st_usleep(st_utime_t usecs)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (usecs != ST_UTIME_NO_TIMEOUT) {
|
||||
me->state = _ST_ST_SLEEPING;
|
||||
_ST_ADD_SLEEPQ(me, usecs);
|
||||
} else {
|
||||
me->state = _ST_ST_SUSPENDED;
|
||||
}
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_sleep(int secs)
|
||||
{
|
||||
return st_usleep((secs >= 0) ? secs * (st_utime_t) 1000000LL : ST_UTIME_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Condition variable functions
|
||||
*/
|
||||
_st_cond_t *st_cond_new(void)
|
||||
{
|
||||
_st_cond_t *cvar;
|
||||
|
||||
cvar = (_st_cond_t *) calloc(1, sizeof(_st_cond_t));
|
||||
if (cvar) {
|
||||
ST_INIT_CLIST(&cvar->wait_q);
|
||||
}
|
||||
|
||||
return cvar;
|
||||
}
|
||||
|
||||
int st_cond_destroy(_st_cond_t *cvar)
|
||||
{
|
||||
if (cvar->wait_q.next != &cvar->wait_q) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(cvar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
int rv;
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Put caller thread on the condition variable's wait queue */
|
||||
me->state = _ST_ST_COND_WAIT;
|
||||
ST_APPEND_LINK(&me->wait_links, &cvar->wait_q);
|
||||
|
||||
if (timeout != ST_UTIME_NO_TIMEOUT) {
|
||||
_ST_ADD_SLEEPQ(me, timeout);
|
||||
}
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
ST_REMOVE_LINK(&me->wait_links);
|
||||
rv = 0;
|
||||
|
||||
if (me->flags & _ST_FL_TIMEDOUT) {
|
||||
me->flags &= ~_ST_FL_TIMEDOUT;
|
||||
errno = ETIME;
|
||||
rv = -1;
|
||||
}
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int st_cond_wait(_st_cond_t *cvar)
|
||||
{
|
||||
return st_cond_timedwait(cvar, ST_UTIME_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
static int _st_cond_signal(_st_cond_t *cvar, int broadcast)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
_st_clist_t *q;
|
||||
|
||||
for (q = cvar->wait_q.next; q != &cvar->wait_q; q = q->next) {
|
||||
thread = _ST_THREAD_WAITQ_PTR(q);
|
||||
if (thread->state == _ST_ST_COND_WAIT) {
|
||||
if (thread->flags & _ST_FL_ON_SLEEPQ) {
|
||||
_ST_DEL_SLEEPQ(thread);
|
||||
}
|
||||
|
||||
/* Make thread runnable */
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(thread);
|
||||
if (!broadcast) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_cond_signal(_st_cond_t *cvar)
|
||||
{
|
||||
return _st_cond_signal(cvar, 0);
|
||||
}
|
||||
|
||||
int st_cond_broadcast(_st_cond_t *cvar)
|
||||
{
|
||||
return _st_cond_signal(cvar, 1);
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Mutex functions
|
||||
*/
|
||||
_st_mutex_t *st_mutex_new(void)
|
||||
{
|
||||
_st_mutex_t *lock;
|
||||
|
||||
lock = (_st_mutex_t *) calloc(1, sizeof(_st_mutex_t));
|
||||
if (lock) {
|
||||
ST_INIT_CLIST(&lock->wait_q);
|
||||
lock->owner = NULL;
|
||||
}
|
||||
|
||||
return lock;
|
||||
}
|
||||
|
||||
int st_mutex_destroy(_st_mutex_t *lock)
|
||||
{
|
||||
if (lock->owner != NULL || lock->wait_q.next != &lock->wait_q) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_mutex_lock(_st_mutex_t *lock)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lock->owner == NULL) {
|
||||
/* Got the mutex */
|
||||
lock->owner = me;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lock->owner == me) {
|
||||
errno = EDEADLK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Put caller thread on the mutex's wait queue */
|
||||
me->state = _ST_ST_LOCK_WAIT;
|
||||
ST_APPEND_LINK(&me->wait_links, &lock->wait_q);
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
ST_REMOVE_LINK(&me->wait_links);
|
||||
|
||||
if ((me->flags & _ST_FL_INTERRUPT) && lock->owner != me) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_mutex_unlock(_st_mutex_t *lock)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
_st_clist_t *q;
|
||||
|
||||
if (lock->owner != _ST_CURRENT_THREAD()) {
|
||||
errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (q = lock->wait_q.next; q != &lock->wait_q; q = q->next) {
|
||||
thread = _ST_THREAD_WAITQ_PTR(q);
|
||||
if (thread->state == _ST_ST_LOCK_WAIT) {
|
||||
lock->owner = thread;
|
||||
/* Make thread runnable */
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(thread);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* No threads waiting on this mutex */
|
||||
lock->owner = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_mutex_trylock(_st_mutex_t *lock)
|
||||
{
|
||||
if (lock->owner != NULL) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Got the mutex */
|
||||
lock->owner = _ST_CURRENT_THREAD();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in a new issue