]>
Commit | Line | Data |
---|---|---|
127631e0 CP |
1 | /*!\r |
2 | SoundManager 2: Javascript Sound for the Web\r | |
3 | --------------------------------------------\r | |
4 | http://schillmania.com/projects/soundmanager2/\r | |
5 | \r | |
6 | Copyright (c) 2008, Scott Schiller. All rights reserved.\r | |
7 | Code licensed under the BSD License:\r | |
8 | http://schillmania.com/projects/soundmanager2/license.txt\r | |
9 | \r | |
86f67adc | 10 | V2.95a.20090501\r |
127631e0 CP |
11 | */\r |
12 | \r | |
5ad04c7b CP |
13 | var soundManager = null;\r |
14 | \r | |
127631e0 CP |
15 | function SoundManager(smURL,smID) {\r |
16 | \r | |
17 | this.flashVersion = 8; // version of flash to require, either 8 or 9. Some API features require Flash 9.\r | |
18 | this.debugMode = true; // enable debugging output (div#soundmanager-debug, OR console if available + configured)\r | |
19 | this.useConsole = true; // use firebug/safari console.log()-type debug console if available\r | |
20 | this.consoleOnly = false; // if console is being used, do not create/write to #soundmanager-debug\r | |
21 | this.waitForWindowLoad = false; // force SM2 to wait for window.onload() before trying to call soundManager.onload()\r | |
22 | this.nullURL = 'null.mp3'; // path to "null" (empty) MP3 file, used to unload sounds (Flash 8 only)\r | |
23 | this.allowPolling = true; // allow flash to poll for status update (required for "while playing", peak, sound spectrum functions to work.)\r | |
24 | this.useMovieStar = false; // enable support for Flash 9.0r115+ (codename "MovieStar") MPEG4 audio + video formats (AAC, M4V, FLV, MOV etc.)\r | |
86f67adc CP |
25 | this.bgColor = '#ffffff'; // movie (.swf) background color, '#000000' useful if showing on-screen/full-screen video etc.\r |
26 | this.useHighPerformance = false; // position:fixed flash movie gives increased js/flash speed\r | |
27 | this.flashLoadTimeout = 750; // ms to wait for flash movie to load before failing (0 = infinity)\r | |
28 | this.wmode = null; // mode to render the flash movie in - null, transparent, opaque (last two allow layering of HTML on top)\r | |
29 | this.allowFullScreen = true; // enter full-screen (via double-click on movie) for flash 9+ video\r | |
127631e0 CP |
30 | \r |
31 | this.defaultOptions = {\r | |
32 | 'autoLoad': false, // enable automatic loading (otherwise .load() will be called on demand with .play(), the latter being nicer on bandwidth - if you want to .load yourself, you also can)\r | |
33 | 'stream': true, // allows playing before entire file has loaded (recommended)\r | |
34 | 'autoPlay': false, // enable playing of file as soon as possible (much faster if "stream" is true)\r | |
35 | 'onid3': null, // callback function for "ID3 data is added/available"\r | |
36 | 'onload': null, // callback function for "load finished"\r | |
37 | 'whileloading': null, // callback function for "download progress update" (X of Y bytes received)\r | |
38 | 'onplay': null, // callback for "play" start\r | |
39 | 'onpause': null, // callback for "pause"\r | |
40 | 'onresume': null, // callback for "resume" (pause toggle)\r | |
41 | 'whileplaying': null, // callback during play (position update)\r | |
42 | 'onstop': null, // callback for "user stop"\r | |
43 | 'onfinish': null, // callback function for "sound finished playing"\r | |
44 | 'onbeforefinish': null, // callback for "before sound finished playing (at [time])"\r | |
45 | 'onbeforefinishtime': 5000, // offset (milliseconds) before end of sound to trigger beforefinish (eg. 1000 msec = 1 second)\r | |
46 | 'onbeforefinishcomplete':null, // function to call when said sound finishes playing\r | |
47 | 'onjustbeforefinish':null, // callback for [n] msec before end of current sound\r | |
48 | 'onjustbeforefinishtime':200, // [n] - if not using, set to 0 (or null handler) and event will not fire.\r | |
49 | 'multiShot': true, // let sounds "restart" or layer on top of each other when played multiple times, rather than one-shot/one at a time\r | |
50 | 'position': null, // offset (milliseconds) to seek to within loaded sound data.\r | |
51 | 'pan': 0, // "pan" settings, left-to-right, -100 to 100\r | |
52 | 'volume': 100 // self-explanatory. 0-100, the latter being the max.\r | |
53 | };\r | |
54 | \r | |
55 | this.flash9Options = { // flash 9-only options, merged into defaultOptions if flash 9 is being used\r | |
86f67adc | 56 | 'isMovieStar': null, // "MovieStar" MPEG4 audio/video mode. Null (default) = auto detect MP4, AAC etc. based on URL. true = force on, ignore URL\r |
127631e0 CP |
57 | 'usePeakData': false, // enable left/right channel peak (level) data\r |
58 | 'useWaveformData': false, // enable sound spectrum (raw waveform data) - WARNING: CPU-INTENSIVE: may set CPUs on fire.\r | |
86f67adc CP |
59 | 'useEQData': false, // enable sound EQ (frequency spectrum data) - WARNING: Also CPU-intensive.\r |
60 | 'onbufferchange': null, // callback for "isBuffering" property change\r | |
61 | 'ondataerror': null // callback for waveform/eq data access error (flash playing audio in other tabs/domains)\r | |
127631e0 CP |
62 | };\r |
63 | \r | |
64 | this.movieStarOptions = { // flash 9.0r115+ MPEG4 audio/video options, merged into defaultOptions if flash 9 + movieStar mode is enabled\r | |
86f67adc CP |
65 | 'onmetadata': null, // callback for when video width/height etc. are received\r |
66 | 'useVideo': false, // if loading movieStar content, whether to show video\r | |
67 | 'bufferTime': null // seconds of data to buffer before playback begins (null = flash default of 0.1 seconds - if AAC playback is gappy, try up to 3 seconds)\r | |
127631e0 CP |
68 | };\r |
69 | \r | |
5ad04c7b | 70 | // jslint global declarations\r |
86f67adc | 71 | /*global SM2_DEFER, sm2Debugger, alert, console, document, navigator, setTimeout, window */\r |
5ad04c7b CP |
72 | \r |
73 | var SMSound = null; // defined later\r | |
74 | \r | |
75 | var _s = this;\r | |
127631e0 | 76 | this.version = null;\r |
86f67adc | 77 | this.versionNumber = 'V2.95a.20090501';\r |
127631e0 CP |
78 | this.movieURL = null;\r |
79 | this.url = null;\r | |
80 | this.altURL = null;\r | |
81 | this.swfLoaded = false;\r | |
82 | this.enabled = false;\r | |
83 | this.o = null;\r | |
84 | this.id = (smID||'sm2movie');\r | |
85 | this.oMC = null;\r | |
5ad04c7b | 86 | this.sounds = {};\r |
127631e0 CP |
87 | this.soundIDs = [];\r |
88 | this.muted = false;\r | |
86f67adc | 89 | this.isFullScreen = false; // set later by flash 9+\r |
127631e0 CP |
90 | this.isIE = (navigator.userAgent.match(/MSIE/i));\r |
91 | this.isSafari = (navigator.userAgent.match(/safari/i));\r | |
92 | this.isGecko = (navigator.userAgent.match(/gecko/i));\r | |
93 | this.debugID = 'soundmanager-debug';\r | |
86f67adc | 94 | this.specialWmodeCase = false;\r |
127631e0 CP |
95 | this._debugOpen = true;\r |
96 | this._didAppend = false;\r | |
97 | this._appendSuccess = false;\r | |
98 | this._didInit = false;\r | |
99 | this._disabled = false;\r | |
100 | this._windowLoaded = false;\r | |
101 | this._hasConsole = (typeof console != 'undefined' && typeof console.log != 'undefined');\r | |
102 | this._debugLevels = ['log','info','warn','error'];\r | |
103 | this._defaultFlashVersion = 8;\r | |
86f67adc CP |
104 | this._oRemoved = null;\r |
105 | this._oRemovedHTML = null;\r | |
106 | \r | |
107 | var _$ = function(sID) {\r | |
108 | return document.getElementById(sID);\r | |
109 | };\r | |
5ad04c7b | 110 | \r |
127631e0 | 111 | this.filePatterns = {\r |
5ad04c7b CP |
112 | flash8: /\.mp3(\?.*)?$/i,\r |
113 | flash9: /\.mp3(\?.*)?$/i\r | |
127631e0 | 114 | };\r |
5ad04c7b | 115 | \r |
127631e0 | 116 | this.netStreamTypes = ['aac','flv','mov','mp4','m4v','f4v','m4a','mp4v','3gp','3g2']; // Flash v9.0r115+ "moviestar" formats\r |
5ad04c7b CP |
117 | this.netStreamPattern = new RegExp('\\.('+this.netStreamTypes.join('|')+')(\\?.*)?$','i');\r |
118 | \r | |
127631e0 CP |
119 | this.filePattern = null;\r |
120 | this.features = {\r | |
86f67adc | 121 | buffering: false,\r |
127631e0 CP |
122 | peakData: false,\r |
123 | waveformData: false,\r | |
5ad04c7b CP |
124 | eqData: false,\r |
125 | movieStar: false\r | |
127631e0 CP |
126 | };\r |
127 | \r | |
128 | this.sandbox = {\r | |
129 | 'type': null,\r | |
130 | 'types': {\r | |
131 | 'remote': 'remote (domain-based) rules',\r | |
132 | 'localWithFile': 'local with file access (no internet access)',\r | |
133 | 'localWithNetwork': 'local with network (internet access only, no local access)',\r | |
134 | 'localTrusted': 'local, trusted (local + internet access)'\r | |
135 | },\r | |
136 | 'description': null,\r | |
137 | 'noRemote': null,\r | |
138 | 'noLocal': null\r | |
139 | };\r | |
140 | \r | |
141 | this._setVersionInfo = function() {\r | |
142 | if (_s.flashVersion != 8 && _s.flashVersion != 9) {\r | |
143 | alert('soundManager.flashVersion must be 8 or 9. "'+_s.flashVersion+'" is invalid. Reverting to '+_s._defaultFlashVersion+'.');\r | |
144 | _s.flashVersion = _s._defaultFlashVersion;\r | |
145 | }\r | |
146 | _s.version = _s.versionNumber+(_s.flashVersion==9?' (AS3/Flash 9)':' (AS2/Flash 8)');\r | |
147 | // set up default options\r | |
148 | if (_s.flashVersion > 8) {\r | |
149 | _s.defaultOptions = _s._mergeObjects(_s.defaultOptions,_s.flash9Options);\r | |
86f67adc | 150 | _s.features.buffering = true;\r |
127631e0 CP |
151 | }\r |
152 | if (_s.flashVersion > 8 && _s.useMovieStar) {\r | |
5ad04c7b | 153 | // flash 9+ support for movieStar formats as well as MP3\r |
127631e0 | 154 | _s.defaultOptions = _s._mergeObjects(_s.defaultOptions,_s.movieStarOptions);\r |
5ad04c7b CP |
155 | _s.filePatterns.flash9 = new RegExp('\\.(mp3|'+_s.netStreamTypes.join('|')+')(\\?.*)?$','i');\r |
156 | _s.features.movieStar = true;\r | |
127631e0 | 157 | } else {\r |
5ad04c7b CP |
158 | _s.useMovieStar = false;\r |
159 | _s.features.movieStar = false;\r | |
127631e0 CP |
160 | }\r |
161 | _s.filePattern = _s.filePatterns[(_s.flashVersion!=8?'flash9':'flash8')];\r | |
162 | _s.movieURL = (_s.flashVersion==8?'soundmanager2.swf':'soundmanager2_flash9.swf');\r | |
86f67adc | 163 | _s.features.peakData = _s.features.waveformData = _s.features.eqData = (_s.flashVersion>8);\r |
5ad04c7b | 164 | };\r |
127631e0 CP |
165 | \r |
166 | this._overHTTP = (document.location?document.location.protocol.match(/http/i):null);\r | |
167 | this._waitingforEI = false;\r | |
168 | this._initPending = false;\r | |
169 | this._tryInitOnFocus = (this.isSafari && typeof document.hasFocus == 'undefined');\r | |
170 | this._isFocused = (typeof document.hasFocus != 'undefined'?document.hasFocus():null);\r | |
171 | this._okToDisable = !this._tryInitOnFocus;\r | |
172 | \r | |
173 | this.useAltURL = !this._overHTTP; // use altURL if not "online"\r | |
174 | \r | |
175 | var flashCPLink = 'http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html';\r | |
176 | \r | |
86f67adc CP |
177 | this.strings = {\r |
178 | notReady: 'Not loaded yet - wait for soundManager.onload() before calling sound-related methods',\r | |
179 | appXHTML: 'soundManager._createMovie(): appendChild/innerHTML set failed. May be app/xhtml+xml DOM-related.'\r | |
180 | };\r | |
181 | \r | |
127631e0 CP |
182 | // --- public methods ---\r |
183 | \r | |
184 | this.supported = function() {\r | |
185 | return (_s._didInit && !_s._disabled);\r | |
186 | };\r | |
187 | \r | |
188 | this.getMovie = function(smID) {\r | |
86f67adc | 189 | return _s.isIE?window[smID]:(_s.isSafari?_$(smID)||document[smID]:_$(smID));\r |
127631e0 CP |
190 | };\r |
191 | \r | |
192 | this.loadFromXML = function(sXmlUrl) {\r | |
193 | try {\r | |
194 | _s.o._loadFromXML(sXmlUrl);\r | |
195 | } catch(e) {\r | |
196 | _s._failSafely();\r | |
197 | return true;\r | |
5ad04c7b | 198 | }\r |
127631e0 CP |
199 | };\r |
200 | \r | |
201 | this.createSound = function(oOptions) {\r | |
5ad04c7b | 202 | if (!_s._didInit) {\r |
86f67adc | 203 | throw _s._complain('soundManager.createSound(): '+_s.strings.notReady,arguments.callee.caller);\r |
5ad04c7b CP |
204 | }\r |
205 | if (arguments.length == 2) {\r | |
127631e0 | 206 | // function overloading in JS! :) ..assume simple createSound(id,url) use case\r |
5ad04c7b CP |
207 | oOptions = {'id':arguments[0],'url':arguments[1]};\r |
208 | }\r | |
127631e0 CP |
209 | var thisOptions = _s._mergeObjects(oOptions); // inherit SM2 defaults\r |
210 | var _tO = thisOptions; // alias\r | |
211 | _s._wD('soundManager.createSound(): '+_tO.id+' ('+_tO.url+')',1);\r | |
212 | if (_s._idCheck(_tO.id,true)) {\r | |
213 | _s._wD('soundManager.createSound(): '+_tO.id+' exists',1);\r | |
214 | return _s.sounds[_tO.id];\r | |
5ad04c7b | 215 | }\r |
127631e0 | 216 | if (_s.flashVersion > 8 && _s.useMovieStar) {\r |
5ad04c7b | 217 | if (_tO.isMovieStar === null) {\r |
127631e0 CP |
218 | _tO.isMovieStar = (_tO.url.match(_s.netStreamPattern)?true:false);\r |
219 | }\r | |
220 | if (_tO.isMovieStar) {\r | |
221 | _s._wD('soundManager.createSound(): using MovieStar handling');\r | |
222 | }\r | |
223 | if (_tO.isMovieStar && (_tO.usePeakData || _tO.useWaveformData || _tO.useEQData)) {\r | |
224 | _s._wD('Warning: peak/waveform/eqData features unsupported for non-MP3 formats');\r | |
225 | _tO.usePeakData = false;\r | |
226 | _tO.useWaveformData = false;\r | |
227 | _tO.useEQData = false;\r | |
228 | }\r | |
5ad04c7b | 229 | }\r |
127631e0 CP |
230 | _s.sounds[_tO.id] = new SMSound(_tO);\r |
231 | _s.soundIDs[_s.soundIDs.length] = _tO.id;\r | |
232 | // AS2:\r | |
233 | if (_s.flashVersion == 8) {\r | |
234 | _s.o._createSound(_tO.id,_tO.onjustbeforefinishtime);\r | |
235 | } else {\r | |
86f67adc | 236 | _s.o._createSound(_tO.id,_tO.url,_tO.onjustbeforefinishtime,_tO.usePeakData,_tO.useWaveformData,_tO.useEQData,_tO.isMovieStar,(_tO.isMovieStar?_tO.useVideo:false),(_tO.isMovieStar?_tO.bufferTime:false));\r |
5ad04c7b | 237 | }\r |
127631e0 | 238 | if (_tO.autoLoad || _tO.autoPlay) {\r |
5ad04c7b | 239 | // TODO: does removing timeout here cause problems?\r |
127631e0 CP |
240 | if (_s.sounds[_tO.id]) {\r |
241 | _s.sounds[_tO.id].load(_tO);\r | |
242 | }\r | |
127631e0 CP |
243 | }\r |
244 | if (_tO.autoPlay) {\r | |
5ad04c7b | 245 | _s.sounds[_tO.id].play();\r |
127631e0 CP |
246 | }\r |
247 | return _s.sounds[_tO.id];\r | |
248 | };\r | |
249 | \r | |
250 | this.createVideo = function(oOptions) {\r | |
251 | if (arguments.length==2) {\r | |
5ad04c7b CP |
252 | oOptions = {'id':arguments[0],'url':arguments[1]};\r |
253 | }\r | |
127631e0 CP |
254 | if (_s.flashVersion >= 9) {\r |
255 | oOptions.isMovieStar = true;\r | |
256 | oOptions.useVideo = true;\r | |
257 | } else {\r | |
258 | _s._wD('soundManager.createVideo(): flash 9 required for video. Exiting.',2);\r | |
259 | return false;\r | |
260 | }\r | |
261 | if (!_s.useMovieStar) {\r | |
262 | _s._wD('soundManager.createVideo(): MovieStar mode not enabled. Exiting.',2);\r | |
263 | }\r | |
264 | return _s.createSound(oOptions);\r | |
5ad04c7b | 265 | };\r |
127631e0 CP |
266 | \r |
267 | this.destroySound = function(sID,bFromSound) {\r | |
268 | // explicitly destroy a sound before normal page unload, etc.\r | |
5ad04c7b CP |
269 | if (!_s._idCheck(sID)) {\r |
270 | return false;\r | |
271 | }\r | |
127631e0 CP |
272 | for (var i=0; i<_s.soundIDs.length; i++) {\r |
273 | if (_s.soundIDs[i] == sID) {\r | |
274 | _s.soundIDs.splice(i,1);\r | |
275 | continue;\r | |
5ad04c7b CP |
276 | }\r |
277 | }\r | |
127631e0 CP |
278 | // conservative option: avoid crash with ze flash 8\r |
279 | // calling destroySound() within a sound onload() might crash firefox, certain flavours of winXP + flash 8??\r | |
280 | // if (_s.flashVersion != 8) {\r | |
281 | _s.sounds[sID].unload();\r | |
282 | // }\r | |
283 | if (!bFromSound) {\r | |
284 | // ignore if being called from SMSound instance\r | |
285 | _s.sounds[sID].destruct();\r | |
5ad04c7b | 286 | }\r |
127631e0 CP |
287 | delete _s.sounds[sID];\r |
288 | };\r | |
289 | \r | |
290 | this.destroyVideo = this.destroySound;\r | |
291 | \r | |
292 | this.load = function(sID,oOptions) {\r | |
5ad04c7b CP |
293 | if (!_s._idCheck(sID)) {\r |
294 | return false;\r | |
295 | }\r | |
127631e0 CP |
296 | _s.sounds[sID].load(oOptions);\r |
297 | };\r | |
298 | \r | |
299 | this.unload = function(sID) {\r | |
5ad04c7b CP |
300 | if (!_s._idCheck(sID)) {\r |
301 | return false;\r | |
302 | }\r | |
127631e0 CP |
303 | _s.sounds[sID].unload();\r |
304 | };\r | |
305 | \r | |
306 | this.play = function(sID,oOptions) {\r | |
86f67adc CP |
307 | if (!_s._didInit) {\r |
308 | throw _s._complain('soundManager.play(): '+_s.strings.notReady,arguments.callee.caller);\r | |
309 | }\r | |
127631e0 | 310 | if (!_s._idCheck(sID)) {\r |
5ad04c7b CP |
311 | if (typeof oOptions != 'Object') {\r |
312 | oOptions = {url:oOptions}; // overloading use case: play('mySound','/path/to/some.mp3');\r | |
313 | }\r | |
127631e0 CP |
314 | if (oOptions && oOptions.url) {\r |
315 | // overloading use case, creation + playing of sound: .play('someID',{url:'/path/to.mp3'});\r | |
316 | _s._wD('soundController.play(): attempting to create "'+sID+'"',1);\r | |
317 | oOptions.id = sID;\r | |
318 | _s.createSound(oOptions);\r | |
319 | } else {\r | |
320 | return false;\r | |
5ad04c7b CP |
321 | }\r |
322 | }\r | |
127631e0 CP |
323 | _s.sounds[sID].play(oOptions);\r |
324 | };\r | |
325 | \r | |
326 | this.start = this.play; // just for convenience\r | |
327 | \r | |
328 | this.setPosition = function(sID,nMsecOffset) {\r | |
5ad04c7b CP |
329 | if (!_s._idCheck(sID)) {\r |
330 | return false;\r | |
331 | }\r | |
127631e0 CP |
332 | _s.sounds[sID].setPosition(nMsecOffset);\r |
333 | };\r | |
334 | \r | |
335 | this.stop = function(sID) {\r | |
5ad04c7b CP |
336 | if (!_s._idCheck(sID)) {\r |
337 | return false;\r | |
338 | }\r | |
127631e0 CP |
339 | _s._wD('soundManager.stop('+sID+')',1);\r |
340 | _s.sounds[sID].stop(); \r | |
341 | };\r | |
342 | \r | |
343 | this.stopAll = function() {\r | |
344 | _s._wD('soundManager.stopAll()',1);\r | |
345 | for (var oSound in _s.sounds) {\r | |
5ad04c7b CP |
346 | if (_s.sounds[oSound] instanceof SMSound) {\r |
347 | _s.sounds[oSound].stop(); // apply only to sound objects\r | |
348 | }\r | |
349 | }\r | |
127631e0 CP |
350 | };\r |
351 | \r | |
352 | this.pause = function(sID) {\r | |
5ad04c7b CP |
353 | if (!_s._idCheck(sID)) {\r |
354 | return false;\r | |
355 | }\r | |
127631e0 CP |
356 | _s.sounds[sID].pause();\r |
357 | };\r | |
358 | \r | |
359 | this.pauseAll = function() {\r | |
360 | for (var i=_s.soundIDs.length; i--;) {\r | |
361 | _s.sounds[_s.soundIDs[i]].pause();\r | |
362 | }\r | |
363 | };\r | |
364 | \r | |
365 | this.resume = function(sID) {\r | |
5ad04c7b CP |
366 | if (!_s._idCheck(sID)) {\r |
367 | return false;\r | |
368 | }\r | |
127631e0 CP |
369 | _s.sounds[sID].resume();\r |
370 | };\r | |
371 | \r | |
372 | this.resumeAll = function() {\r | |
373 | for (var i=_s.soundIDs.length; i--;) {\r | |
374 | _s.sounds[_s.soundIDs[i]].resume();\r | |
375 | }\r | |
376 | };\r | |
377 | \r | |
378 | this.togglePause = function(sID) {\r | |
5ad04c7b CP |
379 | if (!_s._idCheck(sID)) {\r |
380 | return false;\r | |
381 | }\r | |
127631e0 CP |
382 | _s.sounds[sID].togglePause();\r |
383 | };\r | |
384 | \r | |
385 | this.setPan = function(sID,nPan) {\r | |
5ad04c7b CP |
386 | if (!_s._idCheck(sID)) {\r |
387 | return false;\r | |
388 | }\r | |
127631e0 CP |
389 | _s.sounds[sID].setPan(nPan);\r |
390 | };\r | |
391 | \r | |
392 | this.setVolume = function(sID,nVol) {\r | |
5ad04c7b CP |
393 | if (!_s._idCheck(sID)) {\r |
394 | return false;\r | |
395 | }\r | |
127631e0 CP |
396 | _s.sounds[sID].setVolume(nVol);\r |
397 | };\r | |
398 | \r | |
399 | this.mute = function(sID) {\r | |
5ad04c7b CP |
400 | if (typeof sID != 'string') {\r |
401 | sID = null;\r | |
402 | }\r | |
127631e0 | 403 | if (!sID) {\r |
127631e0 CP |
404 | _s._wD('soundManager.mute(): Muting all sounds');\r |
405 | for (var i=_s.soundIDs.length; i--;) {\r | |
406 | _s.sounds[_s.soundIDs[i]].mute();\r | |
407 | }\r | |
408 | _s.muted = true;\r | |
409 | } else {\r | |
5ad04c7b CP |
410 | if (!_s._idCheck(sID)) {\r |
411 | return false;\r | |
412 | }\r | |
127631e0 CP |
413 | _s._wD('soundManager.mute(): Muting "'+sID+'"');\r |
414 | _s.sounds[sID].mute();\r | |
415 | }\r | |
416 | };\r | |
417 | \r | |
418 | this.muteAll = function() {\r | |
419 | _s.mute();\r | |
420 | };\r | |
421 | \r | |
422 | this.unmute = function(sID) {\r | |
5ad04c7b CP |
423 | if (typeof sID != 'string') {\r |
424 | sID = null;\r | |
425 | }\r | |
127631e0 | 426 | if (!sID) {\r |
127631e0 CP |
427 | _s._wD('soundManager.unmute(): Unmuting all sounds');\r |
428 | for (var i=_s.soundIDs.length; i--;) {\r | |
429 | _s.sounds[_s.soundIDs[i]].unmute();\r | |
430 | }\r | |
431 | _s.muted = false;\r | |
432 | } else {\r | |
5ad04c7b CP |
433 | if (!_s._idCheck(sID)) {\r |
434 | return false;\r | |
435 | }\r | |
127631e0 CP |
436 | _s._wD('soundManager.unmute(): Unmuting "'+sID+'"');\r |
437 | _s.sounds[sID].unmute();\r | |
438 | }\r | |
439 | };\r | |
440 | \r | |
441 | this.unmuteAll = function() {\r | |
442 | _s.unmute();\r | |
443 | };\r | |
444 | \r | |
5ad04c7b CP |
445 | this.getMemoryUse = function() {\r |
446 | if (_s.flashVersion == 8) {\r | |
447 | // not supported in Flash 8\r | |
448 | return 0;\r | |
449 | }\r | |
450 | if (_s.o) {\r | |
451 | return parseInt(_s.o._getMemoryUse(),10);\r | |
452 | }\r | |
453 | };\r | |
454 | \r | |
127631e0 | 455 | this.setPolling = function(bPolling) {\r |
5ad04c7b CP |
456 | if (!_s.o || !_s.allowPolling) {\r |
457 | return false;\r | |
458 | }\r | |
127631e0 CP |
459 | _s.o._setPolling(bPolling);\r |
460 | };\r | |
461 | \r | |
86f67adc | 462 | this.disable = function(bNoDisable) {\r |
127631e0 | 463 | // destroy all functions\r |
86f67adc CP |
464 | if (typeof bNoDisable == 'undefined') {\r |
465 | bNoDisable = false;\r | |
466 | }\r | |
5ad04c7b CP |
467 | if (_s._disabled) {\r |
468 | return false;\r | |
86f67adc | 469 | }\r |
127631e0 | 470 | _s._disabled = true;\r |
86f67adc | 471 | _s._wD('soundManager.disable(): Shutting down',1);\r |
127631e0 CP |
472 | for (var i=_s.soundIDs.length; i--;) {\r |
473 | _s._disableObject(_s.sounds[_s.soundIDs[i]]);\r | |
5ad04c7b | 474 | }\r |
86f67adc CP |
475 | _s.initComplete(bNoDisable); // fire "complete", despite fail\r |
476 | // _s._disableObject(_s); // taken out to allow reboot()\r | |
127631e0 CP |
477 | };\r |
478 | \r | |
127631e0 CP |
479 | this.canPlayURL = function(sURL) {\r |
480 | return (sURL?(sURL.match(_s.filePattern)?true:false):null); \r | |
481 | };\r | |
482 | \r | |
483 | this.getSoundById = function(sID,suppressDebug) {\r | |
5ad04c7b CP |
484 | if (!sID) {\r |
485 | throw new Error('SoundManager.getSoundById(): sID is null/undefined');\r | |
486 | }\r | |
127631e0 CP |
487 | var result = _s.sounds[sID];\r |
488 | if (!result && !suppressDebug) {\r | |
489 | _s._wD('"'+sID+'" is an invalid sound ID.',2);\r | |
490 | // soundManager._wD('trace: '+arguments.callee.caller);\r | |
5ad04c7b | 491 | }\r |
127631e0 CP |
492 | return result;\r |
493 | };\r | |
494 | \r | |
495 | this.onload = function() {\r | |
496 | // window.onload() equivalent for SM2, ready to create sounds etc.\r | |
497 | // this is a stub - you can override this in your own external script, eg. soundManager.onload = function() {}\r | |
86f67adc | 498 | soundManager._wD('Warning: soundManager.onload() is undefined.',2);\r |
127631e0 CP |
499 | };\r |
500 | \r | |
501 | this.onerror = function() {\r | |
502 | // stub for user handler, called when SM2 fails to load/init\r | |
503 | };\r | |
504 | \r | |
505 | // --- "private" methods ---\r | |
506 | \r | |
507 | this._idCheck = this.getSoundById;\r | |
508 | \r | |
86f67adc CP |
509 | this._complain = function(sMsg,oCaller) {\r |
510 | // Try to create meaningful custom errors, w/stack trace to the "offending" line\r | |
511 | var sPre = 'Error: ';\r | |
512 | if (!oCaller) {\r | |
513 | return new Error(sPre+sMsg);\r | |
514 | }\r | |
515 | var e = new Error(''); // make a mistake.\r | |
516 | var stackMsg = null;\r | |
517 | if (e.stack) {\r | |
518 | // potentially dangerous: Try to return a meaningful stacktrace where provided (Mozilla)\r | |
519 | try {\r | |
520 | var splitChar = '@';\r | |
521 | var stackTmp = e.stack.split(splitChar);\r | |
522 | stackMsg = stackTmp[4]; // try to return only the relevant bit, skipping internal SM2 shiz\r | |
523 | } catch(ee) {\r | |
524 | // oops.\r | |
525 | stackMsg = e.stack;\r | |
526 | }\r | |
527 | }\r | |
528 | if (typeof console != 'undefined' && typeof console.trace != 'undefined') {\r | |
529 | console.trace();\r | |
530 | }\r | |
531 | var errorDesc = sPre+sMsg+'. \nCaller: '+oCaller.toString()+(e.stack?' \nTop of stacktrace: '+stackMsg:(e.message?' \nMessage: '+e.message:''));\r | |
532 | // See JS error/debug/console output for real error source, stack trace / message detail where possible.\r | |
533 | return new Error(errorDesc);\r | |
534 | };\r | |
535 | \r | |
5ad04c7b CP |
536 | var _doNothing = function() {\r |
537 | return false;\r | |
538 | };\r | |
86f67adc | 539 | \r |
5ad04c7b CP |
540 | _doNothing._protected = true;\r |
541 | \r | |
127631e0 CP |
542 | this._disableObject = function(o) {\r |
543 | for (var oProp in o) {\r | |
5ad04c7b CP |
544 | if (typeof o[oProp] == 'function' && typeof o[oProp]._protected == 'undefined') {\r |
545 | o[oProp] = _doNothing;\r | |
546 | }\r | |
547 | }\r | |
127631e0 CP |
548 | oProp = null;\r |
549 | };\r | |
550 | \r | |
86f67adc CP |
551 | this._failSafely = function(bNoDisable) {\r |
552 | // general failure exception handler\r | |
553 | if (typeof bNoDisable == 'undefined') {\r | |
554 | bNoDisable = false;\r | |
555 | }\r | |
556 | if (!_s._disabled || bNoDisable) {\r | |
127631e0 | 557 | _s._wD('soundManager: Failed to initialise.',2);\r |
86f67adc | 558 | _s.disable(bNoDisable);\r |
5ad04c7b | 559 | }\r |
127631e0 CP |
560 | };\r |
561 | \r | |
562 | this._normalizeMovieURL = function(smURL) {\r | |
5ad04c7b | 563 | var urlParams = null;\r |
127631e0 | 564 | if (smURL) {\r |
5ad04c7b CP |
565 | if (smURL.match(/\.swf(\?.*)?$/i)) {\r |
566 | urlParams = smURL.substr(smURL.toLowerCase().lastIndexOf('.swf?')+4);\r | |
567 | if (urlParams) {\r | |
568 | return smURL; // assume user knows what they're doing\r | |
569 | }\r | |
570 | } else if (smURL.lastIndexOf('/') != smURL.length-1) {\r | |
127631e0 CP |
571 | smURL = smURL+'/';\r |
572 | }\r | |
573 | }\r | |
574 | return(smURL && smURL.lastIndexOf('/')!=-1?smURL.substr(0,smURL.lastIndexOf('/')+1):'./')+_s.movieURL;\r | |
575 | };\r | |
576 | \r | |
577 | this._getDocument = function() {\r | |
578 | return (document.body?document.body:(document.documentElement?document.documentElement:document.getElementsByTagName('div')[0]));\r | |
579 | };\r | |
580 | \r | |
581 | this._getDocument._protected = true;\r | |
582 | \r | |
583 | this._createMovie = function(smID,smURL) {\r | |
5ad04c7b CP |
584 | if (_s._didAppend && _s._appendSuccess) {\r |
585 | return false; // ignore if already succeeded\r | |
586 | }\r | |
587 | if (window.location.href.indexOf('debug=1')+1) {\r | |
588 | _s.debugMode = true; // allow force of debug mode via URL\r | |
589 | }\r | |
127631e0 CP |
590 | _s._didAppend = true;\r |
591 | \r | |
592 | // safety check for legacy (change to Flash 9 URL)\r | |
593 | _s._setVersionInfo();\r | |
594 | var remoteURL = (smURL?smURL:_s.url);\r | |
595 | var localURL = (_s.altURL?_s.altURL:remoteURL);\r | |
596 | _s.url = _s._normalizeMovieURL(_s._overHTTP?remoteURL:localURL);\r | |
597 | smURL = _s.url;\r | |
598 | \r | |
5ad04c7b | 599 | var specialCase = null;\r |
86f67adc CP |
600 | \r |
601 | if (_s.useHighPerformance && _s.useMovieStar && _s.defaultOptions.useVideo === true) {\r | |
602 | specialCase = 'soundManager note: disabling highPerformance, not applicable with movieStar mode + useVideo';\r | |
5ad04c7b CP |
603 | _s.useHighPerformance = false;\r |
604 | }\r | |
605 | \r | |
86f67adc CP |
606 | _s.wmode = (!_s.wmode && _s.useHighPerformance && !_s.useMovieStar?'transparent':_s.wmode);\r |
607 | \r | |
608 | if (_s.wmode !== null && _s.flashLoadTimeout !== 0 && !_s.useHighPerformance && !_s.isIE && navigator.platform.match(/win32/i)) {\r | |
609 | _s.specialWmodeCase = true;\r | |
610 | // extra-special case: movie doesn't load until scrolled into view when using wmode = anything but 'window' here\r | |
611 | // does not apply when using high performance (position:fixed means on-screen), OR infinite flash load timeout\r | |
612 | _s._wD('soundManager note: Removing wmode, preventing off-screen SWF loading issue');\r | |
613 | _s.wmode = null;\r | |
614 | }\r | |
615 | \r | |
616 | if (_s.flashVersion == 8) {\r | |
617 | _s.allowFullScreen = false;\r | |
618 | }\r | |
5ad04c7b CP |
619 | \r |
620 | var oEmbed = {\r | |
621 | name: smID,\r | |
622 | id: smID,\r | |
623 | src: smURL,\r | |
624 | width: '100%',\r | |
625 | height: '100%',\r | |
626 | quality: 'high',\r | |
627 | allowScriptAccess: 'always',\r | |
628 | bgcolor: _s.bgColor,\r | |
629 | pluginspage: 'http://www.macromedia.com/go/getflashplayer',\r | |
86f67adc CP |
630 | type: 'application/x-shockwave-flash',\r |
631 | wmode: _s.wmode,\r | |
632 | allowfullscreen: (_s.allowFullScreen?'true':'false')\r | |
5ad04c7b CP |
633 | };\r |
634 | \r | |
86f67adc CP |
635 | if (!_s.wmode) {\r |
636 | delete oEmbed.wmode; // don't write empty attribute\r | |
637 | }\r | |
638 | \r | |
5ad04c7b CP |
639 | var oObject = {\r |
640 | id: smID,\r | |
641 | data: smURL,\r | |
642 | type: 'application/x-shockwave-flash',\r | |
643 | width: '100%',\r | |
86f67adc CP |
644 | height: '100%',\r |
645 | wmode: _s.wmode\r | |
5ad04c7b CP |
646 | };\r |
647 | \r | |
5ad04c7b CP |
648 | var oMovie = null;\r |
649 | var tmp = null;\r | |
650 | \r | |
651 | if (_s.isIE) {\r | |
652 | // IE is "special".\r | |
653 | oMovie = document.createElement('div');\r | |
86f67adc | 654 | var movieHTML = '<object id="'+smID+'" data="'+smURL+'" type="application/x-shockwave-flash" width="100%" height="100%"><param name="movie" value="'+smURL+'" /><param name="AllowScriptAccess" value="always" /><param name="quality" value="high" />'+(_s.wmode?'<param name="wmode" value="'+_s.wmode+'" /> ':'')+'<param name="bgcolor" value="'+_s.bgColor+'" /><param name="allowFullScreen" value="'+(_s.allowFullScreen?'true':'false')+'" /><!-- --></object>';\r |
5ad04c7b CP |
655 | } else {\r |
656 | oMovie = document.createElement('embed');\r | |
657 | for (tmp in oEmbed) {\r | |
658 | if (oEmbed.hasOwnProperty(tmp)) {\r | |
659 | oMovie.setAttribute(tmp,oEmbed[tmp]);\r | |
86f67adc | 660 | }\r |
5ad04c7b CP |
661 | }\r |
662 | }\r | |
663 | \r | |
664 | var oD = document.createElement('div');\r | |
665 | oD.id = _s.debugID+'-toggle';\r | |
666 | var oToggle = {\r | |
667 | position: 'fixed',\r | |
668 | bottom: '0px',\r | |
669 | right: '0px',\r | |
670 | width: '1.2em',\r | |
671 | height: '1.2em',\r | |
672 | lineHeight: '1.2em',\r | |
673 | margin: '2px',\r | |
674 | textAlign: 'center',\r | |
675 | border: '1px solid #999',\r | |
676 | cursor: 'pointer',\r | |
677 | background: '#fff',\r | |
678 | color: '#333',\r | |
679 | zIndex: 10001\r | |
680 | };\r | |
681 | \r | |
682 | oD.appendChild(document.createTextNode('-'));\r | |
683 | oD.onclick = _s._toggleDebug;\r | |
684 | oD.title = 'Toggle SM2 debug console';\r | |
685 | \r | |
686 | if (navigator.userAgent.match(/msie 6/i)) {\r | |
687 | oD.style.position = 'absolute';\r | |
688 | oD.style.cursor = 'hand';\r | |
689 | }\r | |
690 | \r | |
691 | for (tmp in oToggle) {\r | |
86f67adc CP |
692 | if (oToggle.hasOwnProperty(tmp)) {\r |
693 | oD.style[tmp] = oToggle[tmp];\r | |
694 | }\r | |
5ad04c7b | 695 | }\r |
127631e0 | 696 | \r |
127631e0 | 697 | var oTarget = _s._getDocument();\r |
5ad04c7b | 698 | \r |
127631e0 CP |
699 | if (oTarget) {\r |
700 | \r | |
86f67adc | 701 | _s.oMC = _$('sm2-container')?_$('sm2-container'):document.createElement('div');\r |
5ad04c7b | 702 | \r |
127631e0 CP |
703 | if (!_s.oMC.id) {\r |
704 | _s.oMC.id = 'sm2-container';\r | |
705 | _s.oMC.className = 'movieContainer';\r | |
706 | // "hide" flash movie\r | |
707 | var s = null;\r | |
5ad04c7b | 708 | var oEl = null;\r |
127631e0 CP |
709 | if (_s.useHighPerformance) {\r |
710 | s = {\r | |
5ad04c7b CP |
711 | position: 'fixed',\r |
712 | width: '8px',\r | |
127631e0 CP |
713 | height: '8px', // must be at least 6px for flash to run fast. odd? yes.\r |
714 | bottom: '0px',\r | |
86f67adc CP |
715 | left: '0px'\r |
716 | // zIndex:-1 // sit behind everything else - potentially dangerous/buggy?\r | |
5ad04c7b | 717 | };\r |
127631e0 CP |
718 | } else {\r |
719 | s = {\r | |
720 | position: 'absolute',\r | |
86f67adc | 721 | width: '1px',\r |
127631e0 | 722 | height: '1px',\r |
86f67adc CP |
723 | top: '-999px',\r |
724 | left: '-999px'\r | |
5ad04c7b | 725 | };\r |
127631e0 CP |
726 | }\r |
727 | var x = null;\r | |
728 | for (x in s) {\r | |
5ad04c7b CP |
729 | if (s.hasOwnProperty(x)) {\r |
730 | _s.oMC.style[x] = s[x];\r | |
731 | }\r | |
127631e0 CP |
732 | }\r |
733 | try {\r | |
5ad04c7b CP |
734 | if (!_s.isIE) {\r |
735 | _s.oMC.appendChild(oMovie);\r | |
736 | }\r | |
127631e0 | 737 | oTarget.appendChild(_s.oMC);\r |
5ad04c7b CP |
738 | if (_s.isIE) {\r |
739 | oEl = _s.oMC.appendChild(document.createElement('div'));\r | |
740 | oEl.className = 'sm2-object-box';\r | |
741 | oEl.innerHTML = movieHTML;\r | |
742 | }\r | |
127631e0 CP |
743 | _s._appendSuccess = true;\r |
744 | } catch(e) {\r | |
86f67adc | 745 | throw new Error(_s.strings.appXHTML);\r |
127631e0 CP |
746 | }\r |
747 | } else {\r | |
748 | // it's already in the document.\r | |
5ad04c7b CP |
749 | _s.oMC.appendChild(oMovie);\r |
750 | if (_s.isIE) {\r | |
751 | oEl = _s.oMC.appendChild(document.createElement('div'));\r | |
752 | oEl.className = 'sm2-object-box';\r | |
753 | oEl.innerHTML = movieHTML;\r | |
754 | }\r | |
127631e0 CP |
755 | _s._appendSuccess = true;\r |
756 | }\r | |
5ad04c7b | 757 | \r |
86f67adc | 758 | if (!_$(_s.debugID) && ((!_s._hasConsole||!_s.useConsole)||(_s.useConsole && _s._hasConsole && !_s.consoleOnly))) {\r |
127631e0 CP |
759 | var oDebug = document.createElement('div');\r |
760 | oDebug.id = _s.debugID;\r | |
761 | oDebug.style.display = (_s.debugMode?'block':'none');\r | |
86f67adc | 762 | if (_s.debugMode && !_$(oD.id)) {\r |
127631e0 | 763 | try {\r |
127631e0 | 764 | oTarget.appendChild(oD);\r |
5ad04c7b | 765 | } catch(e2) {\r |
86f67adc | 766 | throw new Error(_s.strings.appXHTML);\r |
5ad04c7b | 767 | }\r |
86f67adc | 768 | oTarget.appendChild(oDebug);\r |
5ad04c7b | 769 | }\r |
5ad04c7b | 770 | }\r |
127631e0 | 771 | oTarget = null;\r |
5ad04c7b CP |
772 | }\r |
773 | \r | |
774 | if (specialCase) {\r | |
775 | _s._wD(specialCase);\r | |
776 | }\r | |
777 | \r | |
86f67adc CP |
778 | _s._wD('-- SoundManager 2 '+_s.version+(_s.useMovieStar?', MovieStar mode':'')+(_s.useHighPerformance?', high performance mode':'')+(_s.wmode?', wmode: '+_s.wmode:'')+' --',1);\r |
779 | _s._wD('soundManager._createMovie(): Trying to load '+smURL+(!_s._overHTTP && _s.altURL?' (alternate URL)':''),1);\r | |
127631e0 CP |
780 | };\r |
781 | \r | |
782 | // aliased to this._wD()\r | |
783 | this._writeDebug = function(sText,sType,bTimestamp) {\r | |
5ad04c7b CP |
784 | if (!_s.debugMode) {\r |
785 | return false;\r | |
786 | }\r | |
127631e0 CP |
787 | if (typeof bTimestamp != 'undefined' && bTimestamp) {\r |
788 | sText = sText + ' | '+new Date().getTime();\r | |
5ad04c7b | 789 | }\r |
127631e0 CP |
790 | if (_s._hasConsole && _s.useConsole) {\r |
791 | var sMethod = _s._debugLevels[sType];\r | |
792 | if (typeof console[sMethod] != 'undefined') {\r | |
86f67adc | 793 | console[sMethod](sText);\r |
127631e0 CP |
794 | } else {\r |
795 | console.log(sText);\r | |
5ad04c7b CP |
796 | }\r |
797 | if (_s.useConsoleOnly) {\r | |
86f67adc CP |
798 | return true;\r |
799 | }\r | |
5ad04c7b | 800 | }\r |
127631e0 CP |
801 | var sDID = 'soundmanager-debug';\r |
802 | try {\r | |
86f67adc | 803 | var o = _$(sDID);\r |
5ad04c7b CP |
804 | if (!o) {\r |
805 | return false;\r | |
806 | }\r | |
127631e0 | 807 | var oItem = document.createElement('div');\r |
86f67adc CP |
808 | if (++_s._wdCount%2===0) {\r |
809 | oItem.className = 'sm2-alt';\r | |
810 | }\r | |
5ad04c7b | 811 | // sText = sText.replace(/\n/g,'<br />');\r |
127631e0 | 812 | if (typeof sType == 'undefined') {\r |
5ad04c7b | 813 | sType = 0;\r |
127631e0 | 814 | } else {\r |
5ad04c7b CP |
815 | sType = parseInt(sType,10);\r |
816 | }\r | |
817 | oItem.appendChild(document.createTextNode(sText));\r | |
127631e0 | 818 | if (sType) {\r |
5ad04c7b CP |
819 | if (sType >= 2) {\r |
820 | oItem.style.fontWeight = 'bold';\r | |
821 | }\r | |
822 | if (sType == 3) {\r | |
823 | oItem.style.color = '#ff3333';\r | |
824 | }\r | |
825 | }\r | |
127631e0 CP |
826 | // o.appendChild(oItem); // top-to-bottom\r |
827 | o.insertBefore(oItem,o.firstChild); // bottom-to-top\r | |
828 | } catch(e) {\r | |
829 | // oh well\r | |
5ad04c7b | 830 | }\r |
127631e0 CP |
831 | o = null;\r |
832 | };\r | |
833 | this._writeDebug._protected = true;\r | |
86f67adc CP |
834 | this._wdCount = 0;\r |
835 | this._wdCount._protected = true;\r | |
127631e0 CP |
836 | this._wD = this._writeDebug;\r |
837 | \r | |
838 | this._wDAlert = function(sText) { alert(sText); };\r | |
839 | \r | |
840 | if (window.location.href.indexOf('debug=alert')+1 && _s.debugMode) {\r | |
841 | _s._wD = _s._wDAlert;\r | |
5ad04c7b | 842 | }\r |
127631e0 CP |
843 | \r |
844 | this._toggleDebug = function() {\r | |
86f67adc CP |
845 | var o = _$(_s.debugID);\r |
846 | var oT = _$(_s.debugID+'-toggle');\r | |
5ad04c7b CP |
847 | if (!o) {\r |
848 | return false;\r | |
849 | }\r | |
127631e0 CP |
850 | if (_s._debugOpen) {\r |
851 | // minimize\r | |
852 | oT.innerHTML = '+';\r | |
853 | o.style.display = 'none';\r | |
854 | } else {\r | |
855 | oT.innerHTML = '-';\r | |
856 | o.style.display = 'block';\r | |
5ad04c7b | 857 | }\r |
127631e0 CP |
858 | _s._debugOpen = !_s._debugOpen;\r |
859 | };\r | |
860 | \r | |
861 | this._toggleDebug._protected = true;\r | |
862 | \r | |
863 | this._debug = function() {\r | |
864 | _s._wD('--- soundManager._debug(): Current sound objects ---',1);\r | |
865 | for (var i=0,j=_s.soundIDs.length; i<j; i++) {\r | |
866 | _s.sounds[_s.soundIDs[i]]._debug();\r | |
5ad04c7b CP |
867 | }\r |
868 | };\r | |
869 | \r | |
870 | this._debugTS = function(sEventType,bSuccess,sMessage) {\r | |
871 | // troubleshooter debug hooks\r | |
872 | if (typeof sm2Debugger != 'undefined') {\r | |
873 | try {\r | |
874 | sm2Debugger.handleEvent(sEventType,bSuccess,sMessage);\r | |
875 | } catch(e) {\r | |
876 | // oh well \r | |
877 | }\r | |
878 | }\r | |
127631e0 CP |
879 | };\r |
880 | \r | |
5ad04c7b CP |
881 | this._debugTS._protected = true;\r |
882 | \r | |
127631e0 CP |
883 | this._mergeObjects = function(oMain,oAdd) {\r |
884 | // non-destructive merge\r | |
885 | var o1 = {}; // clone o1\r | |
886 | for (var i in oMain) {\r | |
5ad04c7b CP |
887 | if (oMain.hasOwnProperty(i)) {\r |
888 | o1[i] = oMain[i];\r | |
889 | }\r | |
127631e0 CP |
890 | }\r |
891 | var o2 = (typeof oAdd == 'undefined'?_s.defaultOptions:oAdd);\r | |
892 | for (var o in o2) {\r | |
5ad04c7b CP |
893 | if (o2.hasOwnProperty(o) && typeof o1[o] == 'undefined') {\r |
894 | o1[o] = o2[o];\r | |
895 | }\r | |
896 | }\r | |
127631e0 CP |
897 | return o1;\r |
898 | };\r | |
899 | \r | |
900 | this.createMovie = function(sURL) {\r | |
5ad04c7b CP |
901 | if (sURL) {\r |
902 | _s.url = sURL;\r | |
903 | }\r | |
127631e0 CP |
904 | _s._initMovie();\r |
905 | };\r | |
906 | \r | |
907 | this.go = this.createMovie; // nice alias\r | |
908 | \r | |
909 | this._initMovie = function() {\r | |
910 | // attempt to get, or create, movie\r | |
5ad04c7b | 911 | if (_s.o) {\r |
86f67adc CP |
912 | return false; // may already exist\r |
913 | }\r | |
914 | _s.o = _s.getMovie(_s.id); // (inline markup)\r | |
127631e0 | 915 | if (!_s.o) {\r |
86f67adc CP |
916 | if (!_s.oRemoved) {\r |
917 | // try to create\r | |
918 | _s._createMovie(_s.id,_s.url);\r | |
919 | } else {\r | |
920 | // try to re-append removed movie after reboot()\r | |
921 | if (!_s.isIE) {\r | |
922 | _s.oMC.appendChild(_s.oRemoved);\r | |
923 | } else {\r | |
924 | _s.oMC.innerHTML = _s.oRemovedHTML;\r | |
925 | }\r | |
926 | _s.oRemoved = null;\r | |
927 | _s._didAppend = true;\r | |
928 | }\r | |
127631e0 | 929 | _s.o = _s.getMovie(_s.id);\r |
5ad04c7b | 930 | }\r |
127631e0 CP |
931 | if (_s.o) {\r |
932 | _s._wD('soundManager._initMovie(): Got '+_s.o.nodeName+' element ('+(_s._didAppend?'created via JS':'static HTML')+')',1);\r | |
86f67adc CP |
933 | if (_s.flashLoadTimeout>0) {\r |
934 | _s._wD('soundManager._initMovie(): Waiting for ExternalInterface call from Flash..');\r | |
935 | }\r | |
5ad04c7b | 936 | }\r |
127631e0 CP |
937 | };\r |
938 | \r | |
939 | this.waitForExternalInterface = function() {\r | |
5ad04c7b CP |
940 | if (_s._waitingForEI) {\r |
941 | return false;\r | |
942 | }\r | |
127631e0 CP |
943 | _s._waitingForEI = true;\r |
944 | if (_s._tryInitOnFocus && !_s._isFocused) {\r | |
86f67adc | 945 | _s._wD('soundManager: Special case: Waiting for focus-related event..');\r |
127631e0 | 946 | return false;\r |
5ad04c7b | 947 | }\r |
86f67adc | 948 | if (_s.flashLoadTimeout>0) {\r |
127631e0 | 949 | if (!_s._didInit) {\r |
86f67adc CP |
950 | _s._wD('soundManager: Getting impatient, still waiting for Flash.. ;)');\r |
951 | }\r | |
952 | setTimeout(function() {\r | |
953 | if (!_s._didInit) {\r | |
954 | _s._wD('soundManager: No Flash response within reasonable time after document load.\nPossible causes: Loading '+_s.movieURL+' failed, Flash version under '+_s.flashVersion+', no support, flash blocked or JS-Flash security error.',2);\r | |
955 | if (!_s._overHTTP) {\r | |
127631e0 | 956 | _s._wD('soundManager: Loading this page from local/network file system (not over HTTP?) Flash security likely restricting JS-Flash access. Consider adding current URL to "trusted locations" in the Flash player security settings manager at '+flashCPLink+', or simply serve this content over HTTP.',2);\r |
5ad04c7b CP |
957 | }\r |
958 | _s._debugTS('flashtojs',false,': Timed out'+(_s._overHTTP)?' (Check flash security)':' (No plugin/missing SWF?)');\r | |
959 | }\r | |
127631e0 | 960 | // if still not initialized and no other options, give up\r |
5ad04c7b | 961 | if (!_s._didInit && _s._okToDisable) {\r |
86f67adc CP |
962 | _s._failSafely(true); // don't disable, for reboot()\r |
963 | }\r | |
964 | },_s.flashLoadTimeout);\r | |
965 | } else if (!_s.didInit) {\r | |
966 | _s._wD('soundManager: Waiting indefinitely for Flash...');\r | |
967 | }\r | |
127631e0 CP |
968 | };\r |
969 | \r | |
970 | this.handleFocus = function() {\r | |
5ad04c7b CP |
971 | if (_s._isFocused || !_s._tryInitOnFocus) {\r |
972 | return true;\r | |
973 | }\r | |
127631e0 CP |
974 | _s._okToDisable = true;\r |
975 | _s._isFocused = true;\r | |
976 | _s._wD('soundManager.handleFocus()');\r | |
977 | if (_s._tryInitOnFocus) {\r | |
978 | // giant Safari 3.1 hack - assume window in focus if mouse is moving, since document.hasFocus() not currently implemented.\r | |
979 | window.removeEventListener('mousemove',_s.handleFocus,false);\r | |
5ad04c7b | 980 | }\r |
127631e0 CP |
981 | // allow init to restart\r |
982 | _s._waitingForEI = false;\r | |
983 | setTimeout(_s.waitForExternalInterface,500);\r | |
984 | // detach event\r | |
985 | if (window.removeEventListener) {\r | |
986 | window.removeEventListener('focus',_s.handleFocus,false);\r | |
987 | } else if (window.detachEvent) {\r | |
988 | window.detachEvent('onfocus',_s.handleFocus);\r | |
5ad04c7b | 989 | }\r |
127631e0 CP |
990 | };\r |
991 | \r | |
86f67adc | 992 | this.initComplete = function(bNoDisable) {\r |
5ad04c7b CP |
993 | if (_s._didInit) {\r |
994 | return false;\r | |
995 | }\r | |
127631e0 CP |
996 | _s._didInit = true;\r |
997 | _s._wD('-- SoundManager 2 '+(_s._disabled?'failed to load':'loaded')+' ('+(_s._disabled?'security/load error':'OK')+') --',1);\r | |
86f67adc | 998 | if (_s._disabled || bNoDisable) {\r |
127631e0 | 999 | _s._wD('soundManager.initComplete(): calling soundManager.onerror()',1);\r |
5ad04c7b | 1000 | _s._debugTS('onload',false);\r |
127631e0 CP |
1001 | _s.onerror.apply(window);\r |
1002 | return false;\r | |
5ad04c7b CP |
1003 | } else {\r |
1004 | _s._debugTS('onload',true);\r | |
1005 | }\r | |
127631e0 CP |
1006 | if (_s.waitForWindowLoad && !_s._windowLoaded) {\r |
1007 | _s._wD('soundManager: Waiting for window.onload()');\r | |
1008 | if (window.addEventListener) {\r | |
1009 | window.addEventListener('load',_s.initUserOnload,false);\r | |
1010 | } else if (window.attachEvent) {\r | |
1011 | window.attachEvent('onload',_s.initUserOnload);\r | |
5ad04c7b | 1012 | }\r |
127631e0 CP |
1013 | return false;\r |
1014 | } else {\r | |
1015 | if (_s.waitForWindowLoad && _s._windowLoaded) {\r | |
1016 | _s._wD('soundManager: Document already loaded');\r | |
5ad04c7b | 1017 | }\r |
127631e0 | 1018 | _s.initUserOnload();\r |
5ad04c7b | 1019 | }\r |
127631e0 CP |
1020 | };\r |
1021 | \r | |
1022 | this.initUserOnload = function() {\r | |
1023 | _s._wD('soundManager.initComplete(): calling soundManager.onload()',1);\r | |
1024 | // call user-defined "onload", scoped to window\r | |
5ad04c7b | 1025 | _s.onload.apply(window);\r |
127631e0 CP |
1026 | _s._wD('soundManager.onload() complete',1);\r |
1027 | };\r | |
1028 | \r | |
1029 | this.init = function() {\r | |
1030 | _s._wD('-- soundManager.init() --');\r | |
1031 | // called after onload()\r | |
1032 | _s._initMovie();\r | |
1033 | if (_s._didInit) {\r | |
1034 | _s._wD('soundManager.init(): Already called?');\r | |
1035 | return false;\r | |
5ad04c7b | 1036 | }\r |
127631e0 CP |
1037 | // event cleanup\r |
1038 | if (window.removeEventListener) {\r | |
1039 | window.removeEventListener('load',_s.beginDelayedInit,false);\r | |
1040 | } else if (window.detachEvent) {\r | |
1041 | window.detachEvent('onload',_s.beginDelayedInit);\r | |
5ad04c7b | 1042 | }\r |
127631e0 | 1043 | try {\r |
5ad04c7b | 1044 | _s._wD('Attempting to call Flash from JS..');\r |
127631e0 CP |
1045 | _s.o._externalInterfaceTest(false); // attempt to talk to Flash\r |
1046 | // _s._wD('Flash ExternalInterface call (JS-Flash) OK',1);\r | |
1047 | if (!_s.allowPolling) {\r | |
1048 | _s._wD('Polling (whileloading/whileplaying support) is disabled.',1);\r | |
1049 | }\r | |
1050 | _s.setPolling(true);\r | |
5ad04c7b CP |
1051 | if (!_s.debugMode) {\r |
1052 | _s.o._disableDebug();\r | |
1053 | }\r | |
127631e0 | 1054 | _s.enabled = true;\r |
5ad04c7b | 1055 | _s._debugTS('jstoflash',true);\r |
127631e0 | 1056 | } catch(e) {\r |
5ad04c7b | 1057 | _s._debugTS('jstoflash',false);\r |
86f67adc | 1058 | _s._failSafely(true); // don't disable, for reboot()\r |
127631e0 CP |
1059 | _s.initComplete();\r |
1060 | return false;\r | |
5ad04c7b | 1061 | }\r |
127631e0 CP |
1062 | _s.initComplete();\r |
1063 | };\r | |
1064 | \r | |
1065 | this.beginDelayedInit = function() {\r | |
86f67adc | 1066 | _s._wD('soundManager.beginDelayedInit()');\r |
127631e0 CP |
1067 | _s._windowLoaded = true;\r |
1068 | setTimeout(_s.waitForExternalInterface,500);\r | |
1069 | setTimeout(_s.beginInit,20);\r | |
1070 | };\r | |
1071 | \r | |
1072 | this.beginInit = function() {\r | |
5ad04c7b CP |
1073 | if (_s._initPending) {\r |
1074 | return false;\r | |
1075 | }\r | |
127631e0 CP |
1076 | _s.createMovie(); // ensure creation if not already done\r |
1077 | _s._initMovie();\r | |
1078 | _s._initPending = true;\r | |
1079 | return true;\r | |
1080 | };\r | |
1081 | \r | |
1082 | this.domContentLoaded = function() {\r | |
1083 | _s._wD('soundManager.domContentLoaded()');\r | |
5ad04c7b CP |
1084 | if (document.removeEventListener) {\r |
1085 | document.removeEventListener('DOMContentLoaded',_s.domContentLoaded,false);\r | |
1086 | }\r | |
127631e0 CP |
1087 | _s.go();\r |
1088 | };\r | |
1089 | \r | |
1090 | this._externalInterfaceOK = function() {\r | |
1091 | // callback from flash for confirming that movie loaded, EI is working etc.\r | |
5ad04c7b CP |
1092 | if (_s.swfLoaded) {\r |
1093 | return false;\r | |
1094 | }\r | |
127631e0 | 1095 | _s._wD('soundManager._externalInterfaceOK()');\r |
5ad04c7b CP |
1096 | _s._debugTS('swf',true);\r |
1097 | _s._debugTS('flashtojs',true);\r | |
127631e0 CP |
1098 | _s.swfLoaded = true;\r |
1099 | _s._tryInitOnFocus = false;\r | |
86f67adc | 1100 | \r |
127631e0 CP |
1101 | if (_s.isIE) {\r |
1102 | // IE needs a timeout OR delay until window.onload - may need TODO: investigating\r | |
1103 | setTimeout(_s.init,100);\r | |
1104 | } else {\r | |
1105 | _s.init();\r | |
5ad04c7b | 1106 | }\r |
86f67adc | 1107 | \r |
127631e0 CP |
1108 | };\r |
1109 | \r | |
1110 | this._setSandboxType = function(sandboxType) {\r | |
1111 | var sb = _s.sandbox;\r | |
1112 | sb.type = sandboxType;\r | |
1113 | sb.description = sb.types[(typeof sb.types[sandboxType] != 'undefined'?sandboxType:'unknown')];\r | |
1114 | _s._wD('Flash security sandbox type: '+sb.type);\r | |
1115 | if (sb.type == 'localWithFile') {\r | |
1116 | sb.noRemote = true;\r | |
1117 | sb.noLocal = false;\r | |
1118 | _s._wD('Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html',2);\r | |
1119 | } else if (sb.type == 'localWithNetwork') {\r | |
1120 | sb.noRemote = false;\r | |
1121 | sb.noLocal = true;\r | |
1122 | } else if (sb.type == 'localTrusted') {\r | |
1123 | sb.noRemote = false;\r | |
1124 | sb.noLocal = false;\r | |
5ad04c7b | 1125 | }\r |
127631e0 CP |
1126 | };\r |
1127 | \r | |
86f67adc CP |
1128 | this.reboot = function() {\r |
1129 | // attempt to reset and init SM2\r | |
1130 | _s._wD('soundManager.reboot()');\r | |
1131 | if (_s.soundIDs.length) {\r | |
1132 | _s._wD('Destroying '+_s.soundIDs.length+' SMSound objects...');\r | |
1133 | }\r | |
1134 | for (var i=_s.soundIDs.length; i--;) {\r | |
1135 | _s.sounds[_s.soundIDs[i]].destruct();\r | |
1136 | }\r | |
1137 | // trash ze flash\r | |
1138 | try {\r | |
1139 | if (_s.isIE) {\r | |
1140 | _s.oRemovedHTML = _s.o.innerHTML;\r | |
1141 | }\r | |
1142 | _s.oRemoved = _s.o.parentNode.removeChild(_s.o);\r | |
1143 | _s._wD('Flash movie removed.');\r | |
1144 | } catch(e) {\r | |
1145 | // uh-oh.\r | |
1146 | _s._wD('Warning: Failed to remove flash movie.',2);\r | |
1147 | }\r | |
1148 | _s.enabled = false;\r | |
1149 | _s._didInit = false;\r | |
1150 | _s._waitingForEI = false;\r | |
1151 | _s._initPending = false;\r | |
1152 | _s._didInit = false;\r | |
1153 | _s._didAppend = false;\r | |
1154 | _s._appendSuccess = false;\r | |
1155 | _s._didInit = false;\r | |
1156 | _s._disabled = false;\r | |
1157 | _s._waitingforEI = true;\r | |
1158 | _s.swfLoaded = false;\r | |
1159 | _s.soundIDs = {};\r | |
1160 | _s.sounds = [];\r | |
1161 | _s.o = null;\r | |
1162 | _s._wD('soundManager: Rebooting...');\r | |
1163 | window.setTimeout(function() {\r | |
1164 | soundManager.beginDelayedInit();\r | |
1165 | },20);\r | |
1166 | };\r | |
1167 | \r | |
127631e0 CP |
1168 | this.destruct = function() {\r |
1169 | _s._wD('soundManager.destruct()');\r | |
1170 | _s.disable(true);\r | |
1171 | };\r | |
1172 | \r | |
1173 | // SMSound (sound object)\r | |
1174 | \r | |
5ad04c7b | 1175 | SMSound = function(oOptions) {\r |
127631e0 CP |
1176 | var _t = this;\r |
1177 | this.sID = oOptions.id;\r | |
1178 | this.url = oOptions.url;\r | |
1179 | this.options = _s._mergeObjects(oOptions);\r | |
1180 | this.instanceOptions = this.options; // per-play-instance-specific options\r | |
1181 | this._iO = this.instanceOptions; // short alias\r | |
1182 | \r | |
5ad04c7b CP |
1183 | // assign property defaults (volume, pan etc.)\r |
1184 | this.pan = this.options.pan;\r | |
1185 | this.volume = this.options.volume;\r | |
1186 | \r | |
86f67adc CP |
1187 | this._lastURL = null;\r |
1188 | \r | |
127631e0 CP |
1189 | this._debug = function() {\r |
1190 | if (_s.debugMode) {\r | |
1191 | var stuff = null;\r | |
1192 | var msg = [];\r | |
1193 | var sF = null;\r | |
1194 | var sfBracket = null;\r | |
1195 | var maxLength = 64; // # of characters of function code to show before truncating\r | |
1196 | for (stuff in _t.options) {\r | |
5ad04c7b | 1197 | if (_t.options[stuff] !== null) {\r |
127631e0 CP |
1198 | if (_t.options[stuff] instanceof Function) {\r |
1199 | // handle functions specially\r | |
1200 | sF = _t.options[stuff].toString();\r | |
1201 | sF = sF.replace(/\s\s+/g,' '); // normalize spaces\r | |
1202 | sfBracket = sF.indexOf('{');\r | |
1203 | msg[msg.length] = ' '+stuff+': {'+sF.substr(sfBracket+1,(Math.min(Math.max(sF.indexOf('\n')-1,maxLength),maxLength))).replace(/\n/g,'')+'... }';\r | |
1204 | } else {\r | |
1205 | msg[msg.length] = ' '+stuff+': '+_t.options[stuff];\r | |
5ad04c7b CP |
1206 | }\r |
1207 | }\r | |
1208 | }\r | |
127631e0 | 1209 | _s._wD('SMSound() merged options: {\n'+msg.join(', \n')+'\n}');\r |
5ad04c7b | 1210 | }\r |
127631e0 CP |
1211 | };\r |
1212 | \r | |
1213 | this._debug();\r | |
1214 | \r | |
1215 | this.id3 = {\r | |
1216 | /* \r | |
1217 | Name/value pairs set via Flash when available - see reference for names:\r | |
1218 | http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001567.html\r | |
1219 | (eg., this.id3.songname or this.id3['songname'])\r | |
1220 | */\r | |
1221 | };\r | |
1222 | \r | |
1223 | this.resetProperties = function(bLoaded) {\r | |
1224 | _t.bytesLoaded = null;\r | |
1225 | _t.bytesTotal = null;\r | |
1226 | _t.position = null;\r | |
1227 | _t.duration = null;\r | |
1228 | _t.durationEstimate = null;\r | |
1229 | _t.loaded = false;\r | |
1230 | _t.playState = 0;\r | |
1231 | _t.paused = false;\r | |
1232 | _t.readyState = 0; // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success\r | |
1233 | _t.muted = false;\r | |
1234 | _t.didBeforeFinish = false;\r | |
1235 | _t.didJustBeforeFinish = false;\r | |
86f67adc | 1236 | _t.isBuffering = false;\r |
127631e0 CP |
1237 | _t.instanceOptions = {};\r |
1238 | _t.instanceCount = 0;\r | |
1239 | _t.peakData = {\r | |
1240 | left: 0,\r | |
1241 | right: 0\r | |
1242 | };\r | |
86f67adc CP |
1243 | _t.waveformData = {\r |
1244 | left: [],\r | |
1245 | right: []\r | |
1246 | };\r | |
127631e0 CP |
1247 | _t.eqData = [];\r |
1248 | };\r | |
1249 | \r | |
1250 | _t.resetProperties();\r | |
1251 | \r | |
1252 | // --- public methods ---\r | |
1253 | \r | |
1254 | this.load = function(oOptions) {\r | |
1255 | if (typeof oOptions != 'undefined') {\r | |
1256 | _t._iO = _s._mergeObjects(oOptions);\r | |
1257 | _t.instanceOptions = _t._iO;\r | |
1258 | } else {\r | |
5ad04c7b | 1259 | oOptions = _t.options;\r |
127631e0 CP |
1260 | _t._iO = oOptions;\r |
1261 | _t.instanceOptions = _t._iO;\r | |
86f67adc CP |
1262 | \r |
1263 | // console.log('typeof oOptions: '+(typeof oOptions)+', lastURL: '+_t._lastURL+', _t.url: '+_t.url);\r | |
1264 | \r | |
1265 | if (_t._lastURL && _t._lastURL != _t.url) {\r | |
1266 | _s._wD('SMSound.load(): Using manually-assigned URL');\r | |
1267 | _t._iO.url = _t.url;\r | |
1268 | _t.url = null;\r | |
1269 | }\r | |
127631e0 | 1270 | } \r |
86f67adc | 1271 | \r |
5ad04c7b CP |
1272 | if (typeof _t._iO.url == 'undefined') {\r |
1273 | _t._iO.url = _t.url;\r | |
1274 | }\r | |
86f67adc | 1275 | \r |
127631e0 | 1276 | _s._wD('soundManager.load(): '+_t._iO.url,1);\r |
5ad04c7b | 1277 | if (_t._iO.url == _t.url && _t.readyState !== 0 && _t.readyState != 2) {\r |
127631e0 CP |
1278 | _s._wD('soundManager.load(): current URL already assigned.',1);\r |
1279 | return false;\r | |
1280 | }\r | |
86f67adc CP |
1281 | _t.url = _t._iO.url;\r |
1282 | _t._lastURL = _t._iO.url;\r | |
127631e0 CP |
1283 | _t.loaded = false;\r |
1284 | _t.readyState = 1;\r | |
5ad04c7b | 1285 | _t.playState = 0; // (oOptions.autoPlay?1:0); // if autoPlay, assume "playing" is true (no way to detect when it actually starts in Flash unless onPlay is watched?)\r |
127631e0 CP |
1286 | try {\r |
1287 | if (_s.flashVersion==8) {\r | |
1288 | _s.o._load(_t.sID,_t._iO.url,_t._iO.stream,_t._iO.autoPlay,(_t._iO.whileloading?1:0));\r | |
1289 | } else {\r | |
1290 | _s.o._load(_t.sID,_t._iO.url,_t._iO.stream?true:false,_t._iO.autoPlay?true:false); // ,(_tO.whileloading?true:false)\r | |
1291 | if (_t._iO.isMovieStar && _t._iO.autoLoad && !_t._iO.autoPlay) {\r | |
1292 | // special case: MPEG4 content must start playing to load, then pause to prevent playing.\r | |
1293 | _t.pause();\r | |
1294 | }\r | |
5ad04c7b | 1295 | }\r |
127631e0 CP |
1296 | } catch(e) {\r |
1297 | _s._wD('SMSound.load(): Exception: JS-Flash communication failed, or JS error.',2);\r | |
5ad04c7b | 1298 | _s._debugTS('onload',false);\r |
127631e0 CP |
1299 | _s.onerror();\r |
1300 | _s.disable();\r | |
5ad04c7b CP |
1301 | }\r |
1302 | \r | |
127631e0 CP |
1303 | };\r |
1304 | \r | |
1305 | this.unload = function() {\r | |
1306 | // Flash 8/AS2 can't "close" a stream - fake it by loading an empty MP3\r | |
1307 | // Flash 9/AS3: Close stream, preventing further load\r | |
5ad04c7b | 1308 | if (_t.readyState !== 0) {\r |
127631e0 CP |
1309 | _s._wD('SMSound.unload(): "'+_t.sID+'"');\r |
1310 | if (_t.readyState != 2) { // reset if not error\r | |
5ad04c7b | 1311 | _t.setPosition(0,true); // reset current sound positioning\r |
127631e0 CP |
1312 | }\r |
1313 | _s.o._unload(_t.sID,_s.nullURL);\r | |
1314 | // reset load/status flags\r | |
1315 | _t.resetProperties();\r | |
1316 | }\r | |
1317 | };\r | |
1318 | \r | |
1319 | this.destruct = function() {\r | |
1320 | // kill sound within Flash\r | |
1321 | _s._wD('SMSound.destruct(): "'+_t.sID+'"');\r | |
1322 | _s.o._destroySound(_t.sID);\r | |
1323 | _s.destroySound(_t.sID,true); // ensure deletion from controller\r | |
5ad04c7b | 1324 | };\r |
127631e0 CP |
1325 | \r |
1326 | this.play = function(oOptions) {\r | |
5ad04c7b CP |
1327 | if (!oOptions) {\r |
1328 | oOptions = {};\r | |
1329 | }\r | |
127631e0 CP |
1330 | _t._iO = _s._mergeObjects(oOptions,_t._iO);\r |
1331 | _t._iO = _s._mergeObjects(_t._iO,_t.options);\r | |
1332 | _t.instanceOptions = _t._iO;\r | |
1333 | if (_t.playState == 1) {\r | |
1334 | var allowMulti = _t._iO.multiShot;\r | |
1335 | if (!allowMulti) {\r | |
1336 | _s._wD('SMSound.play(): "'+_t.sID+'" already playing (one-shot)',1);\r | |
1337 | return false;\r | |
1338 | } else {\r | |
1339 | _s._wD('SMSound.play(): "'+_t.sID+'" already playing (multi-shot)',1);\r | |
5ad04c7b CP |
1340 | }\r |
1341 | }\r | |
127631e0 | 1342 | if (!_t.loaded) {\r |
5ad04c7b | 1343 | if (_t.readyState === 0) {\r |
127631e0 CP |
1344 | _s._wD('SMSound.play(): Attempting to load "'+_t.sID+'"',1);\r |
1345 | // try to get this sound playing ASAP\r | |
1346 | _t._iO.stream = true;\r | |
1347 | _t._iO.autoPlay = true;\r | |
1348 | // TODO: need to investigate when false, double-playing\r | |
1349 | // if (typeof oOptions.autoPlay=='undefined') _tO.autoPlay = true; // only set autoPlay if unspecified here\r | |
1350 | _t.load(_t._iO); // try to get this sound playing ASAP\r | |
1351 | } else if (_t.readyState == 2) {\r | |
1352 | _s._wD('SMSound.play(): Could not load "'+_t.sID+'" - exiting',2);\r | |
1353 | return false;\r | |
1354 | } else {\r | |
1355 | _s._wD('SMSound.play(): "'+_t.sID+'" is loading - attempting to play..',1);\r | |
5ad04c7b | 1356 | }\r |
127631e0 CP |
1357 | } else {\r |
1358 | _s._wD('SMSound.play(): "'+_t.sID+'"');\r | |
5ad04c7b | 1359 | }\r |
127631e0 CP |
1360 | if (_t.paused) {\r |
1361 | _t.resume();\r | |
1362 | } else {\r | |
1363 | _t.playState = 1;\r | |
86f67adc | 1364 | if (!_t.instanceCount || _s.flashVersion > 8) {\r |
5ad04c7b CP |
1365 | _t.instanceCount++;\r |
1366 | }\r | |
127631e0 | 1367 | _t.position = (typeof _t._iO.position != 'undefined' && !isNaN(_t._iO.position)?_t._iO.position:0);\r |
5ad04c7b CP |
1368 | if (_t._iO.onplay) {\r |
1369 | _t._iO.onplay.apply(_t);\r | |
1370 | }\r | |
1371 | _t.setVolume(_t._iO.volume,true); // restrict volume to instance options only\r | |
1372 | _t.setPan(_t._iO.pan,true);\r | |
127631e0 | 1373 | _s.o._start(_t.sID,_t._iO.loop||1,(_s.flashVersion==9?_t.position:_t.position/1000));\r |
5ad04c7b | 1374 | }\r |
127631e0 CP |
1375 | };\r |
1376 | \r | |
1377 | this.start = this.play; // just for convenience\r | |
1378 | \r | |
1379 | this.stop = function(bAll) {\r | |
1380 | if (_t.playState == 1) {\r | |
1381 | _t.playState = 0;\r | |
1382 | _t.paused = false;\r | |
1383 | // if (_s.defaultOptions.onstop) _s.defaultOptions.onstop.apply(_s);\r | |
5ad04c7b CP |
1384 | if (_t._iO.onstop) {\r |
1385 | _t._iO.onstop.apply(_t);\r | |
1386 | }\r | |
127631e0 CP |
1387 | _s.o._stop(_t.sID,bAll);\r |
1388 | _t.instanceCount = 0;\r | |
1389 | _t._iO = {};\r | |
1390 | // _t.instanceOptions = _t._iO;\r | |
5ad04c7b | 1391 | }\r |
127631e0 CP |
1392 | };\r |
1393 | \r | |
5ad04c7b CP |
1394 | this.setPosition = function(nMsecOffset,bNoDebug) {\r |
1395 | if (typeof nMsecOffset == 'undefined') {\r | |
1396 | nMsecOffset = 0;\r | |
1397 | }\r | |
1398 | var offset = Math.min(_t.duration,Math.max(nMsecOffset,0)); // position >= 0 and <= current available (loaded) duration\r | |
1399 | _t._iO.position = offset;\r | |
1400 | if (!bNoDebug) {\r | |
86f67adc | 1401 | // _s._wD('SMSound.setPosition('+nMsecOffset+')'+(nMsecOffset != offset?', corrected value: '+offset:''));\r |
5ad04c7b | 1402 | }\r |
127631e0 CP |
1403 | _s.o._setPosition(_t.sID,(_s.flashVersion==9?_t._iO.position:_t._iO.position/1000),(_t.paused||!_t.playState)); // if paused or not playing, will not resume (by playing)\r |
1404 | };\r | |
1405 | \r | |
1406 | this.pause = function() {\r | |
5ad04c7b CP |
1407 | if (_t.paused || _t.playState === 0) {\r |
1408 | return false;\r | |
1409 | }\r | |
127631e0 CP |
1410 | _s._wD('SMSound.pause()');\r |
1411 | _t.paused = true;\r | |
1412 | _s.o._pause(_t.sID);\r | |
5ad04c7b CP |
1413 | if (_t._iO.onpause) {\r |
1414 | _t._iO.onpause.apply(_t);\r | |
1415 | }\r | |
127631e0 CP |
1416 | };\r |
1417 | \r | |
1418 | this.resume = function() {\r | |
5ad04c7b CP |
1419 | if (!_t.paused || _t.playState === 0) {\r |
1420 | return false;\r | |
1421 | }\r | |
127631e0 CP |
1422 | _s._wD('SMSound.resume()');\r |
1423 | _t.paused = false;\r | |
1424 | _s.o._pause(_t.sID); // flash method is toggle-based (pause/resume)\r | |
5ad04c7b CP |
1425 | if (_t._iO.onresume) {\r |
1426 | _t._iO.onresume.apply(_t);\r | |
1427 | }\r | |
127631e0 CP |
1428 | };\r |
1429 | \r | |
1430 | this.togglePause = function() {\r | |
1431 | _s._wD('SMSound.togglePause()');\r | |
86f67adc | 1432 | if (_t.playState === 0) {\r |
127631e0 CP |
1433 | _t.play({position:(_s.flashVersion==9?_t.position:_t.position/1000)});\r |
1434 | return false;\r | |
5ad04c7b | 1435 | }\r |
127631e0 CP |
1436 | if (_t.paused) {\r |
1437 | _t.resume();\r | |
1438 | } else {\r | |
1439 | _t.pause();\r | |
5ad04c7b | 1440 | }\r |
127631e0 CP |
1441 | };\r |
1442 | \r | |
5ad04c7b CP |
1443 | this.setPan = function(nPan,bInstanceOnly) {\r |
1444 | if (typeof nPan == 'undefined') {\r | |
1445 | nPan = 0;\r | |
1446 | }\r | |
1447 | if (typeof bInstanceOnly == 'undefined') {\r | |
1448 | bInstanceOnly = false;\r | |
1449 | }\r | |
127631e0 CP |
1450 | _s.o._setPan(_t.sID,nPan);\r |
1451 | _t._iO.pan = nPan;\r | |
5ad04c7b CP |
1452 | if (!bInstanceOnly) {\r |
1453 | _t.pan = nPan;\r | |
1454 | }\r | |
127631e0 CP |
1455 | };\r |
1456 | \r | |
5ad04c7b CP |
1457 | this.setVolume = function(nVol,bInstanceOnly) {\r |
1458 | if (typeof nVol == 'undefined') {\r | |
1459 | nVol = 100;\r | |
1460 | }\r | |
1461 | if (typeof bInstanceOnly == 'undefined') {\r | |
1462 | bInstanceOnly = false;\r | |
1463 | }\r | |
127631e0 CP |
1464 | _s.o._setVolume(_t.sID,(_s.muted&&!_t.muted)||_t.muted?0:nVol);\r |
1465 | _t._iO.volume = nVol;\r | |
5ad04c7b CP |
1466 | if (!bInstanceOnly) {\r |
1467 | _t.volume = nVol;\r | |
1468 | }\r | |
127631e0 CP |
1469 | };\r |
1470 | \r | |
1471 | this.mute = function() {\r | |
5ad04c7b | 1472 | _t.muted = true;\r |
127631e0 CP |
1473 | _s.o._setVolume(_t.sID,0);\r |
1474 | };\r | |
1475 | \r | |
1476 | this.unmute = function() {\r | |
5ad04c7b CP |
1477 | _t.muted = false;\r |
1478 | var hasIO = typeof _t._iO.volume != 'undefined';\r | |
86f67adc | 1479 | _s.o._setVolume(_t.sID,hasIO?_t._iO.volume:_t.options.volume);\r |
127631e0 CP |
1480 | };\r |
1481 | \r | |
1482 | // --- "private" methods called by Flash ---\r | |
1483 | \r | |
1484 | this._whileloading = function(nBytesLoaded,nBytesTotal,nDuration) {\r | |
1485 | if (!_t._iO.isMovieStar) {\r | |
1486 | _t.bytesLoaded = nBytesLoaded;\r | |
1487 | _t.bytesTotal = nBytesTotal;\r | |
1488 | _t.duration = Math.floor(nDuration);\r | |
86f67adc | 1489 | _t.durationEstimate = parseInt((_t.bytesTotal/_t.bytesLoaded)*_t.duration,10);\r |
5ad04c7b CP |
1490 | if (_t.readyState != 3 && _t._iO.whileloading) {\r |
1491 | _t._iO.whileloading.apply(_t);\r | |
1492 | }\r | |
127631e0 CP |
1493 | } else {\r |
1494 | _t.bytesLoaded = nBytesLoaded;\r | |
1495 | _t.bytesTotal = nBytesTotal;\r | |
1496 | _t.duration = Math.floor(nDuration);\r | |
1497 | _t.durationEstimate = _t.duration;\r | |
5ad04c7b CP |
1498 | if (_t.readyState != 3 && _t._iO.whileloading) {\r |
1499 | _t._iO.whileloading.apply(_t);\r | |
1500 | }\r | |
127631e0 CP |
1501 | }\r |
1502 | };\r | |
1503 | \r | |
1504 | this._onid3 = function(oID3PropNames,oID3Data) {\r | |
1505 | // oID3PropNames: string array (names)\r | |
1506 | // ID3Data: string array (data)\r | |
1507 | _s._wD('SMSound._onid3(): "'+this.sID+'" ID3 data received.');\r | |
1508 | var oData = [];\r | |
1509 | for (var i=0,j=oID3PropNames.length; i<j; i++) {\r | |
1510 | oData[oID3PropNames[i]] = oID3Data[i];\r | |
1511 | // _s._wD(oID3PropNames[i]+': '+oID3Data[i]);\r | |
5ad04c7b | 1512 | }\r |
127631e0 | 1513 | _t.id3 = _s._mergeObjects(_t.id3,oData);\r |
5ad04c7b CP |
1514 | if (_t._iO.onid3) {\r |
1515 | _t._iO.onid3.apply(_t);\r | |
1516 | }\r | |
127631e0 CP |
1517 | };\r |
1518 | \r | |
86f67adc CP |
1519 | this._whileplaying = function(nPosition,oPeakData,oWaveformDataLeft,oWaveformDataRight,oEQData) {\r |
1520 | \r | |
5ad04c7b CP |
1521 | if (isNaN(nPosition) || nPosition === null) {\r |
1522 | return false; // Flash may return NaN at times\r | |
1523 | }\r | |
86f67adc CP |
1524 | if (_t.playState === 0 && nPosition > 0) {\r |
1525 | // can happen at the end of a video where nPosition == 33 for some reason, after finishing.???\r | |
1526 | // can also happen with a normal stop operation. This resets the position to 0.\r | |
1527 | // _s._writeDebug('Note: Not playing, but position = '+nPosition);\r | |
1528 | nPosition = 0; \r | |
1529 | }\r | |
127631e0 CP |
1530 | _t.position = nPosition;\r |
1531 | if (_t._iO.usePeakData && typeof oPeakData != 'undefined' && oPeakData) {\r | |
1532 | _t.peakData = {\r | |
1533 | left: oPeakData.leftPeak,\r | |
1534 | right: oPeakData.rightPeak\r | |
1535 | };\r | |
5ad04c7b | 1536 | }\r |
86f67adc CP |
1537 | if (_t._iO.useWaveformData && typeof oWaveformDataLeft != 'undefined' && oWaveformDataLeft) {\r |
1538 | _t.waveformData = {\r | |
1539 | left: oWaveformDataLeft.split(','),\r | |
1540 | right: oWaveformDataRight.split(',')\r | |
1541 | };\r | |
5ad04c7b | 1542 | }\r |
127631e0 CP |
1543 | if (_t._iO.useEQData && typeof oEQData != 'undefined' && oEQData) {\r |
1544 | _t.eqData = oEQData;\r | |
5ad04c7b | 1545 | }\r |
127631e0 | 1546 | if (_t.playState == 1) {\r |
86f67adc CP |
1547 | // special case/hack: ensure buffering is false (instant load from cache, thus buffering stuck at 1?)\r |
1548 | if (_t.isBuffering) {\r | |
1549 | _t._onbufferchange(0);\r | |
1550 | }\r | |
127631e0 | 1551 | if (_t._iO.whileplaying) {\r |
86f67adc | 1552 | _t._iO.whileplaying.apply(_t); // flash may call after actual finish\r |
5ad04c7b | 1553 | }\r |
127631e0 CP |
1554 | if (_t.loaded && _t._iO.onbeforefinish && _t._iO.onbeforefinishtime && !_t.didBeforeFinish && _t.duration-_t.position <= _t._iO.onbeforefinishtime) {\r |
1555 | _s._wD('duration-position <= onbeforefinishtime: '+_t.duration+' - '+_t.position+' <= '+_t._iO.onbeforefinishtime+' ('+(_t.duration-_t.position)+')');\r | |
1556 | _t._onbeforefinish();\r | |
5ad04c7b CP |
1557 | }\r |
1558 | }\r | |
127631e0 CP |
1559 | };\r |
1560 | \r | |
1561 | this._onload = function(bSuccess) {\r | |
1562 | bSuccess = (bSuccess==1?true:false);\r | |
86f67adc | 1563 | _s._wD('SMSound._onload(): "'+_t.sID+'"'+(bSuccess?' loaded.':' failed to load? - '+_t.url),(bSuccess?1:2));\r |
127631e0 | 1564 | if (!bSuccess) {\r |
5ad04c7b | 1565 | if (_s.sandbox.noRemote === true) {\r |
127631e0 | 1566 | _s._wD('SMSound._onload(): Reminder: Flash security is denying network/internet access',1);\r |
5ad04c7b CP |
1567 | }\r |
1568 | if (_s.sandbox.noLocal === true) {\r | |
127631e0 | 1569 | _s._wD('SMSound._onload(): Reminder: Flash security is denying local access',1);\r |
5ad04c7b CP |
1570 | }\r |
1571 | }\r | |
127631e0 CP |
1572 | _t.loaded = bSuccess;\r |
1573 | _t.readyState = bSuccess?3:2;\r | |
1574 | if (_t._iO.onload) {\r | |
1575 | _t._iO.onload.apply(_t);\r | |
5ad04c7b | 1576 | }\r |
127631e0 CP |
1577 | };\r |
1578 | \r | |
1579 | this._onbeforefinish = function() {\r | |
1580 | if (!_t.didBeforeFinish) {\r | |
1581 | _t.didBeforeFinish = true;\r | |
1582 | if (_t._iO.onbeforefinish) {\r | |
1583 | _s._wD('SMSound._onbeforefinish(): "'+_t.sID+'"');\r | |
1584 | _t._iO.onbeforefinish.apply(_t);\r | |
1585 | }\r | |
5ad04c7b | 1586 | }\r |
127631e0 CP |
1587 | };\r |
1588 | \r | |
1589 | this._onjustbeforefinish = function(msOffset) {\r | |
1590 | // msOffset: "end of sound" delay actual value (eg. 200 msec, value at event fire time was 187)\r | |
1591 | if (!_t.didJustBeforeFinish) {\r | |
1592 | _t.didJustBeforeFinish = true;\r | |
1593 | if (_t._iO.onjustbeforefinish) {\r | |
1594 | _s._wD('SMSound._onjustbeforefinish(): "'+_t.sID+'"');\r | |
1595 | _t._iO.onjustbeforefinish.apply(_t);\r | |
1596 | }\r | |
5ad04c7b | 1597 | }\r |
127631e0 CP |
1598 | };\r |
1599 | \r | |
1600 | this._onfinish = function() {\r | |
1601 | // sound has finished playing\r | |
5ad04c7b CP |
1602 | \r |
1603 | // TODO: calling user-defined onfinish() should happen after setPosition(0)\r | |
1604 | // OR: onfinish() and then setPosition(0) is bad.\r | |
5ad04c7b CP |
1605 | if (_t._iO.onbeforefinishcomplete) {\r |
1606 | _t._iO.onbeforefinishcomplete.apply(_t);\r | |
127631e0 | 1607 | }\r |
127631e0 | 1608 | // reset some state items\r |
127631e0 CP |
1609 | _t.didBeforeFinish = false;\r |
1610 | _t.didJustBeforeFinish = false;\r | |
1611 | if (_t.instanceCount) {\r | |
1612 | _t.instanceCount--;\r | |
1613 | if (!_t.instanceCount) {\r | |
1614 | // reset instance options\r | |
5ad04c7b CP |
1615 | // _t.setPosition(0);\r |
1616 | _t.playState = 0;\r | |
1617 | _t.paused = false;\r | |
127631e0 CP |
1618 | _t.instanceCount = 0;\r |
1619 | _t.instanceOptions = {};\r | |
5ad04c7b CP |
1620 | if (_t._iO.onfinish) {\r |
1621 | _s._wD('SMSound._onfinish(): "'+_t.sID+'"');\r | |
1622 | _t._iO.onfinish.apply(_t);\r | |
1623 | }\r | |
127631e0 | 1624 | }\r |
5ad04c7b | 1625 | } else {\r |
86f67adc CP |
1626 | if (_t.useVideo) {\r |
1627 | // video has finished\r | |
1628 | // may need to reset position for next play call, "rewind"\r | |
1629 | // _t.setPosition(0);\r | |
1630 | }\r | |
5ad04c7b | 1631 | // _t.setPosition(0);\r |
127631e0 | 1632 | }\r |
86f67adc | 1633 | \r |
127631e0 CP |
1634 | };\r |
1635 | \r | |
1636 | this._onmetadata = function(oMetaData) {\r | |
1637 | // movieStar mode only\r | |
1638 | _s._wD('SMSound.onmetadata()');\r | |
1639 | // Contains a subset of metadata. Note that files may have their own unique metadata.\r | |
1640 | // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000267.html\r | |
1641 | if (!oMetaData.width && !oMetaData.height) {\r | |
1642 | _s._wD('No width/height given, assuming defaults');\r | |
1643 | oMetaData.width = 320;\r | |
1644 | oMetaData.height = 240;\r | |
5ad04c7b | 1645 | }\r |
127631e0 CP |
1646 | _t.metadata = oMetaData; // potentially-large object from flash\r |
1647 | _t.width = oMetaData.width;\r | |
1648 | _t.height = oMetaData.height;\r | |
1649 | if (_t._iO.onmetadata) {\r | |
1650 | _s._wD('SMSound._onmetadata(): "'+_t.sID+'"');\r | |
1651 | _t._iO.onmetadata.apply(_t);\r | |
1652 | }\r | |
5ad04c7b | 1653 | _s._wD('SMSound.onmetadata() complete');\r |
127631e0 CP |
1654 | };\r |
1655 | \r | |
86f67adc CP |
1656 | this._onbufferchange = function(bIsBuffering) {\r |
1657 | if (_t.playState === 0) {\r | |
1658 | // ignore if not playing\r | |
1659 | return false;\r | |
1660 | }\r | |
1661 | if (bIsBuffering == _t.isBuffering) {\r | |
1662 | // ignore initial "false" default, if matching\r | |
1663 | _s._wD('_onbufferchange: ignoring false default / loaded sound');\r | |
1664 | return false;\r | |
1665 | }\r | |
1666 | _t.isBuffering = (bIsBuffering==1?true:false);\r | |
1667 | if (_t._iO.onbufferchange) {\r | |
1668 | _s._wD('SMSound._onbufferchange(): '+bIsBuffering);\r | |
1669 | _t._iO.onbufferchange.apply(_t);\r | |
1670 | }\r | |
1671 | };\r | |
1672 | \r | |
1673 | this._ondataerror = function(sError) {\r | |
1674 | // flash 9 wave/eq data handler\r | |
1675 | if (_t.playState > 0) { // hack: called at start, and end from flash at/after onfinish().\r | |
1676 | _s._wD('SMSound._ondataerror(): '+sError);\r | |
1677 | if (_t._iO.ondataerror) {\r | |
1678 | _t._iO.ondataerror.apply(_t); \r | |
1679 | }\r | |
1680 | } else {\r | |
1681 | // _s._wD('SMSound._ondataerror(): ignoring');\r | |
1682 | }\r | |
1683 | };\r | |
1684 | \r | |
127631e0 CP |
1685 | }; // SMSound()\r |
1686 | \r | |
86f67adc CP |
1687 | this._onfullscreenchange = function(bFullScreen) {\r |
1688 | _s._wD('onfullscreenchange(): '+bFullScreen);\r | |
1689 | _s.isFullScreen = (bFullScreen==1?true:false);\r | |
1690 | if (!_s.isFullScreen) {\r | |
1691 | // attempt to restore window focus after leaving full-screen\r | |
1692 | try {\r | |
1693 | window.focus();\r | |
1694 | _s._wD('window.focus()');\r | |
1695 | } catch(e) {\r | |
1696 | // oh well\r | |
1697 | }\r | |
1698 | }\r | |
1699 | };\r | |
1700 | \r | |
127631e0 CP |
1701 | // register a few event handlers\r |
1702 | if (window.addEventListener) {\r | |
1703 | window.addEventListener('focus',_s.handleFocus,false);\r | |
1704 | window.addEventListener('load',_s.beginDelayedInit,false);\r | |
1705 | window.addEventListener('unload',_s.destruct,false);\r | |
5ad04c7b CP |
1706 | if (_s._tryInitOnFocus) {\r |
1707 | window.addEventListener('mousemove',_s.handleFocus,false); // massive Safari focus hack\r | |
1708 | }\r | |
127631e0 CP |
1709 | } else if (window.attachEvent) {\r |
1710 | window.attachEvent('onfocus',_s.handleFocus);\r | |
1711 | window.attachEvent('onload',_s.beginDelayedInit);\r | |
1712 | window.attachEvent('unload',_s.destruct);\r | |
1713 | } else {\r | |
1714 | // no add/attachevent support - safe to assume no JS -> Flash either.\r | |
5ad04c7b | 1715 | _s._debugTS('onload',false);\r |
127631e0 CP |
1716 | soundManager.onerror();\r |
1717 | soundManager.disable();\r | |
5ad04c7b CP |
1718 | }\r |
1719 | \r | |
1720 | if (document.addEventListener) {\r | |
1721 | document.addEventListener('DOMContentLoaded',_s.domContentLoaded,false);\r | |
1722 | }\r | |
127631e0 | 1723 | \r |
5ad04c7b | 1724 | } // SoundManager()\r |
127631e0 | 1725 | \r |
86f67adc CP |
1726 | // set var SM2_DEFER = true; in your own script to prevent auto start-up\r |
1727 | if (typeof SM2_DEFER == 'undefined' || !SM2_DEFER) {\r | |
1728 | soundManager = new SoundManager();\r | |
1729 | } |