Skip to content

Instantly share code, notes, and snippets.

@stephband stephband/RT Latency Secret
Last active Apr 10, 2017

Embed
What would you like to do?
Round-trip latency detector
var bufferLength = 16384;
var threshold = 0.125; // -18dB
var gain = audio.createGain();
// input comes from a getUserMedia request
input.connect(gain);
function endTest(outTimes, inTimes) {
if (inTimes.length === 0) {
toolApp.problem = 'No input has been detected. Have you connected an output to an input?';
return;
}
if (outTimes.length < inTimes.length) {
toolApp.problem = inTimes.length + ' signals were detected, but only ' + outTimes.length + ' were sent. Is there a lot of noise in your system? Try and keep background noise below -18dB.';
return;
}
if (outTimes.length > inTimes.length) {
toolApp.problem = 'Only ' + inTimes.length + ' signals were detected, where ' + outTimes.length + ' were sent. Have you got your input gain turned up enough?';
return;
}
console.log(outTimes, inTimes);
var latencyTimes = [];
var n = outTimes.length;
while (n--) {
latencyTimes[n] = inTimes[n] - outTimes[n];
}
var min = Math.min.apply(Math, latencyTimes);
var max = Math.max.apply(Math, latencyTimes);
var range = max - min;
if (range > 128) {
// That's a lot of variance in the resulting times. Looks a bit suspect.
toolApp.problem = 'There\'s a LOT of variance in those results. They could be dodgy. Are you waving a mic around? Keep still! Try running the test again.';
return;
}
console.log(min, max);
var n = latencyTimes.length;
var avg = 0;
while (n--) {
avg += latencyTimes[n] / latencyTimes.length;
}
console.log('Average round-trip latency samples:', avg, 'ms:', avg / toolApp.audio.sampleRate);
toolApp.latency = Math.round(avg);
toolApp.problem = false;
}
function testLatency() {
var node = audio.createScriptProcessor(bufferLength, 1, 1);
var frame = -1;
var inputTimes = [];
var outputTimes = [];
// Keep a reference to the node around to avoid Chrome's garbage
// collection.
window.hfiuxw4i8mwxvhmlu = node;
node.onaudioprocess = function(e){
var inputBuffer = e.inputBuffer;
var outputBuffer = e.outputBuffer;
var inputSamples = inputBuffer.getChannelData(0);
var outputSamples = outputBuffer.getChannelData(0);
var first = false;
++frame;
if (frame > 12) {
// Last frame. End the test...
endTest(outputTimes, inputTimes);
gain.disconnect();
node.disconnect();
}
if (frame % 3 - 1 === 0) {
// Every third frame, give the samples an impulse
outputSamples[0] = 1;
outputSamples[1] = 1;
first = true;
outputTimes.push(bufferLength * frame + bufferLength);
}
else {
// The rest of the time send silence
outputSamples[0] = 0;
outputSamples[1] = 0;
}
var n = -1;
var l = inputSamples.length;
// Detect an impulse. Leave frame 0 out to avoid click noise.
if (frame > 0) {
while (++n < l) {
if (Math.abs(inputSamples[n]) > threshold) {
inputTimes.push(bufferLength * frame + n - bufferLength);
// Dont detect any more than one peak per frame.
return;
}
}
}
}
gain.connect(node);
node.connect(audio.destination);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.