Adds audio level statistics for the local stream.
This commit is contained in:
parent
ccfa620f46
commit
873cfebe84
57
app.js
57
app.js
|
@ -14,6 +14,12 @@ var ssrc2jid = {};
|
||||||
*/
|
*/
|
||||||
var statsCollector = null;
|
var statsCollector = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stats collector for the local stream.
|
||||||
|
* @type {LocalStatsCollector}
|
||||||
|
*/
|
||||||
|
var localStatsCollector = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether ssrc is camera video or desktop stream.
|
* Indicates whether ssrc is camera video or desktop stream.
|
||||||
* FIXME: remove those maps
|
* FIXME: remove those maps
|
||||||
|
@ -123,6 +129,8 @@ function audioStreamReady(stream) {
|
||||||
|
|
||||||
VideoLayout.changeLocalAudio(stream);
|
VideoLayout.changeLocalAudio(stream);
|
||||||
|
|
||||||
|
startLocalRtpStatsCollector(stream);
|
||||||
|
|
||||||
if (RTC.browser !== 'firefox') {
|
if (RTC.browser !== 'firefox') {
|
||||||
getUserMediaWithConstraints(['video'],
|
getUserMediaWithConstraints(['video'],
|
||||||
videoStreamReady,
|
videoStreamReady,
|
||||||
|
@ -445,19 +453,55 @@ function statsUpdated(statsCollector)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback called by {@link LocalStatsCollector} in intervals supplied to it's
|
||||||
|
* constructor.
|
||||||
|
* @param statsCollector {@link LocalStatsCollector} source of the event.
|
||||||
|
*/
|
||||||
|
function localStatsUpdated(statsCollector)
|
||||||
|
{
|
||||||
|
console.info("Local audio level: " + statsCollector.audioLevel);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the {@link StatsCollector} if the feature is enabled in config.js.
|
* Starts the {@link StatsCollector} if the feature is enabled in config.js.
|
||||||
*/
|
*/
|
||||||
function startRtpStatsCollector()
|
function startRtpStatsCollector()
|
||||||
{
|
{
|
||||||
if (config.enableRtpStats)
|
if (config.enableRtpStats && !statsCollector)
|
||||||
{
|
{
|
||||||
statsCollector = new StatsCollector(
|
statsCollector = new StatsCollector(
|
||||||
getConferenceHandler().peerconnection, 200, statsUpdated);
|
getConferenceHandler().peerconnection, 200, statsUpdated);
|
||||||
|
|
||||||
|
stopLocalRtpStatsCollector();
|
||||||
|
|
||||||
statsCollector.start();
|
statsCollector.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Starts the {@link LocalStatsCollector} if the feature is enabled in config.js
|
||||||
|
* @param stream the stream that will be used for collecting statistics.
|
||||||
|
*/
|
||||||
|
function startLocalRtpStatsCollector(stream)
|
||||||
|
{
|
||||||
|
if(config.enableRtpStats)
|
||||||
|
{
|
||||||
|
localStatsCollector = new LocalStatsCollector(stream, 200, localStatsUpdated);
|
||||||
|
localStatsCollector.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the {@link LocalStatsCollector}.
|
||||||
|
*/
|
||||||
|
function stopLocalRtpStatsCollector()
|
||||||
|
{
|
||||||
|
if(localStatsCollector)
|
||||||
|
{
|
||||||
|
localStatsCollector.stop();
|
||||||
|
localStatsCollector = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(document).bind('callincoming.jingle', function (event, sid) {
|
$(document).bind('callincoming.jingle', function (event, sid) {
|
||||||
var sess = connection.jingle.sessions[sid];
|
var sess = connection.jingle.sessions[sid];
|
||||||
|
@ -965,10 +1009,10 @@ $(window).bind('beforeunload', function () {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
disposeConference();
|
disposeConference(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
function disposeConference() {
|
function disposeConference(onUnload) {
|
||||||
var handler = getConferenceHandler();
|
var handler = getConferenceHandler();
|
||||||
if (handler && handler.peerconnection) {
|
if (handler && handler.peerconnection) {
|
||||||
// FIXME: probably removing streams is not required and close() should be enough
|
// FIXME: probably removing streams is not required and close() should be enough
|
||||||
|
@ -985,6 +1029,13 @@ function disposeConference() {
|
||||||
statsCollector.stop();
|
statsCollector.stop();
|
||||||
statsCollector = null;
|
statsCollector = null;
|
||||||
}
|
}
|
||||||
|
if(!onUnload) {
|
||||||
|
startLocalRtpStatsCollector(connection.jingle.localAudio);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stopLocalRtpStatsCollector();
|
||||||
|
}
|
||||||
focus = null;
|
focus = null;
|
||||||
activecall = null;
|
activecall = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
<script src="moderatemuc.js?v=3"></script><!-- moderator plugin -->
|
<script src="moderatemuc.js?v=3"></script><!-- moderator plugin -->
|
||||||
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
||||||
<script src="rtp_stats.js?v=1"></script><!-- RTP stats processing -->
|
<script src="rtp_stats.js?v=1"></script><!-- RTP stats processing -->
|
||||||
|
<script src="local_stats.js?v=1"></script><!-- Local stats processing -->
|
||||||
<script src="videolayout.js?v=4"></script><!-- video ui -->
|
<script src="videolayout.js?v=4"></script><!-- video ui -->
|
||||||
<script src="toolbar.js?v=2"></script><!-- toolbar ui -->
|
<script src="toolbar.js?v=2"></script><!-- toolbar ui -->
|
||||||
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
|
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/**
|
||||||
|
* Provides statistics for the local stream.
|
||||||
|
*/
|
||||||
|
var LocalStatsCollector = (function() {
|
||||||
|
/**
|
||||||
|
* Size of the webaudio analizer buffer.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
var WEBAUDIO_ANALIZER_FFT_SIZE = 512;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Value of the webaudio analizer smoothing time parameter.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
var WEBAUDIO_ANALIZER_SMOOTING_TIME = 0.1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <tt>LocalStatsCollector</tt> calculates statistics for the local stream.
|
||||||
|
*
|
||||||
|
* @param stream the local stream
|
||||||
|
* @param interval stats refresh interval given in ms.
|
||||||
|
* @param {function(LocalStatsCollector)} updateCallback the callback called on stats
|
||||||
|
* update.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function LocalStatsCollectorProto(stream, interval, updateCallback) {
|
||||||
|
window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||||
|
this.stream = stream;
|
||||||
|
this.intervalId = null;
|
||||||
|
this.intervalMilis = interval;
|
||||||
|
this.updateCallback = updateCallback;
|
||||||
|
this.audioLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the collecting the statistics.
|
||||||
|
*/
|
||||||
|
LocalStatsCollectorProto.prototype.start = function () {
|
||||||
|
if (!window.AudioContext)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var context = new AudioContext();
|
||||||
|
var analyser = context.createAnalyser();
|
||||||
|
analyser.smoothingTimeConstant = WEBAUDIO_ANALIZER_SMOOTING_TIME;
|
||||||
|
analyser.fftSize = WEBAUDIO_ANALIZER_FFT_SIZE;
|
||||||
|
|
||||||
|
|
||||||
|
var source = context.createMediaStreamSource(this.stream);
|
||||||
|
source.connect(analyser);
|
||||||
|
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.intervalId = setInterval(
|
||||||
|
function () {
|
||||||
|
var array = new Uint8Array(analyser.frequencyBinCount);
|
||||||
|
analyser.getByteFrequencyData(array);
|
||||||
|
self.audioLevel = FrequencyDataToAudioLevel(array);
|
||||||
|
self.updateCallback(self);
|
||||||
|
},
|
||||||
|
this.intervalMilis
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops collecting the statistics.
|
||||||
|
*/
|
||||||
|
LocalStatsCollectorProto.prototype.stop = function () {
|
||||||
|
if (this.intervalId) {
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
this.intervalId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts frequency data array to audio level.
|
||||||
|
* @param array the frequency data array.
|
||||||
|
* @returns {number} the audio level
|
||||||
|
*/
|
||||||
|
var FrequencyDataToAudioLevel = function (array) {
|
||||||
|
var maxVolume = 0;
|
||||||
|
|
||||||
|
var length = array.length;
|
||||||
|
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
if (maxVolume < array[i])
|
||||||
|
maxVolume = array[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxVolume / 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LocalStatsCollectorProto;
|
||||||
|
})();
|
Loading…
Reference in New Issue