-
-
Save stephband/f032a69c54f3a5d0ebf9 to your computer and use it in GitHub Desktop.
Round-trip latency detector
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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