|
|
|
@ -1,307 +1,4 @@ |
|
|
|
|
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.statistics=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
|
|
|
|
// Copyright Joyent, Inc. and other Node contributors.
|
|
|
|
|
//
|
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
function EventEmitter() { |
|
|
|
|
this._events = this._events || {}; |
|
|
|
|
this._maxListeners = this._maxListeners || undefined; |
|
|
|
|
} |
|
|
|
|
module.exports = EventEmitter; |
|
|
|
|
|
|
|
|
|
// Backwards-compat with node 0.10.x
|
|
|
|
|
EventEmitter.EventEmitter = EventEmitter; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype._events = undefined; |
|
|
|
|
EventEmitter.prototype._maxListeners = undefined; |
|
|
|
|
|
|
|
|
|
// By default EventEmitters will print a warning if more than 10 listeners are
|
|
|
|
|
// added to it. This is a useful default which helps finding memory leaks.
|
|
|
|
|
EventEmitter.defaultMaxListeners = 10; |
|
|
|
|
|
|
|
|
|
// Obviously not all Emitters should be limited to 10. This function allows
|
|
|
|
|
// that to be increased. Set to zero for unlimited.
|
|
|
|
|
EventEmitter.prototype.setMaxListeners = function(n) { |
|
|
|
|
if (!isNumber(n) || n < 0 || isNaN(n)) |
|
|
|
|
throw TypeError('n must be a positive number'); |
|
|
|
|
this._maxListeners = n; |
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype.emit = function(type) { |
|
|
|
|
var er, handler, len, args, i, listeners; |
|
|
|
|
|
|
|
|
|
if (!this._events) |
|
|
|
|
this._events = {}; |
|
|
|
|
|
|
|
|
|
// If there is no 'error' event listener then throw.
|
|
|
|
|
if (type === 'error') { |
|
|
|
|
if (!this._events.error || |
|
|
|
|
(isObject(this._events.error) && !this._events.error.length)) { |
|
|
|
|
er = arguments[1]; |
|
|
|
|
if (er instanceof Error) { |
|
|
|
|
throw er; // Unhandled 'error' event
|
|
|
|
|
} |
|
|
|
|
throw TypeError('Uncaught, unspecified "error" event.'); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
handler = this._events[type]; |
|
|
|
|
|
|
|
|
|
if (isUndefined(handler)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
if (isFunction(handler)) { |
|
|
|
|
switch (arguments.length) { |
|
|
|
|
// fast cases
|
|
|
|
|
case 1: |
|
|
|
|
handler.call(this); |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
handler.call(this, arguments[1]); |
|
|
|
|
break; |
|
|
|
|
case 3: |
|
|
|
|
handler.call(this, arguments[1], arguments[2]); |
|
|
|
|
break; |
|
|
|
|
// slower
|
|
|
|
|
default: |
|
|
|
|
len = arguments.length; |
|
|
|
|
args = new Array(len - 1); |
|
|
|
|
for (i = 1; i < len; i++) |
|
|
|
|
args[i - 1] = arguments[i]; |
|
|
|
|
handler.apply(this, args); |
|
|
|
|
} |
|
|
|
|
} else if (isObject(handler)) { |
|
|
|
|
len = arguments.length; |
|
|
|
|
args = new Array(len - 1); |
|
|
|
|
for (i = 1; i < len; i++) |
|
|
|
|
args[i - 1] = arguments[i]; |
|
|
|
|
|
|
|
|
|
listeners = handler.slice(); |
|
|
|
|
len = listeners.length; |
|
|
|
|
for (i = 0; i < len; i++) |
|
|
|
|
listeners[i].apply(this, args); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype.addListener = function(type, listener) { |
|
|
|
|
var m; |
|
|
|
|
|
|
|
|
|
if (!isFunction(listener)) |
|
|
|
|
throw TypeError('listener must be a function'); |
|
|
|
|
|
|
|
|
|
if (!this._events) |
|
|
|
|
this._events = {}; |
|
|
|
|
|
|
|
|
|
// To avoid recursion in the case that type === "newListener"! Before
|
|
|
|
|
// adding it to the listeners, first emit "newListener".
|
|
|
|
|
if (this._events.newListener) |
|
|
|
|
this.emit('newListener', type, |
|
|
|
|
isFunction(listener.listener) ? |
|
|
|
|
listener.listener : listener); |
|
|
|
|
|
|
|
|
|
if (!this._events[type]) |
|
|
|
|
// Optimize the case of one listener. Don't need the extra array object.
|
|
|
|
|
this._events[type] = listener; |
|
|
|
|
else if (isObject(this._events[type])) |
|
|
|
|
// If we've already got an array, just append.
|
|
|
|
|
this._events[type].push(listener); |
|
|
|
|
else |
|
|
|
|
// Adding the second element, need to change to array.
|
|
|
|
|
this._events[type] = [this._events[type], listener]; |
|
|
|
|
|
|
|
|
|
// Check for listener leak
|
|
|
|
|
if (isObject(this._events[type]) && !this._events[type].warned) { |
|
|
|
|
var m; |
|
|
|
|
if (!isUndefined(this._maxListeners)) { |
|
|
|
|
m = this._maxListeners; |
|
|
|
|
} else { |
|
|
|
|
m = EventEmitter.defaultMaxListeners; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (m && m > 0 && this._events[type].length > m) { |
|
|
|
|
this._events[type].warned = true; |
|
|
|
|
console.error('(node) warning: possible EventEmitter memory ' + |
|
|
|
|
'leak detected. %d listeners added. ' + |
|
|
|
|
'Use emitter.setMaxListeners() to increase limit.', |
|
|
|
|
this._events[type].length); |
|
|
|
|
if (typeof console.trace === 'function') { |
|
|
|
|
// not supported in IE 10
|
|
|
|
|
console.trace(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype.once = function(type, listener) { |
|
|
|
|
if (!isFunction(listener)) |
|
|
|
|
throw TypeError('listener must be a function'); |
|
|
|
|
|
|
|
|
|
var fired = false; |
|
|
|
|
|
|
|
|
|
function g() { |
|
|
|
|
this.removeListener(type, g); |
|
|
|
|
|
|
|
|
|
if (!fired) { |
|
|
|
|
fired = true; |
|
|
|
|
listener.apply(this, arguments); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
g.listener = listener; |
|
|
|
|
this.on(type, g); |
|
|
|
|
|
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// emits a 'removeListener' event iff the listener was removed
|
|
|
|
|
EventEmitter.prototype.removeListener = function(type, listener) { |
|
|
|
|
var list, position, length, i; |
|
|
|
|
|
|
|
|
|
if (!isFunction(listener)) |
|
|
|
|
throw TypeError('listener must be a function'); |
|
|
|
|
|
|
|
|
|
if (!this._events || !this._events[type]) |
|
|
|
|
return this; |
|
|
|
|
|
|
|
|
|
list = this._events[type]; |
|
|
|
|
length = list.length; |
|
|
|
|
position = -1; |
|
|
|
|
|
|
|
|
|
if (list === listener || |
|
|
|
|
(isFunction(list.listener) && list.listener === listener)) { |
|
|
|
|
delete this._events[type]; |
|
|
|
|
if (this._events.removeListener) |
|
|
|
|
this.emit('removeListener', type, listener); |
|
|
|
|
|
|
|
|
|
} else if (isObject(list)) { |
|
|
|
|
for (i = length; i-- > 0;) { |
|
|
|
|
if (list[i] === listener || |
|
|
|
|
(list[i].listener && list[i].listener === listener)) { |
|
|
|
|
position = i; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (position < 0) |
|
|
|
|
return this; |
|
|
|
|
|
|
|
|
|
if (list.length === 1) { |
|
|
|
|
list.length = 0; |
|
|
|
|
delete this._events[type]; |
|
|
|
|
} else { |
|
|
|
|
list.splice(position, 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (this._events.removeListener) |
|
|
|
|
this.emit('removeListener', type, listener); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype.removeAllListeners = function(type) { |
|
|
|
|
var key, listeners; |
|
|
|
|
|
|
|
|
|
if (!this._events) |
|
|
|
|
return this; |
|
|
|
|
|
|
|
|
|
// not listening for removeListener, no need to emit
|
|
|
|
|
if (!this._events.removeListener) { |
|
|
|
|
if (arguments.length === 0) |
|
|
|
|
this._events = {}; |
|
|
|
|
else if (this._events[type]) |
|
|
|
|
delete this._events[type]; |
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// emit removeListener for all listeners on all events
|
|
|
|
|
if (arguments.length === 0) { |
|
|
|
|
for (key in this._events) { |
|
|
|
|
if (key === 'removeListener') continue; |
|
|
|
|
this.removeAllListeners(key); |
|
|
|
|
} |
|
|
|
|
this.removeAllListeners('removeListener'); |
|
|
|
|
this._events = {}; |
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
listeners = this._events[type]; |
|
|
|
|
|
|
|
|
|
if (isFunction(listeners)) { |
|
|
|
|
this.removeListener(type, listeners); |
|
|
|
|
} else { |
|
|
|
|
// LIFO order
|
|
|
|
|
while (listeners.length) |
|
|
|
|
this.removeListener(type, listeners[listeners.length - 1]); |
|
|
|
|
} |
|
|
|
|
delete this._events[type]; |
|
|
|
|
|
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype.listeners = function(type) { |
|
|
|
|
var ret; |
|
|
|
|
if (!this._events || !this._events[type]) |
|
|
|
|
ret = []; |
|
|
|
|
else if (isFunction(this._events[type])) |
|
|
|
|
ret = [this._events[type]]; |
|
|
|
|
else |
|
|
|
|
ret = this._events[type].slice(); |
|
|
|
|
return ret; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.listenerCount = function(emitter, type) { |
|
|
|
|
var ret; |
|
|
|
|
if (!emitter._events || !emitter._events[type]) |
|
|
|
|
ret = 0; |
|
|
|
|
else if (isFunction(emitter._events[type])) |
|
|
|
|
ret = 1; |
|
|
|
|
else |
|
|
|
|
ret = emitter._events[type].length; |
|
|
|
|
return ret; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function isFunction(arg) { |
|
|
|
|
return typeof arg === 'function'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function isNumber(arg) { |
|
|
|
|
return typeof arg === 'number'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function isObject(arg) { |
|
|
|
|
return typeof arg === 'object' && arg !== null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function isUndefined(arg) { |
|
|
|
|
return arg === void 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
},{}],2:[function(require,module,exports){ |
|
|
|
|
/** |
|
|
|
|
* Provides statistics for the local stream. |
|
|
|
|
*/ |
|
|
|
@ -432,7 +129,7 @@ LocalStatsCollector.prototype.stop = function () { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
module.exports = LocalStatsCollector; |
|
|
|
|
},{}],3:[function(require,module,exports){ |
|
|
|
|
},{}],2:[function(require,module,exports){ |
|
|
|
|
/* global focusMucJid, ssrc2jid */ |
|
|
|
|
/* jshint -W117 */ |
|
|
|
|
/** |
|
|
|
@ -1143,144 +840,449 @@ StatsCollector.prototype.processAudioLevelReport = function () |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
},{}],4:[function(require,module,exports){ |
|
|
|
|
/** |
|
|
|
|
* Created by hristo on 8/4/14. |
|
|
|
|
*/ |
|
|
|
|
var LocalStats = require("./LocalStatsCollector.js"); |
|
|
|
|
var RTPStats = require("./RTPStatsCollector.js"); |
|
|
|
|
var EventEmitter = require("events"); |
|
|
|
|
//These lines should be uncommented when require works in app.js
|
|
|
|
|
//var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
|
|
|
|
|
//var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
|
|
|
|
|
//var XMPPEvents = require("../service/xmpp/XMPPEvents");
|
|
|
|
|
},{}],3:[function(require,module,exports){ |
|
|
|
|
/** |
|
|
|
|
* Created by hristo on 8/4/14. |
|
|
|
|
*/ |
|
|
|
|
var LocalStats = require("./LocalStatsCollector.js"); |
|
|
|
|
var RTPStats = require("./RTPStatsCollector.js"); |
|
|
|
|
var EventEmitter = require("events"); |
|
|
|
|
//These lines should be uncommented when require works in app.js
|
|
|
|
|
//var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
|
|
|
|
|
//var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
|
|
|
|
|
//var XMPPEvents = require("../service/xmpp/XMPPEvents");
|
|
|
|
|
|
|
|
|
|
var eventEmitter = new EventEmitter(); |
|
|
|
|
|
|
|
|
|
var localStats = null; |
|
|
|
|
|
|
|
|
|
var rtpStats = null; |
|
|
|
|
|
|
|
|
|
function stopLocal() |
|
|
|
|
{ |
|
|
|
|
if(localStats) |
|
|
|
|
{ |
|
|
|
|
localStats.stop(); |
|
|
|
|
localStats = null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function stopRemote() |
|
|
|
|
{ |
|
|
|
|
if(rtpStats) |
|
|
|
|
{ |
|
|
|
|
rtpStats.stop(); |
|
|
|
|
eventEmitter.emit("statistics.stop"); |
|
|
|
|
rtpStats = null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function startRemoteStats (peerconnection) { |
|
|
|
|
if (config.enableRtpStats) |
|
|
|
|
{ |
|
|
|
|
if(rtpStats) |
|
|
|
|
{ |
|
|
|
|
rtpStats.stop(); |
|
|
|
|
rtpStats = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
rtpStats = new RTPStats(peerconnection, 200, 2000, eventEmitter); |
|
|
|
|
rtpStats.start(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function onStreamCreated(stream) |
|
|
|
|
{ |
|
|
|
|
if(stream.getOriginalStream().getAudioTracks().length === 0) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
localStats = new LocalStats(stream.getOriginalStream(), 100, statistics, |
|
|
|
|
eventEmitter); |
|
|
|
|
localStats.start(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var statistics = |
|
|
|
|
{ |
|
|
|
|
/** |
|
|
|
|
* Indicates that this audio level is for local jid. |
|
|
|
|
* @type {string} |
|
|
|
|
*/ |
|
|
|
|
LOCAL_JID: 'local', |
|
|
|
|
|
|
|
|
|
addAudioLevelListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.on("statistics.audioLevel", listener); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
removeAudioLevelListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.removeListener("statistics.audioLevel", listener); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
addConnectionStatsListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.on("statistics.connectionstats", listener); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
removeConnectionStatsListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.removeListener("statistics.connectionstats", listener); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
addRemoteStatsStopListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.on("statistics.stop", listener); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
removeRemoteStatsStopListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.removeListener("statistics.stop", listener); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
stop: function () { |
|
|
|
|
stopLocal(); |
|
|
|
|
stopRemote(); |
|
|
|
|
if(eventEmitter) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.removeAllListeners(); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
stopRemoteStatistics: function() |
|
|
|
|
{ |
|
|
|
|
stopRemote(); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
onConferenceCreated: function (event) { |
|
|
|
|
startRemoteStats(event.peerconnection); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
onDisposeConference: function (onUnload) { |
|
|
|
|
stopRemote(); |
|
|
|
|
if(onUnload) { |
|
|
|
|
stopLocal(); |
|
|
|
|
eventEmitter.removeAllListeners(); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
start: function () { |
|
|
|
|
RTC.addStreamListener(onStreamCreated, |
|
|
|
|
StreamEventTypes.EVENT_TYPE_LOCAL_CREATED); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = statistics; |
|
|
|
|
},{"./LocalStatsCollector.js":1,"./RTPStatsCollector.js":2,"events":4}],4:[function(require,module,exports){ |
|
|
|
|
// Copyright Joyent, Inc. and other Node contributors.
|
|
|
|
|
//
|
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
function EventEmitter() { |
|
|
|
|
this._events = this._events || {}; |
|
|
|
|
this._maxListeners = this._maxListeners || undefined; |
|
|
|
|
} |
|
|
|
|
module.exports = EventEmitter; |
|
|
|
|
|
|
|
|
|
// Backwards-compat with node 0.10.x
|
|
|
|
|
EventEmitter.EventEmitter = EventEmitter; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype._events = undefined; |
|
|
|
|
EventEmitter.prototype._maxListeners = undefined; |
|
|
|
|
|
|
|
|
|
// By default EventEmitters will print a warning if more than 10 listeners are
|
|
|
|
|
// added to it. This is a useful default which helps finding memory leaks.
|
|
|
|
|
EventEmitter.defaultMaxListeners = 10; |
|
|
|
|
|
|
|
|
|
// Obviously not all Emitters should be limited to 10. This function allows
|
|
|
|
|
// that to be increased. Set to zero for unlimited.
|
|
|
|
|
EventEmitter.prototype.setMaxListeners = function(n) { |
|
|
|
|
if (!isNumber(n) || n < 0 || isNaN(n)) |
|
|
|
|
throw TypeError('n must be a positive number'); |
|
|
|
|
this._maxListeners = n; |
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype.emit = function(type) { |
|
|
|
|
var er, handler, len, args, i, listeners; |
|
|
|
|
|
|
|
|
|
if (!this._events) |
|
|
|
|
this._events = {}; |
|
|
|
|
|
|
|
|
|
// If there is no 'error' event listener then throw.
|
|
|
|
|
if (type === 'error') { |
|
|
|
|
if (!this._events.error || |
|
|
|
|
(isObject(this._events.error) && !this._events.error.length)) { |
|
|
|
|
er = arguments[1]; |
|
|
|
|
if (er instanceof Error) { |
|
|
|
|
throw er; // Unhandled 'error' event
|
|
|
|
|
} else { |
|
|
|
|
throw TypeError('Uncaught, unspecified "error" event.'); |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
handler = this._events[type]; |
|
|
|
|
|
|
|
|
|
if (isUndefined(handler)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
if (isFunction(handler)) { |
|
|
|
|
switch (arguments.length) { |
|
|
|
|
// fast cases
|
|
|
|
|
case 1: |
|
|
|
|
handler.call(this); |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
handler.call(this, arguments[1]); |
|
|
|
|
break; |
|
|
|
|
case 3: |
|
|
|
|
handler.call(this, arguments[1], arguments[2]); |
|
|
|
|
break; |
|
|
|
|
// slower
|
|
|
|
|
default: |
|
|
|
|
len = arguments.length; |
|
|
|
|
args = new Array(len - 1); |
|
|
|
|
for (i = 1; i < len; i++) |
|
|
|
|
args[i - 1] = arguments[i]; |
|
|
|
|
handler.apply(this, args); |
|
|
|
|
} |
|
|
|
|
} else if (isObject(handler)) { |
|
|
|
|
len = arguments.length; |
|
|
|
|
args = new Array(len - 1); |
|
|
|
|
for (i = 1; i < len; i++) |
|
|
|
|
args[i - 1] = arguments[i]; |
|
|
|
|
|
|
|
|
|
listeners = handler.slice(); |
|
|
|
|
len = listeners.length; |
|
|
|
|
for (i = 0; i < len; i++) |
|
|
|
|
listeners[i].apply(this, args); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype.addListener = function(type, listener) { |
|
|
|
|
var m; |
|
|
|
|
|
|
|
|
|
if (!isFunction(listener)) |
|
|
|
|
throw TypeError('listener must be a function'); |
|
|
|
|
|
|
|
|
|
if (!this._events) |
|
|
|
|
this._events = {}; |
|
|
|
|
|
|
|
|
|
// To avoid recursion in the case that type === "newListener"! Before
|
|
|
|
|
// adding it to the listeners, first emit "newListener".
|
|
|
|
|
if (this._events.newListener) |
|
|
|
|
this.emit('newListener', type, |
|
|
|
|
isFunction(listener.listener) ? |
|
|
|
|
listener.listener : listener); |
|
|
|
|
|
|
|
|
|
if (!this._events[type]) |
|
|
|
|
// Optimize the case of one listener. Don't need the extra array object.
|
|
|
|
|
this._events[type] = listener; |
|
|
|
|
else if (isObject(this._events[type])) |
|
|
|
|
// If we've already got an array, just append.
|
|
|
|
|
this._events[type].push(listener); |
|
|
|
|
else |
|
|
|
|
// Adding the second element, need to change to array.
|
|
|
|
|
this._events[type] = [this._events[type], listener]; |
|
|
|
|
|
|
|
|
|
// Check for listener leak
|
|
|
|
|
if (isObject(this._events[type]) && !this._events[type].warned) { |
|
|
|
|
var m; |
|
|
|
|
if (!isUndefined(this._maxListeners)) { |
|
|
|
|
m = this._maxListeners; |
|
|
|
|
} else { |
|
|
|
|
m = EventEmitter.defaultMaxListeners; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (m && m > 0 && this._events[type].length > m) { |
|
|
|
|
this._events[type].warned = true; |
|
|
|
|
console.error('(node) warning: possible EventEmitter memory ' + |
|
|
|
|
'leak detected. %d listeners added. ' + |
|
|
|
|
'Use emitter.setMaxListeners() to increase limit.', |
|
|
|
|
this._events[type].length); |
|
|
|
|
if (typeof console.trace === 'function') { |
|
|
|
|
// not supported in IE 10
|
|
|
|
|
console.trace(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
var eventEmitter = new EventEmitter(); |
|
|
|
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener; |
|
|
|
|
|
|
|
|
|
var localStats = null; |
|
|
|
|
EventEmitter.prototype.once = function(type, listener) { |
|
|
|
|
if (!isFunction(listener)) |
|
|
|
|
throw TypeError('listener must be a function'); |
|
|
|
|
|
|
|
|
|
var rtpStats = null; |
|
|
|
|
var fired = false; |
|
|
|
|
|
|
|
|
|
function stopLocal() |
|
|
|
|
{ |
|
|
|
|
if(localStats) |
|
|
|
|
{ |
|
|
|
|
localStats.stop(); |
|
|
|
|
localStats = null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
function g() { |
|
|
|
|
this.removeListener(type, g); |
|
|
|
|
|
|
|
|
|
function stopRemote() |
|
|
|
|
{ |
|
|
|
|
if(rtpStats) |
|
|
|
|
{ |
|
|
|
|
rtpStats.stop(); |
|
|
|
|
eventEmitter.emit("statistics.stop"); |
|
|
|
|
rtpStats = null; |
|
|
|
|
if (!fired) { |
|
|
|
|
fired = true; |
|
|
|
|
listener.apply(this, arguments); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function startRemoteStats (peerconnection) { |
|
|
|
|
if (config.enableRtpStats) |
|
|
|
|
{ |
|
|
|
|
if(rtpStats) |
|
|
|
|
{ |
|
|
|
|
rtpStats.stop(); |
|
|
|
|
rtpStats = null; |
|
|
|
|
} |
|
|
|
|
g.listener = listener; |
|
|
|
|
this.on(type, g); |
|
|
|
|
|
|
|
|
|
rtpStats = new RTPStats(peerconnection, 200, 2000, eventEmitter); |
|
|
|
|
rtpStats.start(); |
|
|
|
|
} |
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
// emits a 'removeListener' event iff the listener was removed
|
|
|
|
|
EventEmitter.prototype.removeListener = function(type, listener) { |
|
|
|
|
var list, position, length, i; |
|
|
|
|
|
|
|
|
|
function onStreamCreated(stream) |
|
|
|
|
{ |
|
|
|
|
if(stream.getAudioTracks().length === 0) |
|
|
|
|
return; |
|
|
|
|
if (!isFunction(listener)) |
|
|
|
|
throw TypeError('listener must be a function'); |
|
|
|
|
|
|
|
|
|
localStats = new LocalStats(stream, 100, this, |
|
|
|
|
eventEmitter); |
|
|
|
|
localStats.start(); |
|
|
|
|
} |
|
|
|
|
if (!this._events || !this._events[type]) |
|
|
|
|
return this; |
|
|
|
|
|
|
|
|
|
list = this._events[type]; |
|
|
|
|
length = list.length; |
|
|
|
|
position = -1; |
|
|
|
|
|
|
|
|
|
var statistics = |
|
|
|
|
{ |
|
|
|
|
/** |
|
|
|
|
* Indicates that this audio level is for local jid. |
|
|
|
|
* @type {string} |
|
|
|
|
*/ |
|
|
|
|
LOCAL_JID: 'local', |
|
|
|
|
if (list === listener || |
|
|
|
|
(isFunction(list.listener) && list.listener === listener)) { |
|
|
|
|
delete this._events[type]; |
|
|
|
|
if (this._events.removeListener) |
|
|
|
|
this.emit('removeListener', type, listener); |
|
|
|
|
|
|
|
|
|
addAudioLevelListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.on("statistics.audioLevel", listener); |
|
|
|
|
}, |
|
|
|
|
} else if (isObject(list)) { |
|
|
|
|
for (i = length; i-- > 0;) { |
|
|
|
|
if (list[i] === listener || |
|
|
|
|
(list[i].listener && list[i].listener === listener)) { |
|
|
|
|
position = i; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
removeAudioLevelListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.removeListener("statistics.audioLevel", listener); |
|
|
|
|
}, |
|
|
|
|
if (position < 0) |
|
|
|
|
return this; |
|
|
|
|
|
|
|
|
|
addConnectionStatsListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.on("statistics.connectionstats", listener); |
|
|
|
|
}, |
|
|
|
|
if (list.length === 1) { |
|
|
|
|
list.length = 0; |
|
|
|
|
delete this._events[type]; |
|
|
|
|
} else { |
|
|
|
|
list.splice(position, 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
removeConnectionStatsListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.removeListener("statistics.connectionstats", listener); |
|
|
|
|
}, |
|
|
|
|
if (this._events.removeListener) |
|
|
|
|
this.emit('removeListener', type, listener); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
addRemoteStatsStopListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.on("statistics.stop", listener); |
|
|
|
|
}, |
|
|
|
|
EventEmitter.prototype.removeAllListeners = function(type) { |
|
|
|
|
var key, listeners; |
|
|
|
|
|
|
|
|
|
removeRemoteStatsStopListener: function(listener) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.removeListener("statistics.stop", listener); |
|
|
|
|
}, |
|
|
|
|
if (!this._events) |
|
|
|
|
return this; |
|
|
|
|
|
|
|
|
|
stop: function () { |
|
|
|
|
stopLocal(); |
|
|
|
|
stopRemote(); |
|
|
|
|
if(eventEmitter) |
|
|
|
|
{ |
|
|
|
|
eventEmitter.removeAllListeners(); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// not listening for removeListener, no need to emit
|
|
|
|
|
if (!this._events.removeListener) { |
|
|
|
|
if (arguments.length === 0) |
|
|
|
|
this._events = {}; |
|
|
|
|
else if (this._events[type]) |
|
|
|
|
delete this._events[type]; |
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
stopRemoteStatistics: function() |
|
|
|
|
{ |
|
|
|
|
stopRemote(); |
|
|
|
|
}, |
|
|
|
|
// emit removeListener for all listeners on all events
|
|
|
|
|
if (arguments.length === 0) { |
|
|
|
|
for (key in this._events) { |
|
|
|
|
if (key === 'removeListener') continue; |
|
|
|
|
this.removeAllListeners(key); |
|
|
|
|
} |
|
|
|
|
this.removeAllListeners('removeListener'); |
|
|
|
|
this._events = {}; |
|
|
|
|
return this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
onConferenceCreated: function (event) { |
|
|
|
|
startRemoteStats(event.peerconnection); |
|
|
|
|
}, |
|
|
|
|
listeners = this._events[type]; |
|
|
|
|
|
|
|
|
|
onDisposeConference: function (onUnload) { |
|
|
|
|
stopRemote(); |
|
|
|
|
if(onUnload) { |
|
|
|
|
stopLocal(); |
|
|
|
|
eventEmitter.removeAllListeners(); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
if (isFunction(listeners)) { |
|
|
|
|
this.removeListener(type, listeners); |
|
|
|
|
} else { |
|
|
|
|
// LIFO order
|
|
|
|
|
while (listeners.length) |
|
|
|
|
this.removeListener(type, listeners[listeners.length - 1]); |
|
|
|
|
} |
|
|
|
|
delete this._events[type]; |
|
|
|
|
|
|
|
|
|
start: function () { |
|
|
|
|
RTC.addStreamListener(onStreamCreated, |
|
|
|
|
StreamEventTypes.EVENT_TYPE_LOCAL_CREATED); |
|
|
|
|
} |
|
|
|
|
return this; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.prototype.listeners = function(type) { |
|
|
|
|
var ret; |
|
|
|
|
if (!this._events || !this._events[type]) |
|
|
|
|
ret = []; |
|
|
|
|
else if (isFunction(this._events[type])) |
|
|
|
|
ret = [this._events[type]]; |
|
|
|
|
else |
|
|
|
|
ret = this._events[type].slice(); |
|
|
|
|
return ret; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
EventEmitter.listenerCount = function(emitter, type) { |
|
|
|
|
var ret; |
|
|
|
|
if (!emitter._events || !emitter._events[type]) |
|
|
|
|
ret = 0; |
|
|
|
|
else if (isFunction(emitter._events[type])) |
|
|
|
|
ret = 1; |
|
|
|
|
else |
|
|
|
|
ret = emitter._events[type].length; |
|
|
|
|
return ret; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function isFunction(arg) { |
|
|
|
|
return typeof arg === 'function'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function isNumber(arg) { |
|
|
|
|
return typeof arg === 'number'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function isObject(arg) { |
|
|
|
|
return typeof arg === 'object' && arg !== null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function isUndefined(arg) { |
|
|
|
|
return arg === void 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
module.exports = statistics; |
|
|
|
|
},{"./LocalStatsCollector.js":2,"./RTPStatsCollector.js":3,"events":1}]},{},[4])(4) |
|
|
|
|
},{}]},{},[3])(3) |
|
|
|
|
}); |