diff --git a/README.md b/README.md index 4a4766f0..2bb6c3b5 100644 --- a/README.md +++ b/README.md @@ -378,9 +378,11 @@ Automatically attempts to enable audio on mobile (iOS, Android, etc) devices and Each HTML5 Audio object must be unlocked individually, so we keep a global pool of unlocked nodes to share between all `Howl` instances. This pool gets created on the first user interaction and is set to the size of this property. #### autoSuspend `Boolean` `true` Automatically suspends the Web Audio AudioContext after 30 seconds of inactivity to decrease processing and energy usage. Automatically resumes upon new playback. Set this property to `false` to disable this behavior. -#### ctx `Boolean` *`Web Audio Only`* +#### eagerPlayback `Boolean` `false` +When enabled, allows playback to begin before the browser has estimated that enough data has loaded in order to play the sound to its end, without having to stop and buffer for more content. +#### ctx `AudioContext` `null` *`Web Audio Only`* Exposes the `AudioContext` with Web Audio API. -#### masterGain `Boolean` *`Web Audio Only`* +#### masterGain `GainNode` `null` *`Web Audio Only`* Exposes the master `GainNode` with Web Audio API. This can be useful for writing plugins or advanced usage. diff --git a/src/howler.core.js b/src/howler.core.js index aa60cdbe..442a39ca 100644 --- a/src/howler.core.js +++ b/src/howler.core.js @@ -51,6 +51,7 @@ self.usingWebAudio = true; self.autoSuspend = true; self.ctx = null; + self.eagerPlayback = false; // Set to false to disable the auto audio unlocker. self.autoUnlock = true; @@ -63,8 +64,8 @@ /** * Get/set the global volume for all sounds. - * @param {Float} vol Volume from 0.0 to 1.0. - * @return {Howler/Float} Returns self or current volume. + * @param {float} vol Volume from 0.0 to 1.0. + * @return {Howler/float} Returns self or current volume. */ volume: function(vol) { var self = this || Howler; @@ -539,6 +540,22 @@ self._resumeAfterSuspend = true; } + return self; + }, + + /** + * Use `canplay` event for determining when playback can begin. In contrast with the `canplaythrough` event, + * `canplay` is fired when enough data has been loaded to begin playing the media, but not necessarily enough to + * play without stopping and buffering additional data. + * @return {Howler} + */ + _enableEagerPlayback: function() { + var self = this; + + if (self._canPlayEvent === 'canplaythrough') { + self._canPlayEvent = 'canplay'; + } + return self; } }; @@ -623,6 +640,10 @@ // Web Audio or HTML5 Audio? self._webAudio = Howler.usingWebAudio && !self._html5; + if (Howler.eagerPlayback) { + Howler._enableEagerPlayback(); + } + // Automatically try to enable audio. if (typeof Howler.ctx !== 'undefined' && Howler.ctx && Howler.autoUnlock) { Howler._unlockAudio(); @@ -897,7 +918,11 @@ } else { // Fire this when the sound is ready to play to begin HTML5 Audio playback. var playHtml5 = function() { - node.currentTime = seek; + // When `eagerPlayback` is enabled, setting `currentTime` to the same value prevents the + // play promise from ever resolving in Chromium-based browsers. + if (node.currentTime !== seek) { + node.currentTime = seek; + } node.muted = sound._muted || self._muted || Howler._muted || node.muted; node.volume = sound._volume * Howler.volume(); node.playbackRate = sound._rate; @@ -974,7 +999,7 @@ node.load(); } - // Play immediately if ready, or wait for the 'canplaythrough'e vent. + // Play immediately if ready, or wait for the '_canPlayEvent' event. var loadedNoReadyState = (window && window.ejecta) || (!node.readyState && Howler._navigator.isCocoonJS); if (node.readyState >= 3 || loadedNoReadyState) { playHtml5(); @@ -984,7 +1009,7 @@ var listener = function() { self._state = 'loaded'; - + // Begin playback. playHtml5(); @@ -2260,7 +2285,7 @@ self._errorFn = self._errorListener.bind(self); self._node.addEventListener('error', self._errorFn, false); - // Listen for 'canplaythrough' event to let us know the sound is ready. + // Listen for '_canPlayEvent' event to let us know the sound is ready. self._loadFn = self._loadListener.bind(self); self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false); diff --git a/tests/core.html5audio.html b/tests/core.html5audio.html index ecf3ae67..bc444ad3 100644 --- a/tests/core.html5audio.html +++ b/tests/core.html5audio.html @@ -12,6 +12,7 @@
+