Skip to content

Commit 0629f9e

Browse files
authored
Merge pull request #658 from golddranks/master
Fixed an edge case with Safari ("infinite" html5 audio -> the end event won't run)
2 parents 289bcda + 2e5c752 commit 0629f9e

File tree

1 file changed

+32
-0
lines changed

1 file changed

+32
-0
lines changed

src/howler.core.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,7 @@
17461746
// Remove any event listeners.
17471747
sounds[i]._node.removeEventListener('error', sounds[i]._errorFn, false);
17481748
sounds[i]._node.removeEventListener(Howler._canPlayEvent, sounds[i]._loadFn, false);
1749+
sounds[i]._node.removeEventListener('ended', sounds[i]._endFn, false);
17491750

17501751
// Release the Audio object back to the pool.
17511752
Howler._releaseHtml5Audio(sounds[i]._node);
@@ -2242,6 +2243,11 @@
22422243
self._loadFn = self._loadListener.bind(self);
22432244
self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false);
22442245

2246+
// Listen for the 'ended' event on the sound to account for edge-case where
2247+
// a finite sound has a duration of Infinity.
2248+
self._endFn = self._endListener.bind(self);
2249+
self._node.addEventListener('ended', self._endFn, false);
2250+
22452251
// Setup the new audio node.
22462252
self._node.src = parent._src;
22472253
self._node.preload = parent._preload === true ? 'auto' : parent._preload;
@@ -2315,6 +2321,32 @@
23152321

23162322
// Clear the event listener.
23172323
self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false);
2324+
},
2325+
2326+
/**
2327+
* HTML5 Audio ended listener callback.
2328+
*/
2329+
_endListener: function() {
2330+
var self = this;
2331+
var parent = self._parent;
2332+
2333+
// Only handle the `ended`` event if the duration is Infinity.
2334+
if (parent._duration === Infinity) {
2335+
// Update the parent duration to match the real audio duration.
2336+
// Round up the duration to account for the lower precision in HTML5 Audio.
2337+
parent._duration = Math.ceil(self._node.duration * 10) / 10;
2338+
2339+
// Update the sprite that corresponds to the real duration.
2340+
if (parent._sprite.__default[1] === Infinity) {
2341+
parent._sprite.__default[1] = parent._duration * 1000;
2342+
}
2343+
2344+
// Run the regular ended method.
2345+
parent._ended(self);
2346+
}
2347+
2348+
// Clear the event listener since the duration is now correct.
2349+
self._node.removeEventListener('ended', self._endFn, false);
23182350
}
23192351
};
23202352

0 commit comments

Comments
 (0)