diff --git a/README.md b/README.md index f1376636..f018d3e3 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,8 @@ Fires when the sound's playback rate has changed. The first parameter is the ID Fires when the sound has been seeked. The first parameter is the ID of the sound. #### onfade `Function` Fires when the current sound finishes fading in/out. The first parameter is the ID of the sound. +#### onunlock `Function` +Fires when audio has been automatically unlocked through a touch/click event. ### Methods @@ -285,19 +287,19 @@ Get the duration of the audio source. Will return 0 until after the `load` event #### on(event, function, [id]) Listen for events. Multiple events can be added by calling this multiple times. -* **event**: `String` Name of event to fire/set (`load`, `loaderror`, `playerror`, `play`, `end`, `pause`, `stop`, `mute`, `volume`, `rate`, `seek`, `fade`). +* **event**: `String` Name of event to fire/set (`load`, `loaderror`, `playerror`, `play`, `end`, `pause`, `stop`, `mute`, `volume`, `rate`, `seek`, `fade`, `unlock`). * **function**: `Function` Define function to fire on event. * **id**: `Number` `optional` Only listen to events for this sound id. #### once(event, function, [id]) Same as `on`, but it removes itself after the callback is fired. -* **event**: `String` Name of event to fire/set (`load`, `loaderror`, `playerror`, `play`, `end`, `pause`, `stop`, `mute`, `volume`, `rate`, `seek`, `fade`). +* **event**: `String` Name of event to fire/set (`load`, `loaderror`, `playerror`, `play`, `end`, `pause`, `stop`, `mute`, `volume`, `rate`, `seek`, `fade`, `unlock`). * **function**: `Function` Define function to fire on event. * **id**: `Number` `optional` Only listen to events for this sound id. #### off(event, [function], [id]) Remove event listener that you've set. Call without parameters to remove all events. -* **event**: `String` Name of event (`load`, `loaderror`, `playerror`, `play`, `end`, `pause`, `stop`, `mute`, `volume`, `rate`, `seek`, `fade`). +* **event**: `String` Name of event (`load`, `loaderror`, `playerror`, `play`, `end`, `pause`, `stop`, `mute`, `volume`, `rate`, `seek`, `fade`, `unlock`). * **function**: `Function` `optional` The listener to remove. Omit this to remove all events of type. * **id**: `Number` `optional` Only remove events for this sound id. @@ -415,13 +417,29 @@ Get/set the direction the listener is pointing in the 3D cartesian space. A fron * **zUp**: `Number` The z-orientation of the top of the listener. -### Mobile Playback -By default, audio on iOS, Android, etc is locked until a sound is played within a user interaction, and then it plays normally the rest of the page session ([Apple documentation](https://developer.apple.com/library/safari/documentation/audiovideo/conceptual/using_html5_audio_video/PlayingandSynthesizingSounds/PlayingandSynthesizingSounds.html)). The default behavior of howler.js is to attempt to silently unlock audio playback by playing an empty buffer on the first `touchend` event. This behavior can be disabled by calling: +### Mobile/Chrome Playback +By default, audio on mobile browsers and Chrome is locked until a sound is played within a user interaction, and then it plays normally the rest of the page session ([Apple documentation](https://developer.apple.com/library/safari/documentation/audiovideo/conceptual/using_html5_audio_video/PlayingandSynthesizingSounds/PlayingandSynthesizingSounds.html)). The default behavior of howler.js is to attempt to silently unlock audio playback by playing an empty buffer on the first `touchend` event. This behavior can be disabled by calling: ```javascript Howler.mobileAutoEnable = false; ``` +If you try to play audio automatically on page load, you can listen to a `playerror` event and then wait for the `unlock` event to try and play the audio again: + +```javascript +var sound = new Howl({ + src: ['sound.webm', 'sound.mp3'], + onplayerror: function() { + sound.once('unlock', function() { + sound.play(); + }); + } +}); + +sound.play(); +``` + + ### Dolby Audio Playback Full support for playback of the Dolby Audio format (currently support in Edge and Safari) is included. However, you must specify that the file you are loading is `dolby` since it is in a `mp4` container. diff --git a/src/howler.core.js b/src/howler.core.js index 35371046..25edb7a6 100644 --- a/src/howler.core.js +++ b/src/howler.core.js @@ -279,13 +279,13 @@ var self = this || Howler; // Only run this on mobile devices if audio isn't already eanbled. - var isMobile = /iPhone|iPad|iPod|Android|BlackBerry|BB10|Silk|Mobi/i.test(self._navigator && self._navigator.userAgent); - var isTouch = !!(('ontouchend' in window) || (self._navigator && self._navigator.maxTouchPoints > 0) || (self._navigator && self._navigator.msMaxTouchPoints > 0)); - if (self._mobileEnabled || !self.ctx || (!isMobile && !isTouch)) { + var isMobile = /iPhone|iPad|iPod|Android|BlackBerry|BB10|Silk|Mobi|Chrome/i.test(self._navigator && self._navigator.userAgent); + if (self._mobileEnabled || !self.ctx || !isMobile) { return; } self._mobileEnabled = false; + self.mobileAutoEnable = false; // Some mobile devices/platforms have distortion issues when opening/closing tabs and/or web views. // Bugs in the browser (especially Mobile Safari) can cause the sampleRate to change from 44100 to 48000. @@ -302,7 +302,9 @@ // Call this method on touch start to create and play a buffer, // then check if the audio actually played to determine if // audio has now been unlocked on iOS, Android, etc. - var unlock = function() { + var unlock = function(e) { + e.preventDefault(); + // Fix Android can not play in suspend state. Howler._autoResume(); @@ -329,17 +331,23 @@ // Update the unlocked state and prevent this check from happening again. self._mobileEnabled = true; - self.mobileAutoEnable = false; // Remove the touch start listener. document.removeEventListener('touchstart', unlock, true); document.removeEventListener('touchend', unlock, true); + document.removeEventListener('click', unlock, true); + + // Let all sounds know that audio has been unlocked. + for (var i=0; i