I'm having difficulties with AudioContext.getOutputTimestamp on Apple devices, which i use for synchronizing animation data to Audio. the difference between Audio Context current time and getOutputTimestamp context time, ie a measure of Audio processing to speaker output latency, which can differ, depending on device.
Since the original getOutputTimestamp introduction, I have not been able to use the output timestamp in Safari, but could use it in Chrome on Apple devices.
However, since upgrading to iOS 15.1 getOutputTimestamp is giving contextTime values that is approx /10,000 smaller than Audio context current time, when they are supposed to be in the same units as audio context currentTime
See the following modification of example from Web Audio examples which illustrates the problems with AudioContext.getOutputTimestamp on Apple devices
getOutputTimestamp() reference
Any help in understanding why I'm seeing such big differences here on Apple devices would be much appreciated.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<title>Output timestamp example</title>
</head>
<body>
<h1>Output timestamp example</h1>
<button class="play">Play</button>
<button class="stop">Stop</button>
<pre></pre>
</body>
<script>
// define variables
let audioCtx;
let source;
let songLength;
let rAF;
const pre = document.querySelector('pre');
const myScript = document.querySelector('script');
const play = document.querySelector('.play');
const stop = document.querySelector('.stop');
// use XHR to load an audio track, and
// decodeAudioData to decode it and stick it in a buffer.
// Then we put the buffer into the source
function getData() {
source = audioCtx.createBufferSource();
fetch('https://mdn.github.io/webaudio-examples/output-timestamp/outfoxing.mp3')
.then(response => response.arrayBuffer())
.then(buffer => {
let audioData = buffer;
audioCtx.decodeAudioData(audioData, function(buffer) {
myBuffer = buffer;
songLength = buffer.duration;
source.buffer = myBuffer;
source.connect(audioCtx.destination);
source.loop = true;
},
function(e) {
"Error with decoding audio data" + e.error
});
})
}
// wire up buttons to stop and play audio, and range slider control
play.addEventListener('click', () => {
if(!audioCtx) {
audioCtx = new window.AudioContext();
}
getData();
source.start(0);
play.setAttribute('disabled', 'disabled');
rAF = requestAnimationFrame(outputTimestamps);
});
stop.addEventListener('click', () => {
source.stop(0);
play.removeAttribute('disabled');
cancelAnimationFrame(rAF);
});
// function to output timestamps
function outputTimestamps() {
let ts = audioCtx.getOutputTimestamp()
console.log('audioCtx.currentTime: ' + audioCtx.currentTime.toFixed(3) ,
'\t Context time: ' +ts.contextTime.toFixed(3),
'\tDifference: ' + (audioCtx.currentTime - ts.contextTime).toFixed(3));
rAF = requestAnimationFrame(outputTimestamps);
}
// dump script to pre element
pre.innerHTML = myScript.innerHTML;
</script>
</html>
Typical MacOS and iOS console outputs, Safari and Chrome
audioCtx.currentTime: 28.865 Context time: 0.001 Difference: 28.865
audioCtx.currentTime: 28.883 Context time: 0.001 Difference: 28.882
Typical expected outputs for desktop and Android Browsers, and iOS Chrome prior the 15.1 Safari upgrade,
audioCtx.currentTime: 28.021 Context time: 27.979 Difference: 0.042
audioCtx.currentTime: 28.040 Context time: 27.999 Difference: 0.041