Skip to content

Commit a093f49

Browse files
committed
v2.2.0
1 parent a7ad26c commit a093f49

20 files changed

+103
-53
lines changed

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
## 2.2.0 (May 17, 2020)
2+
- `ADDED` New `xhr` property that allows setting custom headers (such as for auth), changing the `withCredentials` setting and specifying the HTTP method for the request. These only apply to Web Audio ([#997](https://github.com/goldfire/howler.js/pull/997)).
3+
- `ADDED` New `Howler.stop()` global stop method to stop all sounds at once ([#1308](https://github.com/goldfire/howler.js/issues/1308)).
4+
- `ADDED` Support for `m48` audio format ([#1170](https://github.com/goldfire/howler.js/pull/1170)).
5+
- `CHANGED` Allow passing `metadata` string to `preload` option to only preload the metadata ([#1140](https://github.com/goldfire/howler.js/pull/1140)).
6+
- `FIXED` Correctly handle AudioContext interrupted state causing stuck `suspending` state ([#1106](https://github.com/goldfire/howler.js/pull/1106)).
7+
- `FIXED` The `volume` method would sometimes return incorrect values when using very short `fade` lengths ([#1045](https://github.com/goldfire/howler.js/pull/1045)).
8+
- `FIXED` Error that `HowlerGlobal` was not defined when using `jsdom-global` ([#1331](https://github.com/goldfire/howler.js/pull/1331)).
9+
- `FIXED` Memory leak in Safari when an audio context can't be unlocked ([#1338](https://github.com/goldfire/howler.js/pull/1338)).
10+
11+
### Breaking Changes
12+
* The `xhrWithCredentials` property is now included in the `xhr` property object with key `withCredentials`.
13+
114
## 2.1.3 (December 24, 2019)
215
- `FIXED` Don't try to obtain HTML5 audio if there is no audio support ([#1191](https://github.com/goldfire/howler.js/issues/1191)).
316
- `FIXED` The x/y/z orientations for the top of the listener weren't being set properly ([#1221](https://github.com/goldfire/howler.js/pull/1221)).

LICENSE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2013-2019 James Simpson and GoldFire Studios, Inc.
1+
Copyright (c) 2013-2020 James Simpson and GoldFire Studios, Inc.
22

33
Permission is hereby granted, free of charge, to any person obtaining
44
a copy of this software and associated documentation files (the

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,6 @@ ffmpeg -i sound1.wav -dash 1 sound1.webm
504504

505505
### License
506506

507-
Copyright (c) 2013-2019 [James Simpson](https://twitter.com/GoldFireStudios) and [GoldFire Studios, Inc.](http://goldfirestudios.com)
507+
Copyright (c) 2013-2020 [James Simpson](https://twitter.com/GoldFireStudios) and [GoldFire Studios, Inc.](http://goldfirestudios.com)
508508

509509
Released under the [MIT License](https://github.com/goldfire/howler.js/blob/master/LICENSE.md).

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

+67-30
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/*!
2-
* howler.js v2.1.3
2+
* howler.js v2.2.0
33
* howlerjs.com
44
*
5-
* (c) 2013-2019, James Simpson of GoldFire Studios
5+
* (c) 2013-2020, James Simpson of GoldFire Studios
66
* goldfirestudios.com
77
*
88
* MIT License
@@ -150,6 +150,20 @@
150150
return self;
151151
},
152152

153+
/**
154+
* Handle stopping all sounds globally.
155+
*/
156+
stop: function() {
157+
var self = this || Howler;
158+
159+
// Loop through all Howls and stop them.
160+
for (var i=0; i<self._howls.length; i++) {
161+
self._howls[i].stop();
162+
}
163+
164+
return self;
165+
},
166+
153167
/**
154168
* Unload and destroy all currently loaded Howl objects.
155169
* @return {Howler}
@@ -263,6 +277,7 @@
263277
aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''),
264278
caf: !!audioTest.canPlayType('audio/x-caf;').replace(/^no$/, ''),
265279
m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
280+
m4b: !!(audioTest.canPlayType('audio/x-m4b;') || audioTest.canPlayType('audio/m4b;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
266281
mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
267282
weba: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''),
268283
webm: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''),
@@ -312,7 +327,7 @@
312327
// to the WebAudio API which only needs a single activation.
313328
// This must occur before WebAudio setup or the source.onended
314329
// event will not fire.
315-
for (var i=0; i<self.html5PoolSize; i++) {
330+
while (self._html5AudioPool.length < self.html5PoolSize) {
316331
try {
317332
var audioNode = new Audio();
318333

@@ -324,6 +339,7 @@
324339
self._releaseHtml5Audio(audioNode);
325340
} catch (e) {
326341
self.noAudio = true;
342+
break;
327343
}
328344
}
329345

@@ -466,14 +482,20 @@
466482

467483
self._suspendTimer = null;
468484
self.state = 'suspending';
469-
self.ctx.suspend().then(function() {
485+
486+
// Handle updating the state of the audio context after suspending.
487+
var handleSuspension = function() {
470488
self.state = 'suspended';
471489

472490
if (self._resumeAfterSuspend) {
473491
delete self._resumeAfterSuspend;
474492
self._autoResume();
475493
}
476-
});
494+
};
495+
496+
// Either the state gets suspended or it is interrupted.
497+
// Either way, we need to update the state to suspended.
498+
self.ctx.suspend().then(handleSuspension, handleSuspension);
477499
}, 30000);
478500

479501
return self;
@@ -490,10 +512,10 @@
490512
return;
491513
}
492514

493-
if (self.state === 'running' && self._suspendTimer) {
515+
if (self.state === 'running' && self.ctx.state !== 'interrupted' && self._suspendTimer) {
494516
clearTimeout(self._suspendTimer);
495517
self._suspendTimer = null;
496-
} else if (self.state === 'suspended') {
518+
} else if (self.state === 'suspended' || self.state === 'running' && self.ctx.state === 'interrupted') {
497519
self.ctx.resume().then(function() {
498520
self.state = 'running';
499521

@@ -557,12 +579,16 @@
557579
self._muted = o.mute || false;
558580
self._loop = o.loop || false;
559581
self._pool = o.pool || 5;
560-
self._preload = (typeof o.preload === 'boolean') ? o.preload : true;
582+
self._preload = (typeof o.preload === 'boolean' || o.preload === 'metadata') ? o.preload : true;
561583
self._rate = o.rate || 1;
562584
self._sprite = o.sprite || {};
563585
self._src = (typeof o.src !== 'string') ? o.src : [o.src];
564586
self._volume = o.volume !== undefined ? o.volume : 1;
565-
self._xhrWithCredentials = o.xhrWithCredentials || false;
587+
self._xhr = {
588+
method: o.xhr && o.xhr.method ? o.xhr.method : 'GET',
589+
headers: o.xhr && o.xhr.headers ? o.xhr.headers : null,
590+
withCredentials: o.xhr && o.xhr.withCredentials ? o.xhr.withCredentials : false,
591+
};
566592

567593
// Setup all other default properties.
568594
self._duration = 0;
@@ -610,7 +636,7 @@
610636
}
611637

612638
// Load the source file unless otherwise specified.
613-
if (self._preload) {
639+
if (self._preload && self._preload !== 'none') {
614640
self.load();
615641
}
616642

@@ -721,8 +747,8 @@
721747
// Use the default sound sprite (plays the full audio length).
722748
sprite = '__default';
723749

724-
// Check if there is a single paused sound that isn't ended.
725-
// If there is, play that sound. If not, continue as usual.
750+
// Check if there is a single paused sound that isn't ended.
751+
// If there is, play that sound. If not, continue as usual.
726752
if (!self._playLock) {
727753
var num = 0;
728754
for (var i=0; i<self._sounds.length; i++) {
@@ -851,7 +877,7 @@
851877
}
852878
};
853879

854-
if (Howler.state === 'running') {
880+
if (Howler.state === 'running' && Howler.ctx.state !== 'interrupted') {
855881
playWebAudio();
856882
} else {
857883
self._playLock = true;
@@ -1273,8 +1299,8 @@
12731299
}
12741300

12751301
// Make sure the to/from/len values are numbers.
1276-
from = parseFloat(from);
1277-
to = parseFloat(to);
1302+
from = Math.min(Math.max(0, parseFloat(from)), 1);
1303+
to = Math.min(Math.max(0, parseFloat(to)), 1);
12781304
len = parseFloat(len);
12791305

12801306
// Set the volume to the start position.
@@ -1337,8 +1363,11 @@
13371363
vol += diff * tick;
13381364

13391365
// Make sure the volume is in the right bounds.
1340-
vol = Math.max(0, vol);
1341-
vol = Math.min(1, vol);
1366+
if (diff < 0) {
1367+
vol = Math.max(to, vol);
1368+
} else {
1369+
vol = Math.min(to, vol);
1370+
}
13421371

13431372
// Round to within 2 decimal points.
13441373
vol = Math.round(vol * 100) / 100;
@@ -2215,7 +2244,7 @@
22152244

22162245
// Setup the new audio node.
22172246
self._node.src = parent._src;
2218-
self._node.preload = 'auto';
2247+
self._node.preload = parent._preload === true ? 'auto' : parent._preload;
22192248
self._node.volume = volume * Howler.volume();
22202249

22212250
// Begin loading the source.
@@ -2324,9 +2353,17 @@
23242353
} else {
23252354
// Load the buffer from the URL.
23262355
var xhr = new XMLHttpRequest();
2327-
xhr.open('GET', url, true);
2328-
xhr.withCredentials = self._xhrWithCredentials;
2356+
xhr.open(self._xhr.method, url, true);
2357+
xhr.withCredentials = self._xhr.withCredentials;
23292358
xhr.responseType = 'arraybuffer';
2359+
2360+
// Apply any custom headers to the request.
2361+
if (self._xhr.headers) {
2362+
Object.keys(self._xhr.headers).forEach(function(key) {
2363+
xhr.setRequestHeader(key, self._xhr.headers[key]);
2364+
});
2365+
}
2366+
23302367
xhr.onload = function() {
23312368
// Make sure we get a successful response back.
23322369
var code = (xhr.status + '')[0];
@@ -2450,7 +2487,7 @@
24502487
var version = appVersion ? parseInt(appVersion[1], 10) : null;
24512488
if (iOS && version && version < 9) {
24522489
var safari = /safari/.test(Howler._navigator && Howler._navigator.userAgent.toLowerCase());
2453-
if (Howler._navigator && Howler._navigator.standalone && !safari || Howler._navigator && !Howler._navigator.standalone && !safari) {
2490+
if (Howler._navigator && !safari) {
24542491
Howler.usingWebAudio = false;
24552492
}
24562493
}
@@ -2482,28 +2519,28 @@
24822519
exports.Howl = Howl;
24832520
}
24842521

2485-
// Define globally in case AMD is not available or unused.
2486-
if (typeof window !== 'undefined') {
2487-
window.HowlerGlobal = HowlerGlobal;
2488-
window.Howler = Howler;
2489-
window.Howl = Howl;
2490-
window.Sound = Sound;
2491-
} else if (typeof global !== 'undefined') { // Add to global in Node.js (for testing, etc).
2522+
// Add to global in Node.js (for testing, etc).
2523+
if (typeof global !== 'undefined') {
24922524
global.HowlerGlobal = HowlerGlobal;
24932525
global.Howler = Howler;
24942526
global.Howl = Howl;
24952527
global.Sound = Sound;
2528+
} else if (typeof window !== 'undefined') { // Define globally in case AMD is not available or unused.
2529+
window.HowlerGlobal = HowlerGlobal;
2530+
window.Howler = Howler;
2531+
window.Howl = Howl;
2532+
window.Sound = Sound;
24962533
}
24972534
})();
24982535

24992536

25002537
/*!
25012538
* Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.
25022539
*
2503-
* howler.js v2.1.3
2540+
* howler.js v2.2.0
25042541
* howlerjs.com
25052542
*
2506-
* (c) 2013-2019, James Simpson of GoldFire Studios
2543+
* (c) 2013-2020, James Simpson of GoldFire Studios
25072544
* goldfirestudios.com
25082545
*
25092546
* MIT License

dist/howler.min.js

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

0 commit comments

Comments
 (0)