onended() does not fire in Safari or on iOS

Viewed 612

The following code works on Chrome 80.0 and Firefox 74.0 (OSX 10.14.6). However, on OSX Safari 13.0.5 or on iOS (testing in Chrome, Safari), the <div> element never turns blue, indicating that the onended callback does not fire. Is this a bug?

const ctx = new (window.AudioContext || window.webkitAudioContext)();

const buff = ctx.createBuffer(1, 32, ctx.sampleRate);
const buffSource = ctx.createBufferSource();
buffSource.buffer = buff;
buffSource.loop = false;

// attempt to add an event listener to the buffer source
buffSource.addEventListener('ended', () => {
    document.getElementById('test').style.backgroundColor = 'blue';    
});

// another slight variation using the named function
function changeBackground() {
    document.getElementById('test').style.backgroundColor = 'blue';    
}
buffSource.addEventListener('ended', changeBackground);

// the documentation suggestion modifying the function directly
buffSource.onended = function(){
    document.getElementById('test').style.backgroundColor = 'blue';
};

// maybe binding would help?
buffSource.onended = function(){
    document.getElementById('test').style.backgroundColor = 'blue';
}.bind(this);

document.getElementById('button').onclick = (e) => {
    ctx.resume();
    buffSource.start();
    document.getElementById('message').innerText = "Pressed Button";
};
#test {
    background-color: red;
    width: 500px;
    height: 500px;
}
#button {
    cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
<body>
  <button id = 'button'>Click me</button>
  <div id = 'test'></div>
  <div id = 'message'></div>
</body>
</html>

1 Answers

Safari doesn't fire the ended event if the AudioBufferSourceNode is not connected.

buffSource.connect(ctx.destination);

Executing this line before calling start() should make it work.

Related