From 04a4920b2cfbcdd2e117fc3d897f133f2d297886 Mon Sep 17 00:00:00 2001 From: James Simpson Date: Fri, 18 Aug 2017 15:38:06 -0500 Subject: [PATCH] Add playerror event for when mobile HTML5 audio is unable to play Fixes #774 --- README.md | 2 ++ src/howler.core.js | 28 +++++++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e597fb6b..6250f43c 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,8 @@ Whether or not to enable the `withCredentials` flag on XHR requests used to fetc Fires when the sound is loaded. #### onloaderror `Function` Fires when the sound is unable to load. The first parameter is the ID of the sound (if it exists) and the second is the error message/code. +#### onplayerror `Function` +Fires when the sound is unable to play. The first parameter is the ID of the sound and the second is the error message/code. #### onplay `Function` Fires when the sound begins playing. The first parameter is the ID of the sound. #### onend `Function` diff --git a/src/howler.core.js b/src/howler.core.js index 7cf30367..bf54616e 100644 --- a/src/howler.core.js +++ b/src/howler.core.js @@ -487,6 +487,7 @@ self._onfade = o.onfade ? [{fn: o.onfade}] : []; self._onload = o.onload ? [{fn: o.onload}] : []; self._onloaderror = o.onloaderror ? [{fn: o.onloaderror}] : []; + self._onplayerror = o.onplayerror ? [{fn: o.onplayerror}] : []; self._onpause = o.onpause ? [{fn: o.onpause}] : []; self._onplay = o.onplay ? [{fn: o.onplay}] : []; self._onstop = o.onstop ? [{fn: o.onstop}] : []; @@ -758,15 +759,28 @@ node.muted = sound._muted || self._muted || Howler._muted || node.muted; node.volume = sound._volume * Howler.volume(); node.playbackRate = sound._rate; - node.play(); - // Setup the new end timer. - if (timeout !== Infinity) { - self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout); - } + // Mobile browsers will throw an error if this is called without user interaction. + try { + node.play(); - if (!internal) { - self._emit('play', sound._id); + // If the node is still paused, then we can assume there was a playback issue. + if (node.paused) { + self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' + + 'on mobile devices where playback was not within a user interaction.'); + return; + } + + // Setup the new end timer. + if (timeout !== Infinity) { + self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout); + } + + if (!internal) { + self._emit('play', sound._id); + } + } catch (err) { + self._emit('playerror', sound._id, err); } };