| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 | /* global APP, interfaceConfig, $ */
/* jshint -W101 */
import CanvasUtil from './CanvasUtils';
import FilmStrip from '../videolayout/FilmStrip';
const LOCAL_LEVEL = 'local';
let ASDrawContext = null;
let audioLevelCanvasCache = {};
let dominantSpeakerAudioElement = null;
function initDominantSpeakerAudioLevels(dominantSpeakerAvatarSize) {
    let ASRadius = dominantSpeakerAvatarSize / 2;
    let ASCenter = (dominantSpeakerAvatarSize + ASRadius) / 2;
    // Draw a circle.
    ASDrawContext.beginPath();
    ASDrawContext.arc(ASCenter, ASCenter, ASRadius, 0, 2 * Math.PI);
    ASDrawContext.closePath();
    // Add a shadow around the circle
    ASDrawContext.shadowColor = interfaceConfig.SHADOW_COLOR;
    ASDrawContext.shadowOffsetX = 0;
    ASDrawContext.shadowOffsetY = 0;
}
/**
 * Resizes the given audio level canvas to match the given thumbnail size.
 */
function resizeAudioLevelCanvas(audioLevelCanvas, thumbnailWidth, thumbnailHeight) {
    audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA;
    audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA;
}
/**
 * Draws the audio level canvas into the cached canvas object.
 *
 * @param id of the user for whom we draw the audio level
 * @param audioLevel the newAudio level to render
 */
function drawAudioLevelCanvas(id, audioLevel) {
    if (!audioLevelCanvasCache[id]) {
        let videoSpanId = getVideoSpanId(id);
        let audioLevelCanvasOrig = $(`#${videoSpanId}>canvas`).get(0);
        /*
         * FIXME Testing has shown that audioLevelCanvasOrig may not exist.
         * In such a case, the method CanvasUtil.cloneCanvas may throw an
         * error. Since audio levels are frequently updated, the errors have
         * been observed to pile into the console, strain the CPU.
         */
        if (audioLevelCanvasOrig) {
            audioLevelCanvasCache[id]
                = CanvasUtil.cloneCanvas(audioLevelCanvasOrig);
        }
    }
    let canvas = audioLevelCanvasCache[id];
    if (!canvas) {
        return;
    }
    let drawContext = canvas.getContext('2d');
    drawContext.clearRect(0, 0, canvas.width, canvas.height);
    let shadowLevel = getShadowLevel(audioLevel);
    if (shadowLevel > 0) {
        // drawContext, x, y, w, h, r, shadowColor, shadowLevel
        CanvasUtil.drawRoundRectGlow(
            drawContext,
            interfaceConfig.CANVAS_EXTRA / 2, interfaceConfig.CANVAS_EXTRA / 2,
            canvas.width - interfaceConfig.CANVAS_EXTRA,
            canvas.height - interfaceConfig.CANVAS_EXTRA,
            interfaceConfig.CANVAS_RADIUS,
            interfaceConfig.SHADOW_COLOR,
            shadowLevel);
    }
}
/**
 * Returns the shadow/glow level for the given audio level.
 *
 * @param audioLevel the audio level from which we determine the shadow
 * level
 */
function getShadowLevel (audioLevel) {
    let shadowLevel = 0;
    if (audioLevel <= 0.3) {
        shadowLevel = Math.round(
            interfaceConfig.CANVAS_EXTRA/2*(audioLevel/0.3));
    } else if (audioLevel <= 0.6) {
        shadowLevel = Math.round(
            interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.3) / 0.3));
    } else {
        shadowLevel = Math.round(
            interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.6) / 0.4));
    }
    return shadowLevel;
}
/**
 * Returns the video span id corresponding to the given user id
 */
function getVideoSpanId(id) {
    let videoSpanId = null;
    if (id === LOCAL_LEVEL || APP.conference.isLocalId(id)) {
        videoSpanId = 'localVideoContainer';
    } else {
        videoSpanId = `participant_${id}`;
    }
    return videoSpanId;
}
/**
 * The audio Levels plugin.
 */
const AudioLevels = {
    init () {
        dominantSpeakerAudioElement =  $('#dominantSpeakerAudioLevel')[0];
        ASDrawContext = dominantSpeakerAudioElement.getContext('2d');
        let parentContainer = $("#dominantSpeaker");
        let dominantSpeakerWidth = parentContainer.width();
        let dominantSpeakerHeight = parentContainer.height();
        dominantSpeakerAudioElement.width = dominantSpeakerWidth;
        dominantSpeakerAudioElement.height = dominantSpeakerHeight;
        let dominantSpeakerAvatar = $("#dominantSpeakerAvatar");
        initDominantSpeakerAudioLevels(dominantSpeakerAvatar.width());
    },
    /**
     * Updates the audio level canvas for the given id. If the canvas
     * didn't exist we create it.
     */
    updateAudioLevelCanvas (id, thumbWidth, thumbHeight) {
        let videoSpanId = 'localVideoContainer';
        if (id) {
            videoSpanId = `participant_${id}`;
        }
        let videoSpan = document.getElementById(videoSpanId);
        if (!videoSpan) {
            if (id) {
                console.error("No video element for id", id);
            } else {
                console.error("No video element for local video.");
            }
            return;
        }
        let audioLevelCanvas = $(`#${videoSpanId}>canvas`);
        if (!audioLevelCanvas || audioLevelCanvas.length === 0) {
            audioLevelCanvas = document.createElement('canvas');
            audioLevelCanvas.className = "audiolevel";
            audioLevelCanvas.style.bottom
                = `-${interfaceConfig.CANVAS_EXTRA/2}px`;
            audioLevelCanvas.style.left
                = `-${interfaceConfig.CANVAS_EXTRA/2}px`;
            resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
            videoSpan.appendChild(audioLevelCanvas);
        } else {
            audioLevelCanvas = audioLevelCanvas.get(0);
            resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
        }
    },
    /**
     * Updates the audio level UI for the given id.
     *
     * @param id id of the user for whom we draw the audio level
     * @param audioLevel the newAudio level to render
     */
    updateAudioLevel (id, audioLevel, largeVideoId) {
        drawAudioLevelCanvas(id, audioLevel);
        let videoSpanId = getVideoSpanId(id);
        let audioLevelCanvas = $(`#${videoSpanId}>canvas`).get(0);
        if (!audioLevelCanvas) {
            return;
        }
        let drawContext = audioLevelCanvas.getContext('2d');
        let canvasCache = audioLevelCanvasCache[id];
        drawContext.clearRect(
            0, 0, audioLevelCanvas.width, audioLevelCanvas.height
        );
        drawContext.drawImage(canvasCache, 0, 0);
        if (id === LOCAL_LEVEL) {
            id = APP.conference.localId;
            if (!id) {
                return;
            }
        }
        if(id === largeVideoId) {
            window.requestAnimationFrame(function () {
                AudioLevels.updateDominantSpeakerAudioLevel(audioLevel);
            });
        }
    },
    updateDominantSpeakerAudioLevel (audioLevel) {
        if($("#dominantSpeaker").css("visibility") == "hidden"
            || ASDrawContext === null) {
            return;
        }
        ASDrawContext.clearRect(0, 0,
            dominantSpeakerAudioElement.width,
            dominantSpeakerAudioElement.height);
        if (!audioLevel) {
            return;
        }
        ASDrawContext.shadowBlur = getShadowLevel(audioLevel);
        // Fill the shape.
        ASDrawContext.fill();
    },
    updateCanvasSize (thumbWidth, thumbHeight) {
        let canvasWidth = thumbWidth + interfaceConfig.CANVAS_EXTRA;
        let canvasHeight = thumbHeight + interfaceConfig.CANVAS_EXTRA;
        FilmStrip.getThumbs().children('canvas').each(function () {
            $(this).attr('width', canvasWidth);
            $(this).attr('height', canvasHeight);
        });
        Object.keys(audioLevelCanvasCache).forEach(function (id) {
            audioLevelCanvasCache[id].width = canvasWidth;
            audioLevelCanvasCache[id].height = canvasHeight;
        });
    }
};
export default AudioLevels;
 |