Skip to content

Commit b8591f0

Browse files
committedJul 12, 2018
v2.0.14
1 parent 9a9f50f commit b8591f0

8 files changed

+99
-48
lines changed
 

‎CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 2.0.14 (July 12, 2018)
2+
- `CHANGED` Auto unlocking of audio now runs on Chrome to fix issue with HTML5 Audio needing user interaction.
3+
- `CHANGED` Added a new `unlock` event that is fired when the auto unlock happens.
4+
- `CHANGED` A `playerror` now gets fired when HTML5 Audio fails to play due to lack of user interaction.
5+
- `FIXED` Improved HTML5 Audio play lock checks to prevent race conditions ([#995](https://github.com/goldfire/howler.js/pull/995)).
6+
- `FIXED` Intermittent error in Chrome when decoding audio data ([#988](https://github.com/goldfire/howler.js/pull/988)).
7+
- `FIXED` Error when trying to loop spatial audio without a sprite ([#985](https://github.com/goldfire/howler.js/issues/985)).
8+
- `FIXED` Instantly fire the `end` event when a sound is seeked past its duration ([#963](https://github.com/goldfire/howler.js/issues/963)).
9+
- `FIXED` Another issue in Safari where spatial orientation was throwing an error.
10+
111
## 2.0.13 (Juen 22, 2018)
212
- `FIXED` Prevent `stop` event from firing alongside `end` when using HTML5 Audio ([#974](https://github.com/goldfire/howler.js/issues/074)).
313
- `FIXED` Correctly reset a `Sound` after using spatial audio ([#962](https://github.com/goldfire/howler.js/issues/962)).

‎dist/howler.core.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/howler.js

+79-38
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* howler.js v2.0.13
2+
* howler.js v2.0.14
33
* howlerjs.com
44
*
55
* (c) 2013-2018, James Simpson of GoldFire Studios
@@ -279,13 +279,13 @@
279279
var self = this || Howler;
280280

281281
// Only run this on mobile devices if audio isn't already eanbled.
282-
var isMobile = /iPhone|iPad|iPod|Android|BlackBerry|BB10|Silk|Mobi/i.test(self._navigator && self._navigator.userAgent);
283-
var isTouch = !!(('ontouchend' in window) || (self._navigator && self._navigator.maxTouchPoints > 0) || (self._navigator && self._navigator.msMaxTouchPoints > 0));
284-
if (self._mobileEnabled || !self.ctx || (!isMobile && !isTouch)) {
282+
var isMobile = /iPhone|iPad|iPod|Android|BlackBerry|BB10|Silk|Mobi|Chrome/i.test(self._navigator && self._navigator.userAgent);
283+
if (self._mobileEnabled || !self.ctx || !isMobile) {
285284
return;
286285
}
287286

288287
self._mobileEnabled = false;
288+
self.mobileAutoEnable = false;
289289

290290
// Some mobile devices/platforms have distortion issues when opening/closing tabs and/or web views.
291291
// Bugs in the browser (especially Mobile Safari) can cause the sampleRate to change from 44100 to 48000.
@@ -302,7 +302,9 @@
302302
// Call this method on touch start to create and play a buffer,
303303
// then check if the audio actually played to determine if
304304
// audio has now been unlocked on iOS, Android, etc.
305-
var unlock = function() {
305+
var unlock = function(e) {
306+
e.preventDefault();
307+
306308
// Fix Android can not play in suspend state.
307309
Howler._autoResume();
308310

@@ -329,17 +331,23 @@
329331

330332
// Update the unlocked state and prevent this check from happening again.
331333
self._mobileEnabled = true;
332-
self.mobileAutoEnable = false;
333334

334335
// Remove the touch start listener.
335336
document.removeEventListener('touchstart', unlock, true);
336337
document.removeEventListener('touchend', unlock, true);
338+
document.removeEventListener('click', unlock, true);
339+
340+
// Let all sounds know that audio has been unlocked.
341+
for (var i=0; i<self._howls.length; i++) {
342+
self._howls[i]._emit('unlock');
343+
}
337344
};
338345
};
339346

340347
// Setup a touch start listener to attempt an unlock in.
341348
document.addEventListener('touchstart', unlock, true);
342349
document.addEventListener('touchend', unlock, true);
350+
document.addEventListener('click', unlock, true);
343351

344352
return self;
345353
},
@@ -498,6 +506,7 @@
498506
self._onvolume = o.onvolume ? [{fn: o.onvolume}] : [];
499507
self._onrate = o.onrate ? [{fn: o.onrate}] : [];
500508
self._onseek = o.onseek ? [{fn: o.onseek}] : [];
509+
self._onunlock = o.onunlock ? [{fn: o.onunlock}] : [];
501510
self._onresume = [];
502511

503512
// Web Audio or HTML5 Audio?
@@ -714,6 +723,12 @@
714723
sound._stop = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000;
715724
sound._loop = !!(sound._loop || self._sprite[sprite][2]);
716725

726+
// End the sound instantly if seek is at the end.
727+
if (sound._seek >= sound._stop) {
728+
self._ended(sound);
729+
return;
730+
}
731+
717732
// Begin the actual playback.
718733
var node = sound._node;
719734
if (self._webAudio) {
@@ -766,18 +781,23 @@
766781
var play = node.play();
767782

768783
// Support older browsers that don't support promises, and thus don't have this issue.
769-
if (typeof Promise !== 'undefined' && play instanceof Promise) {
784+
if (typeof Promise !== 'undefined' && (play instanceof Promise || typeof play.then === 'function')) {
770785
// Implements a lock to prevent DOMException: The play() request was interrupted by a call to pause().
771786
self._playLock = true;
772787

773788
// Releases the lock and executes queued actions.
774-
var runLoadQueue = function() {
775-
self._playLock = false;
776-
if (!internal) {
777-
self._emit('play', sound._id);
778-
}
779-
};
780-
play.then(runLoadQueue, runLoadQueue);
789+
play
790+
.then(function() {
791+
self._playLock = false;
792+
if (!internal) {
793+
self._emit('play', sound._id);
794+
}
795+
})
796+
.catch(function() {
797+
self._playLock = false;
798+
self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +
799+
'on mobile devices and Chrome where playback was not within a user interaction.');
800+
});
781801
} else if (!internal) {
782802
self._emit('play', sound._id);
783803
}
@@ -788,7 +808,7 @@
788808
// If the node is still paused, then we can assume there was a playback issue.
789809
if (node.paused) {
790810
self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +
791-
'on mobile devices where playback was not within a user interaction.');
811+
'on mobile devices and Chrome where playback was not within a user interaction.');
792812
return;
793813
}
794814

@@ -911,7 +931,7 @@
911931
var self = this;
912932

913933
// If the sound hasn't loaded, add it to the load queue to stop when capable.
914-
if (self._state !== 'loaded') {
934+
if (self._state !== 'loaded' || self._playLock) {
915935
self._queue.push({
916936
event: 'stop',
917937
action: function() {
@@ -980,7 +1000,7 @@
9801000
var self = this;
9811001

9821002
// If the sound hasn't loaded, add it to the load queue to mute when capable.
983-
if (self._state !== 'loaded') {
1003+
if (self._state !== 'loaded'|| self._playLock) {
9841004
self._queue.push({
9851005
event: 'mute',
9861006
action: function() {
@@ -1063,7 +1083,7 @@
10631083
var sound;
10641084
if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {
10651085
// If the sound hasn't loaded, add it to the load queue to change volume when capable.
1066-
if (self._state !== 'loaded') {
1086+
if (self._state !== 'loaded'|| self._playLock) {
10671087
self._queue.push({
10681088
event: 'volume',
10691089
action: function() {
@@ -1122,7 +1142,7 @@
11221142
var self = this;
11231143

11241144
// If the sound hasn't loaded, add it to the load queue to fade when capable.
1125-
if (self._state !== 'loaded') {
1145+
if (self._state !== 'loaded' || self._playLock) {
11261146
self._queue.push({
11271147
event: 'fade',
11281148
action: function() {
@@ -1333,7 +1353,7 @@
13331353
var sound;
13341354
if (typeof rate === 'number') {
13351355
// If the sound hasn't loaded, add it to the load queue to change playback rate when capable.
1336-
if (self._state !== 'loaded') {
1356+
if (self._state !== 'loaded' || self._playLock) {
13371357
self._queue.push({
13381358
event: 'rate',
13391359
action: function() {
@@ -1429,7 +1449,7 @@
14291449
}
14301450

14311451
// If the sound hasn't loaded, add it to the load queue to seek when capable.
1432-
if (self._state !== 'loaded') {
1452+
if (self._state !== 'loaded' || self._playLock) {
14331453
self._queue.push({
14341454
event: 'seek',
14351455
action: function() {
@@ -1456,28 +1476,33 @@
14561476
sound._ended = false;
14571477
self._clearTimer(id);
14581478

1459-
// Restart the playback if the sound was playing.
1460-
if (playing) {
1461-
self.play(id, true);
1462-
}
1463-
14641479
// Update the seek position for HTML5 Audio.
14651480
if (!self._webAudio && sound._node) {
14661481
sound._node.currentTime = seek;
14671482
}
14681483

1484+
// Seek and emit when ready.
1485+
var seekAndEmit = function() {
1486+
self._emit('seek', id);
1487+
1488+
// Restart the playback if the sound was playing.
1489+
if (playing) {
1490+
self.play(id, true);
1491+
}
1492+
};
1493+
14691494
// Wait for the play lock to be unset before emitting (HTML5 Audio).
14701495
if (playing && !self._webAudio) {
14711496
var emitSeek = function() {
14721497
if (!self._playLock) {
1473-
self._emit('seek', id);
1498+
seekAndEmit();
14741499
} else {
14751500
setTimeout(emitSeek, 0);
14761501
}
14771502
};
14781503
setTimeout(emitSeek, 0);
14791504
} else {
1480-
self._emit('seek', id);
1505+
seekAndEmit();
14811506
}
14821507
} else {
14831508
if (self._webAudio) {
@@ -1953,7 +1978,7 @@
19531978
sound._node.bufferSource.loop = sound._loop;
19541979
if (sound._loop) {
19551980
sound._node.bufferSource.loopStart = sound._start || 0;
1956-
sound._node.bufferSource.loopEnd = sound._stop;
1981+
sound._node.bufferSource.loopEnd = sound._stop || 0;
19571982
}
19581983
sound._node.bufferSource.playbackRate.setValueAtTime(sound._rate, Howler.ctx.currentTime);
19591984

@@ -2203,16 +2228,28 @@
22032228
* @param {Howl} self
22042229
*/
22052230
var decodeAudioData = function(arraybuffer, self) {
2206-
// Decode the buffer into an audio source.
2207-
Howler.ctx.decodeAudioData(arraybuffer, function(buffer) {
2231+
// Load the sound on success.
2232+
var success = function(buffer) {
22082233
if (buffer && self._sounds.length > 0) {
22092234
cache[self._src] = buffer;
22102235
loadSound(self, buffer);
2236+
} else {
2237+
onError();
22112238
}
2212-
}, function() {
2239+
};
2240+
2241+
// Fire a load error if something broke.
2242+
var error = function() {
22132243
self._emit('loaderror', null, 'Decoding audio data failed.');
2214-
});
2215-
};
2244+
};
2245+
2246+
// Decode the buffer into an audio source.
2247+
if (typeof Promise !== 'undefined' && Howler.ctx.decodeAudioData.length === 1) {
2248+
Howler.ctx.decodeAudioData(arraybuffer).then(success).catch(error);
2249+
} else {
2250+
Howler.ctx.decodeAudioData(arraybuffer, success, error);
2251+
}
2252+
}
22162253

22172254
/**
22182255
* Sound is now loaded, so finish setting everything up and fire the loaded event.
@@ -2312,7 +2349,7 @@
23122349
/*!
23132350
* Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.
23142351
*
2315-
* howler.js v2.0.13
2352+
* howler.js v2.0.14
23162353
* howlerjs.com
23172354
*
23182355
* (c) 2013-2018, James Simpson of GoldFire Studios
@@ -2703,9 +2740,13 @@
27032740
setupPanner(sound, 'spatial');
27042741
}
27052742

2706-
sound._panner.orientationX.setValueAtTime(x, Howler.ctx.currentTime);
2707-
sound._panner.orientationY.setValueAtTime(y, Howler.ctx.currentTime);
2708-
sound._panner.orientationZ.setValueAtTime(z, Howler.ctx.currentTime);
2743+
if (typeof sound._panner.orientationX !== 'undefined') {
2744+
sound._panner.orientationX.setValueAtTime(x, Howler.ctx.currentTime);
2745+
sound._panner.orientationY.setValueAtTime(y, Howler.ctx.currentTime);
2746+
sound._panner.orientationZ.setValueAtTime(z, Howler.ctx.currentTime);
2747+
} else {
2748+
sound._panner.setOrientation(x, y, z);
2749+
}
27092750
}
27102751

27112752
self._emit('orientation', sound._id);

‎dist/howler.min.js

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/howler.spatial.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "howler",
3-
"version": "2.0.13",
3+
"version": "2.0.14",
44
"description": "Javascript audio library for the modern web.",
55
"homepage": "https://howlerjs.com",
66
"keywords": [

‎src/howler.core.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* howler.js v2.0.13
2+
* howler.js v2.0.14
33
* howlerjs.com
44
*
55
* (c) 2013-2018, James Simpson of GoldFire Studios

‎src/plugins/howler.spatial.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*!
22
* Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.
33
*
4-
* howler.js v2.0.13
4+
* howler.js v2.0.14
55
* howlerjs.com
66
*
77
* (c) 2013-2018, James Simpson of GoldFire Studios

0 commit comments

Comments
 (0)
Please sign in to comment.