Adds audio level statistics for the local stream.

This commit is contained in:
hristoterezov 2014-06-26 16:58:43 +02:00
parent ccfa620f46
commit 873cfebe84
3 changed files with 152 additions and 3 deletions

57
app.js
View File

@ -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;
} }

View File

@ -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">

97
local_stats.js Normal file
View File

@ -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;
})();