mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
add linux version of band check app; add web version of band check app
This commit is contained in:
commit
237fb13e1b
35 changed files with 1966 additions and 218 deletions
0
trunk/research/players/js/AdobeFlashPlayerInstall.swf
Executable file → Normal file
0
trunk/research/players/js/AdobeFlashPlayerInstall.swf
Executable file → Normal file
0
trunk/research/players/js/bootstrap.min.js
vendored
Executable file → Normal file
0
trunk/research/players/js/bootstrap.min.js
vendored
Executable file → Normal file
0
trunk/research/players/js/jquery-1.10.2.min.js
vendored
Executable file → Normal file
0
trunk/research/players/js/jquery-1.10.2.min.js
vendored
Executable file → Normal file
0
trunk/research/players/js/jquery-1.10.2.min.map
Executable file → Normal file
0
trunk/research/players/js/jquery-1.10.2.min.map
Executable file → Normal file
486
trunk/research/players/js/json2.js
Executable file
486
trunk/research/players/js/json2.js
Executable file
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
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');
|
||||
};
|
||||
}
|
||||
}());
|
37
trunk/research/players/js/srs.log.js
Executable file
37
trunk/research/players/js/srs.log.js
Executable file
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
363
trunk/research/players/js/srs.page.js
Executable file
363
trunk/research/players/js/srs.page.js
Executable file
|
@ -0,0 +1,363 @@
|
|||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
// to query the swf anti cache.
|
||||
function srs_get_version_code() { return "1.17"; }
|
||||
// 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; }
|
||||
// get the stream published to vhost,
|
||||
// generally we need to transcode the stream to support HLS and filters.
|
||||
// for example, src_vhost is "players", we transcode stream to vhost "players_pub".
|
||||
// if not equals to the player vhost, return the orignal vhost.
|
||||
function srs_get_player_publish_vhost(src_vhost) { return (src_vhost != srs_get_player_vhost())? src_vhost:(src_vhost + "_pub"); }
|
||||
// for chat, use rtmp only vhost, low latecy, without gop cache.
|
||||
function srs_get_player_chat_vhost(src_vhost) { return (src_vhost != srs_get_player_vhost())? src_vhost:(src_vhost + "_pub_rtmp"); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@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 server = (query.server == undefined)? window.location.hostname:query.server;
|
||||
var port = (query.port == undefined)? 1935:query.port;
|
||||
var vhost = (query.vhost == undefined)? window.location.hostname:query.vhost;
|
||||
var app = (query.app == undefined)? "live":query.app;
|
||||
var stream = (query.stream == undefined)? "livestream":query.stream;
|
||||
|
||||
if (server == vhost || vhost == "") {
|
||||
return "rtmp://" + server + ":" + port + "/" + app + "/" + stream;
|
||||
} else {
|
||||
return "rtmp://" + server + ":" + port + "/" + app + "...vhost..." + vhost + "/" + stream;
|
||||
}
|
||||
}
|
||||
// for the chat to init the publish url.
|
||||
function build_default_publish_rtmp_url() {
|
||||
var query = parse_query_string();
|
||||
|
||||
var server = (query.server == undefined)? window.location.hostname:query.server;
|
||||
var port = (query.port == undefined)? 1935:query.port;
|
||||
var vhost = (query.vhost == undefined)? window.location.hostname:query.vhost;
|
||||
var app = (query.app == undefined)? "live":query.app;
|
||||
var stream = (query.stream == undefined)? "livestream":query.stream;
|
||||
|
||||
if (server == vhost || vhost == "") {
|
||||
return "rtmp://" + server + ":" + port + "/" + app + "/" + stream;
|
||||
} else {
|
||||
vhost = srs_get_player_chat_vhost(vhost);
|
||||
return "rtmp://" + server + ":" + port + "/" + app + "...vhost..." + vhost + "/" + stream;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@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 == undefined)? window.location.port:query.hls_port;
|
||||
var app = (query.app == undefined)? "live":query.app;
|
||||
var stream = (query.stream == undefined)? "livestream":query.stream;
|
||||
|
||||
if (port == "" || port == null || port == undefined) {
|
||||
port = 80;
|
||||
}
|
||||
|
||||
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_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());
|
||||
}
|
||||
}
|
||||
|
||||
// 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_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");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
) {
|
||||
srs_initialize_codec_page(
|
||||
cameras, microphones,
|
||||
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate
|
||||
);
|
||||
|
||||
//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);
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
) {
|
||||
srs_initialize_codec_page(
|
||||
cameras, microphones,
|
||||
sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate
|
||||
);
|
||||
|
||||
//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);
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
) {
|
||||
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();
|
||||
}
|
194
trunk/research/players/js/srs.player.js
Executable file
194
trunk/research/players/js/srs.player.js
Executable file
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.8; // default to 0.8
|
||||
this.volume = 1.0; // default to 100%
|
||||
this.callbackObj = null;
|
||||
|
||||
// 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.
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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";
|
||||
|
||||
var params = {};
|
||||
params.wmode = "opaque";
|
||||
params.allowFullScreen = "true";
|
||||
params.allowScriptAccess = "always";
|
||||
|
||||
var attributes = {};
|
||||
|
||||
var self = this;
|
||||
|
||||
swfobject.embedSWF(
|
||||
"srs_player/release/srs_player.swf?_version="+srs_get_version_code(),
|
||||
this.container,
|
||||
this.width, this.height,
|
||||
"11.1", "js/AdobeFlashPlayerInstall.swf",
|
||||
flashvars, params, attributes,
|
||||
function(callbackObj){
|
||||
self.callbackObj = 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.volume);
|
||||
}
|
||||
SrsPlayer.prototype.stop = function() {
|
||||
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;
|
||||
}
|
||||
|
||||
this.callbackObj.ref.__stop();
|
||||
}
|
||||
SrsPlayer.prototype.pause = function() {
|
||||
this.callbackObj.ref.__pause();
|
||||
}
|
||||
SrsPlayer.prototype.resume = function() {
|
||||
this.callbackObj.ref.__resume();
|
||||
}
|
||||
/**
|
||||
* 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) {
|
||||
this.buffer_time = buffer_time;
|
||||
this.callbackObj.ref.__set_bt(buffer_time);
|
||||
}
|
||||
SrsPlayer.prototype.on_player_ready = function() {
|
||||
}
|
||||
SrsPlayer.prototype.on_player_metadata = function(metadata) {
|
||||
// ignore.
|
||||
}
|
||||
SrsPlayer.prototype.on_player_timer = function(time, buffer_length) {
|
||||
// ignore.
|
||||
}
|
||||
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) {
|
||||
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.on_player_timer(time, buffer_length);
|
||||
}
|
173
trunk/research/players/js/srs.publisher.js
Executable file
173
trunk/research/players/js/srs.publisher.js
Executable file
|
@ -0,0 +1,173 @@
|
|||
/**
|
||||
* 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", "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]);
|
||||
}
|
139
trunk/research/players/js/srs.utility.js
Executable file
139
trunk/research/players/js/srs.utility.js
Executable file
|
@ -0,0 +1,139 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse the query string to object.
|
||||
*/
|
||||
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){
|
||||
return obj;
|
||||
}
|
||||
|
||||
var queries = query_string.split("&");
|
||||
$(queries).each(function(){
|
||||
var query = this.split("=");
|
||||
obj[query[0]] = query[1];
|
||||
obj.user_query[query[0]] = query[1];
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
// @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 port = (a.port == "")? "1935":a.port;
|
||||
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("&"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ret = {
|
||||
server: a.hostname, port: port,
|
||||
vhost: vhost, app: app, stream: stream
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the agent.
|
||||
* @return an object specifies some browser.
|
||||
* for example, get_browser_agents().MSIE
|
||||
*/
|
||||
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
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue