| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 | /* global config, AudioContext */
/**
 * Provides statistics for the local stream.
 */
var RTCBrowserType = require('../RTC/RTCBrowserType');
var StatisticsEvents = require('../../service/statistics/Events');
/**
 * Size of the webaudio analyzer buffer.
 * @type {number}
 */
var WEBAUDIO_ANALYZER_FFT_SIZE = 2048;
/**
 * Value of the webaudio analyzer smoothing time parameter.
 * @type {number}
 */
var WEBAUDIO_ANALYZER_SMOOTING_TIME = 0.8;
/**
 * Converts time domain data array to audio level.
 * @param samples the time domain data array.
 * @returns {number} the audio level
 */
function timeDomainDataToAudioLevel(samples) {
    var maxVolume = 0;
    var length = samples.length;
    for (var i = 0; i < length; i++) {
        if (maxVolume < samples[i])
            maxVolume = samples[i];
    }
    return parseFloat(((maxVolume - 127) / 128).toFixed(3));
}
/**
 * Animates audio level change
 * @param newLevel the new audio level
 * @param lastLevel the last audio level
 * @returns {Number} the audio level to be set
 */
function animateLevel(newLevel, lastLevel) {
    var value = 0;
    var diff = lastLevel - newLevel;
    if(diff > 0.2) {
        value = lastLevel - 0.2;
    }
    else if(diff < -0.4) {
        value = lastLevel + 0.4;
    }
    else {
        value = newLevel;
    }
    return parseFloat(value.toFixed(3));
}
/**
 * <tt>LocalStatsCollector</tt> calculates statistics for the local stream.
 *
 * @param stream the local stream
 * @param interval stats refresh interval given in ms.
 * @constructor
 */
function LocalStatsCollector(stream, interval,
                             statisticsService, eventEmitter) {
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    this.stream = stream;
    this.intervalId = null;
    this.intervalMilis = interval;
    this.eventEmitter = eventEmitter;
    this.audioLevel = 0;
    this.statisticsService = statisticsService;
}
/**
 * Starts the collecting the statistics.
 */
LocalStatsCollector.prototype.start = function () {
    if (config.disableAudioLevels || !window.AudioContext ||
        RTCBrowserType.isTemasysPluginUsed())
        return;
    var context = new AudioContext();
    var analyser = context.createAnalyser();
    analyser.smoothingTimeConstant = WEBAUDIO_ANALYZER_SMOOTING_TIME;
    analyser.fftSize = WEBAUDIO_ANALYZER_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.getByteTimeDomainData(array);
            var audioLevel = timeDomainDataToAudioLevel(array);
            if (audioLevel != self.audioLevel) {
                self.audioLevel = animateLevel(audioLevel, self.audioLevel);
                self.eventEmitter.emit(
                    StatisticsEvents.AUDIO_LEVEL,
                    self.statisticsService.LOCAL_JID,
                    self.audioLevel);
            }
        },
        this.intervalMilis
    );
};
/**
 * Stops collecting the statistics.
 */
LocalStatsCollector.prototype.stop = function () {
    if (this.intervalId) {
        clearInterval(this.intervalId);
        this.intervalId = null;
    }
};
module.exports = LocalStatsCollector;
 |