Skip to content

Commit c791f2e

Browse files
bikubiidserda
authored andcommitted
work around suspended audio streams on iOS Safari 17.4 goldfire#1711
1 parent 003b917 commit c791f2e

File tree

1 file changed

+23
-1
lines changed

1 file changed

+23
-1
lines changed

src/howler.core.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,12 @@
993993
};
994994
node.addEventListener(Howler._canPlayEvent, listener, false);
995995

996+
// the node is not actually playing (has received suspend event & NETWORK_IDLE)
997+
if (node.networkState === 1 && node._wasSuspended) {
998+
console.log('wake up suspended audio node')
999+
node.play()
1000+
}
1001+
9961002
// Cancel the end timer.
9971003
self._clearTimer(sound._id);
9981004
}
@@ -1763,6 +1769,8 @@
17631769
// Remove any event listeners.
17641770
sounds[i]._node.removeEventListener('error', sounds[i]._errorFn, false);
17651771
sounds[i]._node.removeEventListener(Howler._canPlayEvent, sounds[i]._loadFn, false);
1772+
sounds[i]._node.removeEventListener('loadedmetadata', sounds[i]._loadFn, false);
1773+
sounds[i]._node.removeEventListener('suspend', setAudioNodeWasSuspendedFromEvent, false);
17661774
sounds[i]._node.removeEventListener('ended', sounds[i]._endFn, false);
17671775

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

2275+
// sometimes canplaythrough does not fire if the audio node is suspended (see below)
2276+
// so we make extra sure to kick off the event queue here
2277+
// TODO: this could have side effects beyond the _wasSuspended mitigation...
2278+
self._node.addEventListener('loadedmetadata', self._loadFn, false);
2279+
22672280
// Listen for the 'ended' event on the sound to account for edge-case where
22682281
// a finite sound has a duration of Infinity.
22692282
self._endFn = self._endListener.bind(self);
@@ -2274,6 +2287,10 @@
22742287
self._node.preload = parent._preload === true ? 'auto' : parent._preload;
22752288
self._node.volume = volume * Howler.volume();
22762289

2290+
// we record the suspend event with a dirty param in case we need to mitigate it later
2291+
self._node._wasSuspended = false
2292+
self._node.addEventListener('suspend', setAudioNodeWasSuspendedFromEvent, false)
2293+
22772294
// Begin loading the source.
22782295
self._node.load();
22792296
}
@@ -2340,8 +2357,9 @@
23402357
parent._loadQueue();
23412358
}
23422359

2343-
// Clear the event listener.
2360+
// Clear the event listeners
23442361
self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false);
2362+
self._node.removeEventListener('loadedmetadata', self._loadFn, false);
23452363
},
23462364

23472365
/**
@@ -2506,6 +2524,10 @@
25062524
}
25072525
};
25082526

2527+
var setAudioNodeWasSuspendedFromEvent = function(evt) {
2528+
evt.target._wasSuspended = true
2529+
}
2530+
25092531
/**
25102532
* Setup the audio context when available, or switch to HTML5 Audio mode.
25112533
*/

0 commit comments

Comments
 (0)