|
1 | 1 | /*!
|
2 |
| - * howler.js v2.1.3 |
| 2 | + * howler.js v2.2.0 |
3 | 3 | * howlerjs.com
|
4 | 4 | *
|
5 |
| - * (c) 2013-2019, James Simpson of GoldFire Studios |
| 5 | + * (c) 2013-2020, James Simpson of GoldFire Studios |
6 | 6 | * goldfirestudios.com
|
7 | 7 | *
|
8 | 8 | * MIT License
|
|
150 | 150 | return self;
|
151 | 151 | },
|
152 | 152 |
|
| 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 | + |
153 | 167 | /**
|
154 | 168 | * Unload and destroy all currently loaded Howl objects.
|
155 | 169 | * @return {Howler}
|
|
263 | 277 | aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''),
|
264 | 278 | caf: !!audioTest.canPlayType('audio/x-caf;').replace(/^no$/, ''),
|
265 | 279 | 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$/, ''), |
266 | 281 | mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
|
267 | 282 | weba: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''),
|
268 | 283 | webm: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''),
|
|
312 | 327 | // to the WebAudio API which only needs a single activation.
|
313 | 328 | // This must occur before WebAudio setup or the source.onended
|
314 | 329 | // event will not fire.
|
315 |
| - for (var i=0; i<self.html5PoolSize; i++) { |
| 330 | + while (self._html5AudioPool.length < self.html5PoolSize) { |
316 | 331 | try {
|
317 | 332 | var audioNode = new Audio();
|
318 | 333 |
|
|
324 | 339 | self._releaseHtml5Audio(audioNode);
|
325 | 340 | } catch (e) {
|
326 | 341 | self.noAudio = true;
|
| 342 | + break; |
327 | 343 | }
|
328 | 344 | }
|
329 | 345 |
|
|
466 | 482 |
|
467 | 483 | self._suspendTimer = null;
|
468 | 484 | 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() { |
470 | 488 | self.state = 'suspended';
|
471 | 489 |
|
472 | 490 | if (self._resumeAfterSuspend) {
|
473 | 491 | delete self._resumeAfterSuspend;
|
474 | 492 | self._autoResume();
|
475 | 493 | }
|
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); |
477 | 499 | }, 30000);
|
478 | 500 |
|
479 | 501 | return self;
|
|
490 | 512 | return;
|
491 | 513 | }
|
492 | 514 |
|
493 |
| - if (self.state === 'running' && self._suspendTimer) { |
| 515 | + if (self.state === 'running' && self.ctx.state !== 'interrupted' && self._suspendTimer) { |
494 | 516 | clearTimeout(self._suspendTimer);
|
495 | 517 | self._suspendTimer = null;
|
496 |
| - } else if (self.state === 'suspended') { |
| 518 | + } else if (self.state === 'suspended' || self.state === 'running' && self.ctx.state === 'interrupted') { |
497 | 519 | self.ctx.resume().then(function() {
|
498 | 520 | self.state = 'running';
|
499 | 521 |
|
|
557 | 579 | self._muted = o.mute || false;
|
558 | 580 | self._loop = o.loop || false;
|
559 | 581 | 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; |
561 | 583 | self._rate = o.rate || 1;
|
562 | 584 | self._sprite = o.sprite || {};
|
563 | 585 | self._src = (typeof o.src !== 'string') ? o.src : [o.src];
|
564 | 586 | 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 | + }; |
566 | 592 |
|
567 | 593 | // Setup all other default properties.
|
568 | 594 | self._duration = 0;
|
|
610 | 636 | }
|
611 | 637 |
|
612 | 638 | // Load the source file unless otherwise specified.
|
613 |
| - if (self._preload) { |
| 639 | + if (self._preload && self._preload !== 'none') { |
614 | 640 | self.load();
|
615 | 641 | }
|
616 | 642 |
|
|
721 | 747 | // Use the default sound sprite (plays the full audio length).
|
722 | 748 | sprite = '__default';
|
723 | 749 |
|
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. |
726 | 752 | if (!self._playLock) {
|
727 | 753 | var num = 0;
|
728 | 754 | for (var i=0; i<self._sounds.length; i++) {
|
|
851 | 877 | }
|
852 | 878 | };
|
853 | 879 |
|
854 |
| - if (Howler.state === 'running') { |
| 880 | + if (Howler.state === 'running' && Howler.ctx.state !== 'interrupted') { |
855 | 881 | playWebAudio();
|
856 | 882 | } else {
|
857 | 883 | self._playLock = true;
|
|
1273 | 1299 | }
|
1274 | 1300 |
|
1275 | 1301 | // 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); |
1278 | 1304 | len = parseFloat(len);
|
1279 | 1305 |
|
1280 | 1306 | // Set the volume to the start position.
|
|
1337 | 1363 | vol += diff * tick;
|
1338 | 1364 |
|
1339 | 1365 | // 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 | + } |
1342 | 1371 |
|
1343 | 1372 | // Round to within 2 decimal points.
|
1344 | 1373 | vol = Math.round(vol * 100) / 100;
|
|
2215 | 2244 |
|
2216 | 2245 | // Setup the new audio node.
|
2217 | 2246 | self._node.src = parent._src;
|
2218 |
| - self._node.preload = 'auto'; |
| 2247 | + self._node.preload = parent._preload === true ? 'auto' : parent._preload; |
2219 | 2248 | self._node.volume = volume * Howler.volume();
|
2220 | 2249 |
|
2221 | 2250 | // Begin loading the source.
|
|
2324 | 2353 | } else {
|
2325 | 2354 | // Load the buffer from the URL.
|
2326 | 2355 | 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; |
2329 | 2358 | 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 | + |
2330 | 2367 | xhr.onload = function() {
|
2331 | 2368 | // Make sure we get a successful response back.
|
2332 | 2369 | var code = (xhr.status + '')[0];
|
|
2450 | 2487 | var version = appVersion ? parseInt(appVersion[1], 10) : null;
|
2451 | 2488 | if (iOS && version && version < 9) {
|
2452 | 2489 | 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) { |
2454 | 2491 | Howler.usingWebAudio = false;
|
2455 | 2492 | }
|
2456 | 2493 | }
|
|
2482 | 2519 | exports.Howl = Howl;
|
2483 | 2520 | }
|
2484 | 2521 |
|
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') { |
2492 | 2524 | global.HowlerGlobal = HowlerGlobal;
|
2493 | 2525 | global.Howler = Howler;
|
2494 | 2526 | global.Howl = Howl;
|
2495 | 2527 | 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; |
2496 | 2533 | }
|
2497 | 2534 | })();
|
2498 | 2535 |
|
2499 | 2536 |
|
2500 | 2537 | /*!
|
2501 | 2538 | * Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.
|
2502 | 2539 | *
|
2503 |
| - * howler.js v2.1.3 |
| 2540 | + * howler.js v2.2.0 |
2504 | 2541 | * howlerjs.com
|
2505 | 2542 | *
|
2506 |
| - * (c) 2013-2019, James Simpson of GoldFire Studios |
| 2543 | + * (c) 2013-2020, James Simpson of GoldFire Studios |
2507 | 2544 | * goldfirestudios.com
|
2508 | 2545 | *
|
2509 | 2546 | * MIT License
|
|
0 commit comments