Skip to content

Commit

Permalink
work around suspended audio streams on iOS Safari 17.4 goldfire#1711
Browse files Browse the repository at this point in the history
  • Loading branch information
bikubi committed Mar 11, 2024
1 parent 003b917 commit 8bb0610
Showing 1 changed file with 23 additions and 1 deletion.
24 changes: 23 additions & 1 deletion src/howler.core.js
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,12 @@
};
node.addEventListener(Howler._canPlayEvent, listener, false);

// the node is not actually playing (has received suspend event & NETWORK_IDLE)
if (node.networkState === 1 && node._wasSuspended) {
console.log('wake up suspended audio node')
node.play()
}

// Cancel the end timer.
self._clearTimer(sound._id);
}
Expand Down Expand Up @@ -1763,6 +1769,8 @@
// Remove any event listeners.
sounds[i]._node.removeEventListener('error', sounds[i]._errorFn, false);
sounds[i]._node.removeEventListener(Howler._canPlayEvent, sounds[i]._loadFn, false);
sounds[i]._node.removeEventListener('loadedmetadata', sounds[i]._loadFn, false);
sounds[i]._node.removeEventListener('suspend', setAudioNodeWasSuspendedFromEvent, false);
sounds[i]._node.removeEventListener('ended', sounds[i]._endFn, false);

// Release the Audio object back to the pool.
Expand Down Expand Up @@ -2264,6 +2272,11 @@
self._loadFn = self._loadListener.bind(self);
self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false);

// sometimes canplaythrough does not fire if the audio node is suspended (see below)
// so we make extra sure to kick off the event queue here
// TODO: this could have side effects beyond the _wasSuspended mitigation...
self._node.addEventListener('loadedmetadata', self._loadFn, false);

// Listen for the 'ended' event on the sound to account for edge-case where
// a finite sound has a duration of Infinity.
self._endFn = self._endListener.bind(self);
Expand All @@ -2274,6 +2287,10 @@
self._node.preload = parent._preload === true ? 'auto' : parent._preload;
self._node.volume = volume * Howler.volume();

// we record the suspend event with a dirty param in case we need to mitigate it later
self._node._wasSuspended = false
self._node.addEventListener('suspend', setAudioNodeWasSuspendedFromEvent, false)

// Begin loading the source.
self._node.load();
}
Expand Down Expand Up @@ -2340,8 +2357,9 @@
parent._loadQueue();
}

// Clear the event listener.
// Clear the event listeners
self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false);
self._node.removeEventListener('loadedmetadata', self._loadFn, false);
},

/**
Expand Down Expand Up @@ -2506,6 +2524,10 @@
}
};

var setAudioNodeWasSuspendedFromEvent = function(evt) {
evt.target._wasSuspended = true
}

/**
* Setup the audio context when available, or switch to HTML5 Audio mode.
*/
Expand Down

0 comments on commit 8bb0610

Please sign in to comment.