127.0.0.1:8000 watch-together / master src / js / utils / time.js
master

Tree @master (Download .tar.gz)

time.js @masterraw · history · blame

const $ = require('jquery');
const utils = require('.');

const MAX_OFFSET_SAMPLES = 20;
const MAX_LATENCY_SAMPLES = 7;
let latencys = [];
let average_latency = 0;
let offsets = [];
let average_offset = 0;

module.exports = {
    offsets: {
        push: function(offset, latency) {
            offsets.push(offset + latency);
            if (offsets.length > MAX_OFFSET_SAMPLES) {
                offsets.shift();
            }
            average_offset = normalize([...offsets]);

            latencys.push(latency);
            if (latencys.length > MAX_LATENCY_SAMPLES) {
                latencys.shift();
            }
            average_latency = normalize([...latencys]);

            // logger.log("Filtered offsets:", clonedOffsets);
            // logger.log("Final offset:", averageOffset);
            $("#clock-drift").text(utils.round(average_offset));
        }
    },
    server_time: function() {
        return Date.now() + average_offset;
    },
    latency: function() {
        return average_latency;
    }
};

function normalize(list) {
    let med = median(list);
    let std = standardDeviation(list);
    for (let i = 0; i < list.length; i++) {
        let val = list[i];
        if (Math.abs(val - med) > std) {
            list.splice(i--, 1);
        }
    }
    return average(list);
}

function median(arr) {
    const mid = Math.floor(arr.length / 2);
    const nums = [...arr].sort((a, b) => a - b);
    return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
}

function average(data) {
    return data.reduce((sum, value) => sum + value) / data.length;
}

function standardDeviation(values) {
    return Math.sqrt(average(values.map(value => (value - average(values)) ** 2)));
}