soundmanager2-rails 2.97.20130324 → 2.97.20130512

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,7 +8,7 @@
8
8
  * Code provided under the BSD License:
9
9
  * http://schillmania.com/projects/soundmanager2/license.txt
10
10
  *
11
- * V2.97a.20130324 ("Mahalo" Edition)
11
+ * V2.97a.20130512
12
12
  */
13
13
 
14
14
  /*global window, SM2_DEFER, sm2Debugger, console, document, navigator, setTimeout, setInterval, clearInterval, Audio, opera */
@@ -74,7 +74,8 @@ function SoundManager(smURL, smID) {
74
74
  'useHTML5Audio': true, // use HTML5 Audio() where API is supported (most Safari, Chrome versions), Firefox (no MP3/MP4.) Ideally, transparent vs. Flash API where possible.
75
75
  'html5Test': /^(probably|maybe)$/i, // HTML5 Audio() format support test. Use /^probably$/i; if you want to be more conservative.
76
76
  'preferFlash': true, // overrides useHTML5audio. if true and flash support present, will try to use flash for MP3/MP4 as needed since HTML5 audio support is still quirky in browsers.
77
- 'noSWFCache': false // if true, appends ?ts={date} to break aggressive SWF caching.
77
+ 'noSWFCache': false, // if true, appends ?ts={date} to break aggressive SWF caching.
78
+ 'idPrefix': 'sound' // if an id is not provided to createSound(), this prefix is used for generated IDs - 'sound0', 'sound1' etc.
78
79
 
79
80
  };
80
81
 
@@ -188,7 +189,7 @@ function SoundManager(smURL, smID) {
188
189
 
189
190
  // dynamic attributes
190
191
 
191
- this.versionNumber = 'V2.97a.20130324';
192
+ this.versionNumber = 'V2.97a.20130512';
192
193
  this.version = null;
193
194
  this.movieURL = null;
194
195
  this.altURL = null;
@@ -265,11 +266,11 @@ function SoundManager(smURL, smID) {
265
266
 
266
267
  var SMSound,
267
268
  sm2 = this, globalHTML5Audio = null, flash = null, sm = 'soundManager', smc = sm + ': ', h5 = 'HTML5::', id, ua = navigator.userAgent, wl = window.location.href.toString(), doc = document, doNothing, setProperties, init, fV, on_queue = [], debugOpen = true, debugTS, didAppend = false, appendSuccess = false, didInit = false, disabled = false, windowLoaded = false, _wDS, wdCount = 0, initComplete, mixin, assign, extraOptions, addOnEvent, processOnEvents, initUserOnload, delayWaitForEI, waitForEI, setVersionInfo, handleFocus, strings, initMovie, preInit, domContentLoaded, winOnLoad, didDCLoaded, getDocument, createMovie, catchError, setPolling, initDebug, debugLevels = ['log', 'info', 'warn', 'error'], defaultFlashVersion = 8, disableObject, failSafely, normalizeMovieURL, oRemoved = null, oRemovedHTML = null, str, flashBlockHandler, getSWFCSS, swfCSS, toggleDebug, loopFix, policyFix, complain, idCheck, waitingForEI = false, initPending = false, startTimer, stopTimer, timerExecute, h5TimerCount = 0, h5IntervalTimer = null, parseURL, messages = [],
268
- needsFlash = null, featureCheck, html5OK, html5CanPlay, html5Ext, html5Unload, domContentLoadedIE, testHTML5, event, slice = Array.prototype.slice, useGlobalHTML5Audio = false, lastGlobalHTML5URL, hasFlash, detectFlash, badSafariFix, html5_events, showSupport, flushMessages, wrapCallback,
269
- is_iDevice = ua.match(/(ipad|iphone|ipod)/i), isAndroid = ua.match(/android/i), isIE = ua.match(/msie/i), isWebkit = ua.match(/webkit/i), isSafari = (ua.match(/safari/i) && !ua.match(/chrome/i)), isOpera = (ua.match(/opera/i)),
269
+ canIgnoreFlash, needsFlash = null, featureCheck, html5OK, html5CanPlay, html5Ext, html5Unload, domContentLoadedIE, testHTML5, event, slice = Array.prototype.slice, useGlobalHTML5Audio = false, lastGlobalHTML5URL, hasFlash, detectFlash, badSafariFix, html5_events, showSupport, flushMessages, wrapCallback, idCounter = 0,
270
+ is_iDevice = ua.match(/(ipad|iphone|ipod)/i), isAndroid = ua.match(/android/i), isIE = ua.match(/msie/i), isWebkit = ua.match(/webkit/i), isSafari = (ua.match(/safari/i) && !ua.match(/chrome/i)), isOpera = (ua.match(/opera/i)), isFirefox = (ua.match(/firefox/i)),
270
271
  mobileHTML5 = (ua.match(/(mobile|pre\/|xoom)/i) || is_iDevice || isAndroid),
271
272
  isBadSafari = (!wl.match(/usehtml5audio/i) && !wl.match(/sm2\-ignorebadua/i) && isSafari && !ua.match(/silk/i) && ua.match(/OS X 10_6_([3-7])/i)), // Safari 4 and 5 (excluding Kindle Fire, "Silk") occasionally fail to load/play HTML5 audio on Snow Leopard 10.6.3 through 10.6.7 due to bug(s) in QuickTime X and/or other underlying frameworks. :/ Confirmed bug. https://bugs.webkit.org/show_bug.cgi?id=32159
272
- hasConsole = (window.console !== _undefined && console.log !== _undefined), isFocused = (doc.hasFocus !== _undefined?doc.hasFocus():null), tryInitOnFocus = (isSafari && (doc.hasFocus === _undefined || !doc.hasFocus())), okToDisable = !tryInitOnFocus, flashMIME = /(mp3|mp4|mpa|m4a|m4b)/i,
273
+ hasConsole = (window.console !== _undefined && console.log !== _undefined), isFocused = (doc.hasFocus !== _undefined?doc.hasFocus():null), tryInitOnFocus = (isSafari && (doc.hasFocus === _undefined || !doc.hasFocus())), okToDisable = !tryInitOnFocus, flashMIME = /(mp3|mp4|mpa|m4a|m4b)/i, msecScale = 1000,
273
274
  emptyURL = 'about:blank', // safe URL to unload, or load nothing from (flash 8 + most HTML5 UAs)
274
275
  overHTTP = (doc.location?doc.location.protocol.match(/http/i):null),
275
276
  http = (!overHTTP ? 'http:/'+'/' : ''),
@@ -341,14 +342,18 @@ function SoundManager(smURL, smID) {
341
342
 
342
343
  // special case 1: "Late setup". SM2 loaded normally, but user didn't assign flash URL eg., setup({url:...}) before SM2 init. Treat as delayed init.
343
344
 
344
- if (noURL && didDCLoaded && options.url !== _undefined) {
345
- sm2.beginDelayedInit();
346
- }
345
+ if (options) {
346
+
347
+ if (noURL && didDCLoaded && options.url !== _undefined) {
348
+ sm2.beginDelayedInit();
349
+ }
350
+
351
+ // special case 2: If lazy-loading SM2 (DOMContentLoaded has already happened) and user calls setup() with url: parameter, try to init ASAP.
347
352
 
348
- // special case 2: If lazy-loading SM2 (DOMContentLoaded has already happened) and user calls setup() with url: parameter, try to init ASAP.
353
+ if (!didDCLoaded && options.url !== _undefined && doc.readyState === 'complete') {
354
+ setTimeout(domContentLoaded, 1);
355
+ }
349
356
 
350
- if (!didDCLoaded && options.url !== _undefined && doc.readyState === 'complete') {
351
- setTimeout(domContentLoaded, 1);
352
357
  }
353
358
 
354
359
  return sm2;
@@ -357,7 +362,7 @@ function SoundManager(smURL, smID) {
357
362
 
358
363
  this.ok = function() {
359
364
 
360
- return (needsFlash?(didInit && !disabled):(sm2.useHTML5Audio && sm2.hasHTML5));
365
+ return (needsFlash ? (didInit && !disabled) : (sm2.useHTML5Audio && sm2.hasHTML5));
361
366
 
362
367
  };
363
368
 
@@ -392,7 +397,7 @@ function SoundManager(smURL, smID) {
392
397
  }
393
398
 
394
399
  if (_url !== _undefined) {
395
- // function overloading in JS! :) ..assume simple createSound(id,url) use case
400
+ // function overloading in JS! :) ..assume simple createSound(id, url) use case
396
401
  oOptions = {
397
402
  'id': oOptions,
398
403
  'url': _url
@@ -404,12 +409,17 @@ function SoundManager(smURL, smID) {
404
409
 
405
410
  options.url = parseURL(options.url);
406
411
 
412
+ // generate an id, if needed.
413
+ if (options.id === undefined) {
414
+ options.id = sm2.setupOptions.idPrefix + (idCounter++);
415
+ }
416
+
407
417
  // <d>
408
418
  if (options.id.toString().charAt(0).match(/^[0-9]$/)) {
409
419
  sm2._wD(cs + str('badID', options.id), 2);
410
420
  }
411
421
 
412
- sm2._wD(cs + options.id + ' (' + options.url + ')', 1);
422
+ sm2._wD(cs + options.id + (options.url ? ' (' + options.url + ')' : ''), 1);
413
423
  // </d>
414
424
 
415
425
  if (idCheck(options.id, true)) {
@@ -434,10 +444,23 @@ function SoundManager(smURL, smID) {
434
444
 
435
445
  } else {
436
446
 
447
+ if (sm2.html5Only) {
448
+ sm2._wD(options.id + ': No HTML5 support for this sound, and no Flash. Exiting.');
449
+ return make();
450
+ }
451
+
452
+ // TODO: Move HTML5/flash checks into generic URL parsing/handling function.
453
+
454
+ if (sm2.html5.usingFlash && options.url && options.url.match(/data\:/i)) {
455
+ // data: URIs not supported by Flash, either.
456
+ sm2._wD(options.id + ': data: URIs not supported via Flash. Exiting.');
457
+ return make();
458
+ }
459
+
437
460
  if (fV > 8) {
438
461
  if (options.isMovieStar === null) {
439
462
  // attempt to detect MPEG-4 formats
440
- options.isMovieStar = !!(options.serverURL || (options.type ? options.type.match(netStreamMimeTypes) : false) || options.url.match(netStreamPattern));
463
+ options.isMovieStar = !!(options.serverURL || (options.type ? options.type.match(netStreamMimeTypes) : false) || (options.url && options.url.match(netStreamPattern)));
441
464
  }
442
465
  // <d>
443
466
  if (options.isMovieStar) {
@@ -603,30 +626,50 @@ function SoundManager(smURL, smID) {
603
626
 
604
627
  this.play = function(sID, oOptions) {
605
628
 
606
- var result = false;
629
+ var result = null,
630
+ // legacy function-overloading use case: play('mySound', '/path/to/some.mp3');
631
+ overloaded = (oOptions && !(oOptions instanceof Object));
607
632
 
608
633
  if (!didInit || !sm2.ok()) {
609
634
  complain(sm + '.play(): ' + str(!didInit?'notReady':'notOK'));
610
- return result;
635
+ return false;
611
636
  }
612
637
 
613
- if (!idCheck(sID)) {
614
- if (!(oOptions instanceof Object)) {
615
- // overloading use case: play('mySound','/path/to/some.mp3');
638
+ if (!idCheck(sID, overloaded)) {
639
+
640
+ if (!overloaded) {
641
+ // no sound found for the given ID. Bail.
642
+ return false;
643
+ }
644
+
645
+ if (overloaded) {
616
646
  oOptions = {
617
647
  url: oOptions
618
648
  };
619
649
  }
650
+
620
651
  if (oOptions && oOptions.url) {
621
- // overloading use case, create+play: .play('someID',{url:'/path/to.mp3'});
622
- sm2._wD(sm + '.play(): attempting to create "' + sID + '"', 1);
652
+ // overloading use case, create+play: .play('someID', {url:'/path/to.mp3'});
653
+ sm2._wD(sm + '.play(): Attempting to create "' + sID + '"', 1);
623
654
  oOptions.id = sID;
624
655
  result = sm2.createSound(oOptions).play();
625
656
  }
626
- return result;
657
+
658
+ } else if (overloaded) {
659
+
660
+ // existing sound object case
661
+ oOptions = {
662
+ url: oOptions
663
+ };
664
+
627
665
  }
628
666
 
629
- return sm2.sounds[sID].play(oOptions);
667
+ if (result === null) {
668
+ // default case
669
+ result = sm2.sounds[sID].play(oOptions);
670
+ }
671
+
672
+ return result;
630
673
 
631
674
  };
632
675
 
@@ -1025,14 +1068,14 @@ function SoundManager(smURL, smID) {
1025
1068
  this.getSoundById = function(sID, _suppressDebug) {
1026
1069
 
1027
1070
  if (!sID) {
1028
- throw new Error(sm + '.getSoundById(): sID is null/_undefined');
1071
+ return null;
1029
1072
  }
1030
1073
 
1031
1074
  var result = sm2.sounds[sID];
1032
1075
 
1033
1076
  // <d>
1034
1077
  if (!result && !_suppressDebug) {
1035
- sm2._wD('"' + sID + '" is an invalid sound ID.', 2);
1078
+ sm2._wD(sm + '.getSoundById(): Sound "' + sID + '" not found.', 2);
1036
1079
  }
1037
1080
  // </d>
1038
1081
 
@@ -1236,7 +1279,7 @@ function SoundManager(smURL, smID) {
1236
1279
 
1237
1280
  // <d>
1238
1281
  if (sm2.soundIDs.length) {
1239
- sm2._wD('Destroying ' + sm2.soundIDs.length + ' SMSound objects...');
1282
+ sm2._wD('Destroying ' + sm2.soundIDs.length + ' SMSound object' + (sm2.soundIDs.length !== 1 ? 's' : '') + '...');
1240
1283
  }
1241
1284
  // </d>
1242
1285
 
@@ -1246,7 +1289,7 @@ function SoundManager(smURL, smID) {
1246
1289
  sm2.sounds[sm2.soundIDs[i]].destruct();
1247
1290
  }
1248
1291
 
1249
- // trash ze flash
1292
+ // trash ze flash (remove from the DOM)
1250
1293
 
1251
1294
  if (flash) {
1252
1295
 
@@ -1258,8 +1301,6 @@ function SoundManager(smURL, smID) {
1258
1301
 
1259
1302
  oRemoved = flash.parentNode.removeChild(flash);
1260
1303
 
1261
- _wDS('flRemoved');
1262
-
1263
1304
  } catch(e) {
1264
1305
 
1265
1306
  // Remove failed? May be due to flash blockers silently removing the SWF object/embed node from the DOM. Warn and continue.
@@ -1279,6 +1320,8 @@ function SoundManager(smURL, smID) {
1279
1320
  sm2.soundIDs = [];
1280
1321
  sm2.sounds = {};
1281
1322
 
1323
+ idCounter = 0;
1324
+
1282
1325
  if (!resetEvents) {
1283
1326
  // reset callbacks for onready, ontimeout etc. so that they will fire again on re-init
1284
1327
  for (i in on_queue) {
@@ -1409,7 +1452,7 @@ function SoundManager(smURL, smID) {
1409
1452
 
1410
1453
  SMSound = function(oOptions) {
1411
1454
 
1412
- var s = this, resetProperties, add_html5_events, remove_html5_events, stop_html5_timer, start_html5_timer, attachOnPosition, onplay_called = false, onPositionItems = [], onPositionFired = 0, detachOnPosition, applyFromTo, lastURL = null, lastHTML5State;
1455
+ var s = this, resetProperties, add_html5_events, remove_html5_events, stop_html5_timer, start_html5_timer, attachOnPosition, onplay_called = false, onPositionItems = [], onPositionFired = 0, detachOnPosition, applyFromTo, lastURL = null, lastHTML5State, urlOmitted;
1413
1456
 
1414
1457
  lastHTML5State = {
1415
1458
  // tracks duration + position (time)
@@ -1441,6 +1484,9 @@ function SoundManager(smURL, smID) {
1441
1484
  // internal HTML5 Audio() object reference
1442
1485
  this._a = null;
1443
1486
 
1487
+ // for flash 8 special-case createSound() without url, followed by load/play with url case
1488
+ urlOmitted = (this.url ? false : true);
1489
+
1444
1490
  /**
1445
1491
  * SMSound() public methods
1446
1492
  * ------------------------
@@ -1497,6 +1543,18 @@ function SoundManager(smURL, smID) {
1497
1543
 
1498
1544
  sm2._wD(s.id + ': load (' + instanceOptions.url + ')');
1499
1545
 
1546
+ if (!instanceOptions.url && !s.url) {
1547
+ sm2._wD(s.id + ': load(): url is unassigned. Exiting.', 2);
1548
+ return s;
1549
+ }
1550
+
1551
+ // <d>
1552
+ if (!s.isHTML5 && fV === 8 && !s.url && !instanceOptions.autoPlay) {
1553
+ // flash 8 load() -> play() won't work before onload has fired.
1554
+ sm2._wD(s.id + ': Flash 8 load() limitation: Wait for onload() before calling play().', 1);
1555
+ }
1556
+ // </d>
1557
+
1500
1558
  if (instanceOptions.url === s.url && s.readyState !== 0 && s.readyState !== 2) {
1501
1559
  _wDS('onURL', 1);
1502
1560
  // if loaded and an onload() exists, fire immediately.
@@ -1548,7 +1606,8 @@ function SoundManager(smURL, smID) {
1548
1606
  // early HTML5 implementation (non-standard)
1549
1607
  s._a.autobuffer = 'auto';
1550
1608
 
1551
- // standard
1609
+ // standard property, values: none / metadata / auto
1610
+ // reference: http://msdn.microsoft.com/en-us/library/ie/ff974759%28v=vs.85%29.aspx
1552
1611
  s._a.preload = 'auto';
1553
1612
 
1554
1613
  s._a._called_load = true;
@@ -1565,6 +1624,17 @@ function SoundManager(smURL, smID) {
1565
1624
 
1566
1625
  } else {
1567
1626
 
1627
+ if (sm2.html5Only) {
1628
+ sm2._wD(s.id + ': No flash support. Exiting.');
1629
+ return s;
1630
+ }
1631
+
1632
+ if (s._iO.url && s._iO.url.match(/data\:/i)) {
1633
+ // data: URIs not supported by Flash, either.
1634
+ sm2._wD(s.id + ': data: URIs not supported via Flash. Exiting.');
1635
+ return s;
1636
+ }
1637
+
1568
1638
  try {
1569
1639
  s.isHTML5 = false;
1570
1640
  s._iO = policyFix(loopFix(instanceOptions));
@@ -1621,10 +1691,9 @@ function SoundManager(smURL, smID) {
1621
1691
  if (s._a) {
1622
1692
 
1623
1693
  s._a.pause();
1624
- html5Unload(s._a, emptyURL);
1625
1694
 
1626
1695
  // update empty URL, too
1627
- lastURL = emptyURL;
1696
+ lastURL = html5Unload(s._a);
1628
1697
 
1629
1698
  }
1630
1699
 
@@ -1674,7 +1743,6 @@ function SoundManager(smURL, smID) {
1674
1743
  if (!_bFromSM) {
1675
1744
  // ensure deletion from controller
1676
1745
  sm2.destroySound(s.id, true);
1677
-
1678
1746
  }
1679
1747
 
1680
1748
  };
@@ -1688,7 +1756,9 @@ function SoundManager(smURL, smID) {
1688
1756
 
1689
1757
  this.play = function(oOptions, _updatePlayState) {
1690
1758
 
1691
- var fN, allowMulti, a, onready, startOK = true,
1759
+ var fN, allowMulti, a, onready,
1760
+ audioClone, onended, oncanplay,
1761
+ startOK = true,
1692
1762
  exit = null;
1693
1763
 
1694
1764
  // <d>
@@ -1718,7 +1788,7 @@ function SoundManager(smURL, smID) {
1718
1788
  s.instanceOptions = s._iO;
1719
1789
 
1720
1790
  // RTMP-only
1721
- if (s._iO.serverURL && !s.connected) {
1791
+ if (!s.isHTML5 && s._iO.serverURL && !s.connected) {
1722
1792
  if (!s.getAutoPlay()) {
1723
1793
  sm2._wD(fN +' Netstream not connected yet - setting autoPlay');
1724
1794
  s.setAutoPlay(true);
@@ -1736,6 +1806,10 @@ function SoundManager(smURL, smID) {
1736
1806
  allowMulti = s._iO.multiShot;
1737
1807
  if (!allowMulti) {
1738
1808
  sm2._wD(fN + 'Already playing (one-shot)', 1);
1809
+ if (s.isHTML5) {
1810
+ // go back to original position.
1811
+ s.setPosition(s._iO.position);
1812
+ }
1739
1813
  exit = s;
1740
1814
  } else {
1741
1815
  sm2._wD(fN + 'Already playing (multi-shot)', 1);
@@ -1748,8 +1822,19 @@ function SoundManager(smURL, smID) {
1748
1822
 
1749
1823
  // edge case: play() with explicit URL parameter
1750
1824
  if (oOptions.url && oOptions.url !== s.url) {
1751
- // load using merged options
1752
- s.load(s._iO);
1825
+
1826
+ // special case for createSound() followed by load() / play() with url; avoid double-load case.
1827
+ if (!s.readyState && !s.isHTML5 && fV === 8 && urlOmitted) {
1828
+
1829
+ urlOmitted = false;
1830
+
1831
+ } else {
1832
+
1833
+ // load using merged options
1834
+ s.load(s._iO);
1835
+
1836
+ }
1837
+
1753
1838
  }
1754
1839
 
1755
1840
  if (!s.loaded) {
@@ -1759,13 +1844,22 @@ function SoundManager(smURL, smID) {
1759
1844
  sm2._wD(fN + 'Attempting to load');
1760
1845
 
1761
1846
  // try to get this sound playing ASAP
1762
- if (!s.isHTML5) {
1763
- // assign directly because setAutoPlay() increments the instanceCount
1847
+ if (!s.isHTML5 && !sm2.html5Only) {
1848
+
1849
+ // flash: assign directly because setAutoPlay() increments the instanceCount
1764
1850
  s._iO.autoPlay = true;
1765
1851
  s.load(s._iO);
1766
- } else {
1852
+
1853
+ } else if (s.isHTML5) {
1854
+
1767
1855
  // iOS needs this when recycling sounds, loading a new URL on an existing object.
1768
1856
  s.load(s._iO);
1857
+
1858
+ } else {
1859
+
1860
+ sm2._wD(fN + 'Unsupported type. Exiting.');
1861
+ exit = s;
1862
+
1769
1863
  }
1770
1864
 
1771
1865
  // HTML5 hack - re-set instanceOptions?
@@ -1865,9 +1959,10 @@ function SoundManager(smURL, smID) {
1865
1959
 
1866
1960
  }
1867
1961
 
1868
- sm2._wD(fN + 'Starting to play');
1962
+ // sm2._wD(fN + 'Starting to play');
1869
1963
 
1870
- if (!s.instanceCount || s._iO.multiShotEvents || (!s.isHTML5 && fV > 8 && !s.getAutoPlay())) {
1964
+ // increment instance counter, where enabled + supported
1965
+ if (!s.instanceCount || s._iO.multiShotEvents || (s.isHTML5 && s._iO.multiShot && !useGlobalHTML5Audio) || (!s.isHTML5 && fV > 8 && !s.getAutoPlay())) {
1871
1966
  s.instanceCount++;
1872
1967
  }
1873
1968
 
@@ -1895,13 +1990,13 @@ function SoundManager(smURL, smID) {
1895
1990
 
1896
1991
  if (!s.isHTML5) {
1897
1992
 
1898
- startOK = flash._start(s.id, s._iO.loops || 1, (fV === 9 ? s.position : s.position / 1000), s._iO.multiShot || false);
1993
+ startOK = flash._start(s.id, s._iO.loops || 1, (fV === 9 ? s.position : s.position / msecScale), s._iO.multiShot || false);
1899
1994
 
1900
1995
  if (fV === 9 && !startOK) {
1901
1996
  // edge case: no sound hardware, or 32-channel flash ceiling hit.
1902
1997
  // applies only to Flash 9, non-NetStream/MovieStar sounds.
1903
1998
  // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html#play%28%29
1904
- sm2._wD(fN + 'No sound hardware, or 32-sound ceiling hit');
1999
+ sm2._wD(fN + 'No sound hardware, or 32-sound ceiling hit', 2);
1905
2000
  if (s._iO.onplayerror) {
1906
2001
  s._iO.onplayerror.apply(s);
1907
2002
  }
@@ -1910,13 +2005,56 @@ function SoundManager(smURL, smID) {
1910
2005
 
1911
2006
  } else {
1912
2007
 
1913
- start_html5_timer();
2008
+ if (s.instanceCount < 2) {
1914
2009
 
1915
- a = s._setup_html5();
2010
+ // HTML5 single-instance case
1916
2011
 
1917
- s.setPosition(s._iO.position);
2012
+ start_html5_timer();
2013
+
2014
+ a = s._setup_html5();
2015
+
2016
+ s.setPosition(s._iO.position);
2017
+
2018
+ a.play();
2019
+
2020
+ } else {
1918
2021
 
1919
- a.play();
2022
+ // HTML5 multi-shot case
2023
+
2024
+ sm2._wD(s.id + ': Cloning Audio() for instance #' + s.instanceCount + '...');
2025
+
2026
+ audioClone = new Audio(s._iO.url);
2027
+
2028
+ onended = function() {
2029
+ event.remove(audioClone, 'onended', onended);
2030
+ s._onfinish(s);
2031
+ // cleanup
2032
+ html5Unload(audioClone);
2033
+ audioClone = null;
2034
+ };
2035
+
2036
+ oncanplay = function() {
2037
+ event.remove(audioClone, 'canplay', oncanplay);
2038
+ try {
2039
+ audioClone.currentTime = s._iO.position/msecScale;
2040
+ } catch(err) {
2041
+ complain(s.id + ': multiShot play() failed to apply position of ' + (s._iO.position/msecScale));
2042
+ }
2043
+ audioClone.play();
2044
+ };
2045
+
2046
+ event.add(audioClone, 'ended', onended);
2047
+
2048
+ if (s._iO.position) {
2049
+ // HTML5 audio can't seek before onplay() event has fired.
2050
+ // wait for canplay, then seek to position and start playback.
2051
+ event.add(audioClone, 'canplay', oncanplay);
2052
+ } else {
2053
+ // begin playback at currentTime: 0
2054
+ audioClone.play();
2055
+ }
2056
+
2057
+ }
1920
2058
 
1921
2059
  }
1922
2060
 
@@ -2059,21 +2197,20 @@ function SoundManager(smURL, smID) {
2059
2197
  nMsecOffset = 0;
2060
2198
  }
2061
2199
 
2062
- var original_pos,
2063
- position, position1K,
2200
+ var position, position1K,
2064
2201
  // Use the duration from the instance options, if we don't have a track duration yet.
2065
2202
  // position >= 0 and <= current available (loaded) duration
2066
2203
  offset = (s.isHTML5 ? Math.max(nMsecOffset, 0) : Math.min(s.duration || s._iO.duration, Math.max(nMsecOffset, 0)));
2067
2204
 
2068
- original_pos = s.position;
2069
2205
  s.position = offset;
2070
- position1K = s.position/1000;
2206
+ position1K = s.position/msecScale;
2071
2207
  s._resetOnPosition(s.position);
2072
2208
  s._iO.position = offset;
2073
2209
 
2074
2210
  if (!s.isHTML5) {
2075
2211
 
2076
2212
  position = (fV === 9 ? s.position : position1K);
2213
+
2077
2214
  if (s.readyState && s.readyState !== 2) {
2078
2215
  // if paused or not playing, will not resume (by playing)
2079
2216
  flash._setPosition(s.id, position, (s.paused || !s.playState), s._iO.multiShot);
@@ -2083,13 +2220,16 @@ function SoundManager(smURL, smID) {
2083
2220
 
2084
2221
  // Set the position in the canplay handler if the sound is not ready yet
2085
2222
  if (s._html5_canplay) {
2223
+
2086
2224
  if (s._a.currentTime !== position1K) {
2225
+
2087
2226
  /**
2088
2227
  * DOM/JS errors/exceptions to watch out for:
2089
2228
  * if seek is beyond (loaded?) position, "DOM exception 11"
2090
2229
  * "INDEX_SIZE_ERR": DOM exception 1
2091
2230
  */
2092
2231
  sm2._wD(s.id + ': setPosition('+position1K+')');
2232
+
2093
2233
  try {
2094
2234
  s._a.currentTime = position1K;
2095
2235
  if (s.playState === 0 || s.paused) {
@@ -2099,19 +2239,25 @@ function SoundManager(smURL, smID) {
2099
2239
  } catch(e) {
2100
2240
  sm2._wD(s.id + ': setPosition(' + position1K + ') failed: ' + e.message, 2);
2101
2241
  }
2242
+
2102
2243
  }
2103
- } else {
2104
- sm2._wD(s.id + ': setPosition(' + position1K + '): Cannot seek yet, sound not ready');
2105
- }
2106
2244
 
2107
- }
2245
+ } else if (position1K) {
2246
+
2247
+ // warn on non-zero seek attempts
2248
+ sm2._wD(s.id + ': setPosition(' + position1K + '): Cannot seek yet, sound not ready', 2);
2249
+ return s;
2250
+
2251
+ }
2108
2252
 
2109
- if (s.isHTML5) {
2110
2253
  if (s.paused) {
2254
+
2111
2255
  // if paused, refresh UI right away
2112
2256
  // force update
2113
2257
  s._onTimer(true);
2258
+
2114
2259
  }
2260
+
2115
2261
  }
2116
2262
 
2117
2263
  return s;
@@ -2211,7 +2357,7 @@ function SoundManager(smURL, smID) {
2211
2357
 
2212
2358
  if (s.playState === 0) {
2213
2359
  s.play({
2214
- position: (fV === 9 && !s.isHTML5 ? s.position : s.position / 1000)
2360
+ position: (fV === 9 && !s.isHTML5 ? s.position : s.position / msecScale)
2215
2361
  });
2216
2362
  return s;
2217
2363
  }
@@ -2655,7 +2801,7 @@ function SoundManager(smURL, smID) {
2655
2801
  // TODO: investigate why this goes wack if not set/re-set each time.
2656
2802
  s.durationEstimate = s.duration;
2657
2803
 
2658
- time = (s._a.currentTime * 1000 || 0);
2804
+ time = (s._a.currentTime * msecScale || 0);
2659
2805
 
2660
2806
  if (time !== lastHTML5State.time) {
2661
2807
 
@@ -2688,7 +2834,7 @@ function SoundManager(smURL, smID) {
2688
2834
 
2689
2835
  var instanceOptions = s._iO,
2690
2836
  // if audio object exists, use its duration - else, instance option duration (if provided - it's a hack, really, and should be retired) OR null
2691
- d = (s._a && s._a.duration ? s._a.duration*1000 : (instanceOptions && instanceOptions.duration ? instanceOptions.duration : null)),
2837
+ d = (s._a && s._a.duration ? s._a.duration*msecScale : (instanceOptions && instanceOptions.duration ? instanceOptions.duration : null)),
2692
2838
  result = (d && !isNaN(d) && d !== Infinity ? d : null);
2693
2839
 
2694
2840
  return result;
@@ -2897,7 +3043,7 @@ function SoundManager(smURL, smID) {
2897
3043
 
2898
3044
  // <d>
2899
3045
  fN = s.id + ': ';
2900
- sm2._wD(fN + (loadOK ? 'onload()' : 'Failed to load? - ' + s.url), (loadOK ? 1 : 2));
3046
+ sm2._wD(fN + (loadOK ? 'onload()' : 'Failed to load / invalid sound?' + (!s.duration ? ' Zero-length duration reported.' : ' -') + ' (' + s.url + ')'), (loadOK ? 1 : 2));
2901
3047
  if (!loadOK && !s.isHTML5) {
2902
3048
  if (sm2.sandbox.noRemote === true) {
2903
3049
  sm2._wD(fN + str('noNet'), 1);
@@ -3591,7 +3737,7 @@ function SoundManager(smURL, smID) {
3591
3737
  s._onbufferchange(0);
3592
3738
 
3593
3739
  // position according to instance options
3594
- position1K = (s._iO.position !== _undefined && !isNaN(s._iO.position)?s._iO.position/1000:null);
3740
+ position1K = (s._iO.position !== _undefined && !isNaN(s._iO.position)?s._iO.position/msecScale:null);
3595
3741
 
3596
3742
  // set the position if position was set before the sound loaded
3597
3743
  if (s.position && this.currentTime !== position1K) {
@@ -3644,6 +3790,14 @@ function SoundManager(smURL, smID) {
3644
3790
  error: html5_event(function() {
3645
3791
 
3646
3792
  sm2._wD(this._s.id + ': HTML5 error, code ' + this.error.code);
3793
+ /**
3794
+ * HTML5 error codes, per W3C
3795
+ * Error 1: Client aborted download at user's request.
3796
+ * Error 2: Network error after load started.
3797
+ * Error 3: Decoding issue.
3798
+ * Error 4: Media (audio file) not supported.
3799
+ * Reference: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#error-codes
3800
+ */
3647
3801
  // call load with error state?
3648
3802
  this._s._onload(false);
3649
3803
 
@@ -3678,7 +3832,7 @@ function SoundManager(smURL, smID) {
3678
3832
 
3679
3833
  play: html5_event(function() {
3680
3834
 
3681
- sm2._wD(this._s.id + ': play()');
3835
+ // sm2._wD(this._s.id + ': play()');
3682
3836
  // once play starts, no buffering
3683
3837
  this._s._onbufferchange(0);
3684
3838
 
@@ -3702,9 +3856,7 @@ function SoundManager(smURL, smID) {
3702
3856
  ranges = e.target.buffered,
3703
3857
  // firefox 3.6 implements e.loaded/total (bytes)
3704
3858
  loaded = (e.loaded||0),
3705
- total = (e.total||1),
3706
- // HTML5 returns msec. SM2 API uses seconds for setPosition() etc., whether Flash or HTML5.
3707
- scale = 1000;
3859
+ total = (e.total||1);
3708
3860
 
3709
3861
  // reset the "buffered" (loaded byte ranges) array
3710
3862
  s.buffered = [];
@@ -3715,25 +3867,26 @@ function SoundManager(smURL, smID) {
3715
3867
  // https://developer.mozilla.org/en/DOM/TimeRanges
3716
3868
 
3717
3869
  // re-build "buffered" array
3870
+ // HTML5 returns seconds. SM2 API uses msec for setPosition() etc., whether Flash or HTML5.
3718
3871
  for (i=0, j=ranges.length; i<j; i++) {
3719
3872
  s.buffered.push({
3720
- 'start': ranges.start(i) * scale,
3721
- 'end': ranges.end(i) * scale
3873
+ 'start': ranges.start(i) * msecScale,
3874
+ 'end': ranges.end(i) * msecScale
3722
3875
  });
3723
3876
  }
3724
3877
 
3725
3878
  // use the last value locally
3726
- buffered = (ranges.end(0) - ranges.start(0)) * scale;
3879
+ buffered = (ranges.end(0) - ranges.start(0)) * msecScale;
3727
3880
 
3728
3881
  // linear case, buffer sum; does not account for seeking and HTTP partials / byte ranges
3729
- loaded = buffered/(e.target.duration*scale);
3882
+ loaded = Math.min(1, buffered/(e.target.duration*msecScale));
3730
3883
 
3731
3884
  // <d>
3732
3885
  if (isProgress && ranges.length > 1) {
3733
3886
  str = [];
3734
3887
  j = ranges.length;
3735
3888
  for (i=0; i<j; i++) {
3736
- str.push(e.target.buffered.start(i)*scale +'-'+ e.target.buffered.end(i)*scale);
3889
+ str.push(e.target.buffered.start(i)*msecScale +'-'+ e.target.buffered.end(i)*msecScale);
3737
3890
  }
3738
3891
  sm2._wD(this._s.id + ': progress, timeRanges: ' + str.join(', '));
3739
3892
  }
@@ -3809,15 +3962,20 @@ function SoundManager(smURL, smID) {
3809
3962
 
3810
3963
  var result;
3811
3964
 
3812
- if (iO.serverURL || (iO.type && preferFlashCheck(iO.type))) {
3965
+ if (!iO || (!iO.type && !iO.url && !iO.serverURL)) {
3966
+
3967
+ // nothing to check
3968
+ result = false;
3969
+
3970
+ } else if (iO.serverURL || (iO.type && preferFlashCheck(iO.type))) {
3813
3971
 
3814
3972
  // RTMP, or preferring flash
3815
3973
  result = false;
3816
3974
 
3817
3975
  } else {
3818
3976
 
3819
- // Use type, if specified. If HTML5-only mode, no other options, so just give 'er
3820
- result = ((iO.type ? html5CanPlay({type:iO.type}) : html5CanPlay({url:iO.url}) || sm2.html5Only));
3977
+ // Use type, if specified. Pass data: URIs to HTML5. If HTML5-only mode, no other options, so just give 'er
3978
+ result = ((iO.type ? html5CanPlay({type:iO.type}) : html5CanPlay({url:iO.url}) || sm2.html5Only || iO.url.match(/data\:/i)));
3821
3979
 
3822
3980
  }
3823
3981
 
@@ -3825,7 +3983,7 @@ function SoundManager(smURL, smID) {
3825
3983
 
3826
3984
  };
3827
3985
 
3828
- html5Unload = function(oAudio, url) {
3986
+ html5Unload = function(oAudio) {
3829
3987
 
3830
3988
  /**
3831
3989
  * Internal method: Unload media, and cancel any current/pending network requests.
@@ -3835,13 +3993,19 @@ function SoundManager(smURL, smID) {
3835
3993
  * Other UA behaviour is unclear, so everyone else gets an about:blank-style URL.
3836
3994
  */
3837
3995
 
3996
+ var url;
3997
+
3838
3998
  if (oAudio) {
3839
3999
 
3840
- // Firefox likes '' for unload (used to work?) - however, may request hosting page URL (bad.) Most other UAs dislike '' and fail to unload.
4000
+ // Firefox likes '' for unload (used to work, but no longer?) - however, may request hosting page URL (bad.) Most other UAs dislike '' and fail to unload.
4001
+ url = (isSafari && !is_iDevice ? null : (isFirefox ? emptyURL : null));
4002
+
3841
4003
  oAudio.src = url;
3842
4004
 
3843
4005
  // reset some state, too
3844
- oAudio._called_load = false;
4006
+ if (oAudio._called_unload !== undefined) {
4007
+ oAudio._called_load = false;
4008
+ }
3845
4009
 
3846
4010
  }
3847
4011
 
@@ -3852,6 +4016,8 @@ function SoundManager(smURL, smID) {
3852
4016
 
3853
4017
  }
3854
4018
 
4019
+ return url;
4020
+
3855
4021
  };
3856
4022
 
3857
4023
  html5CanPlay = function(o) {
@@ -3935,6 +4101,9 @@ function SoundManager(smURL, smID) {
3935
4101
  */
3936
4102
 
3937
4103
  if (!sm2.useHTML5Audio || !sm2.hasHTML5) {
4104
+ // without HTML5, we need Flash.
4105
+ sm2.html5.usingFlash = true;
4106
+ needsFlash = true;
3938
4107
  return false;
3939
4108
  }
3940
4109
 
@@ -4022,6 +4191,9 @@ function SoundManager(smURL, smID) {
4022
4191
  support.canPlayType = (a?cp:null);
4023
4192
  sm2.html5 = mixin(sm2.html5, support);
4024
4193
 
4194
+ sm2.html5.usingFlash = featureCheck();
4195
+ needsFlash = sm2.html5.usingFlash;
4196
+
4025
4197
  return true;
4026
4198
 
4027
4199
  };
@@ -4041,7 +4213,7 @@ function SoundManager(smURL, smID) {
4041
4213
  waitForever: smc + 'Waiting indefinitely for Flash (will recover if unblocked)...',
4042
4214
  waitSWF: smc + 'Waiting for 100% SWF load...',
4043
4215
  needFunction: smc + 'Function object expected for %s',
4044
- badID: 'Warning: Sound ID "%s" should be a string, starting with a non-numeric character',
4216
+ badID: 'Sound ID "%s" should be a string, starting with a non-numeric character',
4045
4217
  currentObj: smc + '_debug(): Current sound objects',
4046
4218
  waitOnload: smc + 'Waiting for window.onload()',
4047
4219
  docLoaded: smc + 'Document already loaded',
@@ -4055,7 +4227,6 @@ function SoundManager(smURL, smID) {
4055
4227
  smError: 'SMSound.load(): Exception: JS-Flash communication failed, or JS error.',
4056
4228
  fbTimeout: 'No flash response, applying .'+swfCSS.swfTimedout+' CSS...',
4057
4229
  fbLoaded: 'Flash loaded',
4058
- flRemoved: smc + 'Flash movie removed.',
4059
4230
  fbHandler: smc + 'flashBlockHandler()',
4060
4231
  manURL: 'SMSound.load(): Using manually-assigned URL',
4061
4232
  onURL: sm + '.load(): current URL already assigned.',
@@ -4130,7 +4301,7 @@ function SoundManager(smURL, smID) {
4130
4301
  complain = function(sMsg) {
4131
4302
 
4132
4303
  // <d>
4133
- if (console !== _undefined && console.warn !== _undefined) {
4304
+ if (hasConsole && console.warn !== _undefined) {
4134
4305
  console.warn(sMsg);
4135
4306
  } else {
4136
4307
  sm2._wD(sMsg);
@@ -4260,11 +4431,11 @@ function SoundManager(smURL, smID) {
4260
4431
  // starts debug mode, creating output <div> for UAs without console object
4261
4432
 
4262
4433
  // allow force of debug mode via URL
4434
+ // <d>
4263
4435
  if (sm2.debugURLParam.test(wl)) {
4264
4436
  sm2.debugMode = true;
4265
4437
  }
4266
4438
 
4267
- // <d>
4268
4439
  if (id(sm2.debugID)) {
4269
4440
  return false;
4270
4441
  }
@@ -4368,6 +4539,7 @@ function SoundManager(smURL, smID) {
4368
4539
  sm2Debugger.handleEvent(sEventType, bSuccess, sMessage);
4369
4540
  } catch(e) {
4370
4541
  // oh well
4542
+ return false;
4371
4543
  }
4372
4544
  }
4373
4545
 
@@ -4406,6 +4578,7 @@ function SoundManager(smURL, smID) {
4406
4578
  error = {type:'FLASHBLOCK'};
4407
4579
 
4408
4580
  if (sm2.html5Only) {
4581
+ // no flash, or unused
4409
4582
  return false;
4410
4583
  }
4411
4584
 
@@ -4564,6 +4737,7 @@ function SoundManager(smURL, smID) {
4564
4737
  obj = new AX('ShockwaveFlash.ShockwaveFlash');
4565
4738
  } catch(e) {
4566
4739
  // oh well
4740
+ obj = null;
4567
4741
  }
4568
4742
  hasPlugin = (!!obj);
4569
4743
  // cleanup, because it is ActiveX after all
@@ -4578,9 +4752,8 @@ function SoundManager(smURL, smID) {
4578
4752
 
4579
4753
  featureCheck = function() {
4580
4754
 
4581
- var needsFlash,
4755
+ var flashNeeded,
4582
4756
  item,
4583
- result = true,
4584
4757
  formats = sm2.audioFormats,
4585
4758
  // iPhone <= 3.1 has broken HTML5 audio(), but firmware 3.2 (original iPad) + iOS4 works.
4586
4759
  isSpecial = (is_iDevice && !!(ua.match(/os (1|2|3_0|3_1)/i)));
@@ -4593,12 +4766,11 @@ function SoundManager(smURL, smID) {
4593
4766
  // ignore flash case, however
4594
4767
  sm2.html5Only = true;
4595
4768
 
4769
+ // hide the SWF, if present
4596
4770
  if (sm2.oMC) {
4597
4771
  sm2.oMC.style.display = 'none';
4598
4772
  }
4599
4773
 
4600
- result = false;
4601
-
4602
4774
  } else {
4603
4775
 
4604
4776
  if (sm2.useHTML5Audio) {
@@ -4620,11 +4792,22 @@ function SoundManager(smURL, smID) {
4620
4792
 
4621
4793
  if (sm2.useHTML5Audio && sm2.hasHTML5) {
4622
4794
 
4795
+ // sort out whether flash is optional, required or can be ignored.
4796
+
4797
+ // innocent until proven guilty.
4798
+ canIgnoreFlash = true;
4799
+
4623
4800
  for (item in formats) {
4624
4801
  if (formats.hasOwnProperty(item)) {
4625
- if ((formats[item].required && !sm2.html5.canPlayType(formats[item].type)) || (sm2.preferFlash && (sm2.flash[item] || sm2.flash[formats[item].type]))) {
4626
- // flash may be required, or preferred for this format
4627
- needsFlash = true;
4802
+ if (formats[item].required) {
4803
+ if (!sm2.html5.canPlayType(formats[item].type)) {
4804
+ // 100% HTML5 mode is not possible.
4805
+ canIgnoreFlash = false;
4806
+ flashNeeded = true;
4807
+ } else if (sm2.preferFlash && (sm2.flash[item] || sm2.flash[formats[item].type])) {
4808
+ // flash may be required, or preferred for this format.
4809
+ flashNeeded = true;
4810
+ }
4628
4811
  }
4629
4812
  }
4630
4813
  }
@@ -4633,10 +4816,11 @@ function SoundManager(smURL, smID) {
4633
4816
 
4634
4817
  // sanity check...
4635
4818
  if (sm2.ignoreFlash) {
4636
- needsFlash = false;
4819
+ flashNeeded = false;
4820
+ canIgnoreFlash = true;
4637
4821
  }
4638
4822
 
4639
- sm2.html5Only = (sm2.hasHTML5 && sm2.useHTML5Audio && !needsFlash);
4823
+ sm2.html5Only = (sm2.hasHTML5 && sm2.useHTML5Audio && !flashNeeded);
4640
4824
 
4641
4825
  return (!sm2.html5Only);
4642
4826
 
@@ -4847,10 +5031,9 @@ function SoundManager(smURL, smID) {
4847
5031
 
4848
5032
  };
4849
5033
 
4850
- this._externalInterfaceOK = function(flashDate, swfVersion) {
5034
+ this._externalInterfaceOK = function(swfVersion) {
4851
5035
 
4852
5036
  // flash callback confirming flash loaded, EI working etc.
4853
- // flashDate = approx. timing/delay info for JS/flash bridge
4854
5037
  // swfVersion: SWF build string
4855
5038
 
4856
5039
  if (sm2.swfLoaded) {
@@ -4885,7 +5068,7 @@ function SoundManager(smURL, smID) {
4885
5068
  }
4886
5069
  // </d>
4887
5070
 
4888
- // slight delay before init
5071
+ // IE needs a larger timeout
4889
5072
  setTimeout(init, isIE ? 100 : 1);
4890
5073
 
4891
5074
  };
@@ -5283,26 +5466,69 @@ function SoundManager(smURL, smID) {
5283
5466
  // give up / time-out, depending
5284
5467
 
5285
5468
  if (!didInit && okToDisable) {
5469
+
5286
5470
  if (p === null) {
5471
+
5287
5472
  // SWF failed. Maybe blocked.
5473
+
5288
5474
  if (sm2.useFlashBlock || sm2.flashLoadTimeout === 0) {
5475
+
5289
5476
  if (sm2.useFlashBlock) {
5477
+
5290
5478
  flashBlockHandler();
5479
+
5291
5480
  }
5481
+
5292
5482
  _wDS('waitForever');
5483
+
5293
5484
  } else {
5485
+
5294
5486
  // no custom flash block handling, but SWF has timed out. Will recover if user unblocks / allows SWF load.
5295
- _wDS('waitForever');
5296
- // fire any regular registered ontimeout() listeners.
5297
- processOnEvents({type:'ontimeout', ignoreInit: true});
5487
+
5488
+ if (!sm2.useFlashBlock && canIgnoreFlash) {
5489
+
5490
+ // special case: try for a reboot with preferFlash: false, if 100% HTML5 mode is possible and useFlashBlock is not enabled.
5491
+
5492
+ window.setTimeout(function() {
5493
+
5494
+ complain(smc + 'useFlashBlock is false, 100% HTML5 mode is possible. Rebooting with preferFlash: false...');
5495
+
5496
+ sm2.setup({
5497
+ preferFlash: false
5498
+ }).reboot();
5499
+
5500
+ // if for some reason you want to detect this case, use an ontimeout() callback and look for html5Only and didFlashBlock == true.
5501
+ sm2.didFlashBlock = true;
5502
+
5503
+ sm2.beginDelayedInit();
5504
+
5505
+ }, 1);
5506
+
5507
+ } else {
5508
+
5509
+ _wDS('waitForever');
5510
+
5511
+ // fire any regular registered ontimeout() listeners.
5512
+ processOnEvents({type:'ontimeout', ignoreInit: true});
5513
+
5514
+ }
5515
+
5298
5516
  }
5517
+
5299
5518
  } else {
5519
+
5300
5520
  // flash loaded? Shouldn't be a blocking issue, then.
5521
+
5301
5522
  if (sm2.flashLoadTimeout === 0) {
5302
- _wDS('waitForever');
5523
+
5524
+ _wDS('waitForever');
5525
+
5303
5526
  } else {
5527
+
5304
5528
  failSafely(true);
5529
+
5305
5530
  }
5531
+
5306
5532
  }
5307
5533
  }
5308
5534
 
@@ -5362,7 +5588,7 @@ function SoundManager(smURL, smID) {
5362
5588
  if (sm2.useHTML5Audio && sm2.hasHTML5) {
5363
5589
  for (item in sm2.audioFormats) {
5364
5590
  if (sm2.audioFormats.hasOwnProperty(item)) {
5365
- tests.push(item + ' = ' + sm2.html5[item] + (!sm2.html5[item] && hasFlash && sm2.flash[item] ? ' (using flash)' : (sm2.preferFlash && sm2.flash[item] && hasFlash ? ' (preferring flash)': (!sm2.html5[item] ? ' (' + (sm2.audioFormats[item].required ? 'required, ':'') + 'and no flash support)' : ''))));
5591
+ tests.push(item + ' = ' + sm2.html5[item] + (!sm2.html5[item] && needsFlash && sm2.flash[item] ? ' (using flash)' : (sm2.preferFlash && sm2.flash[item] && needsFlash ? ' (preferring flash)': (!sm2.html5[item] ? ' (' + (sm2.audioFormats[item].required ? 'required, ':'') + 'and no flash support)' : ''))));
5366
5592
  }
5367
5593
  }
5368
5594
  sm2._wD('SoundManager 2 HTML5 support: ' + tests.join(', '), 1);
@@ -5559,12 +5785,11 @@ function SoundManager(smURL, smID) {
5559
5785
  a2 = 'sm2-preferflash=',
5560
5786
  b = null,
5561
5787
  b2 = null,
5562
- hasCon = (window.console !== _undefined && typeof console.log === 'function'),
5563
5788
  l = wl.toLowerCase();
5564
5789
 
5565
5790
  if (l.indexOf(a) !== -1) {
5566
5791
  b = (l.charAt(l.indexOf(a)+a.length) === '1');
5567
- if (hasCon) {
5792
+ if (hasConsole) {
5568
5793
  console.log((b?'Enabling ':'Disabling ')+'useHTML5Audio via URL parameter');
5569
5794
  }
5570
5795
  sm2.setup({
@@ -5574,7 +5799,7 @@ function SoundManager(smURL, smID) {
5574
5799
 
5575
5800
  if (l.indexOf(a2) !== -1) {
5576
5801
  b2 = (l.charAt(l.indexOf(a2)+a2.length) === '1');
5577
- if (hasCon) {
5802
+ if (hasConsole) {
5578
5803
  console.log((b2?'Enabling ':'Disabling ')+'preferFlash via URL parameter');
5579
5804
  }
5580
5805
  sm2.setup({
@@ -5596,8 +5821,6 @@ function SoundManager(smURL, smID) {
5596
5821
  }
5597
5822
 
5598
5823
  testHTML5();
5599
- sm2.html5.usingFlash = featureCheck();
5600
- needsFlash = sm2.html5.usingFlash;
5601
5824
 
5602
5825
  if (!hasFlash && needsFlash) {
5603
5826
  messages.push(strings.needFlash);