]>
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 | |
10 | V2.90a.20081028\r | |
11 | */\r | |
12 | \r | |
13 | function SoundManager(smURL,smID) {\r | |
14 | \r | |
15 | this.flashVersion = 8; // version of flash to require, either 8 or 9. Some API features require Flash 9.\r | |
16 | this.debugMode = true; // enable debugging output (div#soundmanager-debug, OR console if available + configured)\r | |
17 | this.useConsole = true; // use firebug/safari console.log()-type debug console if available\r | |
18 | this.consoleOnly = false; // if console is being used, do not create/write to #soundmanager-debug\r | |
19 | this.waitForWindowLoad = false; // force SM2 to wait for window.onload() before trying to call soundManager.onload()\r | |
20 | this.nullURL = 'null.mp3'; // path to "null" (empty) MP3 file, used to unload sounds (Flash 8 only)\r | |
21 | this.allowPolling = true; // allow flash to poll for status update (required for "while playing", peak, sound spectrum functions to work.)\r | |
22 | this.useMovieStar = false; // enable support for Flash 9.0r115+ (codename "MovieStar") MPEG4 audio + video formats (AAC, M4V, FLV, MOV etc.)\r | |
23 | this.useHighPerformance = true; // flash positioning trick, improves JS/flash callback speed, minimizes delay\r | |
24 | this.bgColor = '#ffffff'; // movie (.swf) background color, useful if showing on-screen for video etc.\r | |
25 | \r | |
26 | this.defaultOptions = {\r | |
27 | '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 | |
28 | 'stream': true, // allows playing before entire file has loaded (recommended)\r | |
29 | 'autoPlay': false, // enable playing of file as soon as possible (much faster if "stream" is true)\r | |
30 | 'onid3': null, // callback function for "ID3 data is added/available"\r | |
31 | 'onload': null, // callback function for "load finished"\r | |
32 | 'whileloading': null, // callback function for "download progress update" (X of Y bytes received)\r | |
33 | 'onplay': null, // callback for "play" start\r | |
34 | 'onpause': null, // callback for "pause"\r | |
35 | 'onresume': null, // callback for "resume" (pause toggle)\r | |
36 | 'whileplaying': null, // callback during play (position update)\r | |
37 | 'onstop': null, // callback for "user stop"\r | |
38 | 'onfinish': null, // callback function for "sound finished playing"\r | |
39 | 'onbeforefinish': null, // callback for "before sound finished playing (at [time])"\r | |
40 | 'onbeforefinishtime': 5000, // offset (milliseconds) before end of sound to trigger beforefinish (eg. 1000 msec = 1 second)\r | |
41 | 'onbeforefinishcomplete':null, // function to call when said sound finishes playing\r | |
42 | 'onjustbeforefinish':null, // callback for [n] msec before end of current sound\r | |
43 | 'onjustbeforefinishtime':200, // [n] - if not using, set to 0 (or null handler) and event will not fire.\r | |
44 | '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 | |
45 | 'position': null, // offset (milliseconds) to seek to within loaded sound data.\r | |
46 | 'pan': 0, // "pan" settings, left-to-right, -100 to 100\r | |
47 | 'volume': 100 // self-explanatory. 0-100, the latter being the max.\r | |
48 | };\r | |
49 | \r | |
50 | this.flash9Options = { // flash 9-only options, merged into defaultOptions if flash 9 is being used\r | |
51 | 'isMovieStar': null, // "MovieStar" MPEG4 audio/video mode. Null (default) = auto detect MP4, AAC etc. based on URL. true = force on, ignore URL\r | |
52 | 'usePeakData': false, // enable left/right channel peak (level) data\r | |
53 | 'useWaveformData': false, // enable sound spectrum (raw waveform data) - WARNING: CPU-INTENSIVE: may set CPUs on fire.\r | |
54 | 'useEQData': false // enable sound EQ (frequency spectrum data) - WARNING: Also CPU-intensive.\r | |
55 | };\r | |
56 | \r | |
57 | this.movieStarOptions = { // flash 9.0r115+ MPEG4 audio/video options, merged into defaultOptions if flash 9 + movieStar mode is enabled\r | |
58 | 'onmetadata': null, // callback for when video width/height etc. are received\r | |
59 | 'useVideo': false // if loading movieStar content, whether to show video\r | |
60 | }\r | |
61 | \r | |
62 | this.flashBlockHelper = {\r | |
63 | 'enabled': false, // experimental, removed with >v2.80\r | |
64 | 'message': [] // "nag bar" to show when messaging the user, if SM2 fails on firefox etc.\r | |
65 | };\r | |
66 | \r | |
67 | var _s = this; \r | |
68 | this.version = null;\r | |
69 | this.versionNumber = 'V2.90a.20081028';\r | |
70 | this.movieURL = null;\r | |
71 | this.url = null;\r | |
72 | this.altURL = null;\r | |
73 | this.swfLoaded = false;\r | |
74 | this.enabled = false;\r | |
75 | this.o = null;\r | |
76 | this.id = (smID||'sm2movie');\r | |
77 | this.oMC = null;\r | |
78 | this.sounds = [];\r | |
79 | this.soundIDs = [];\r | |
80 | this.muted = false;\r | |
81 | this.isIE = (navigator.userAgent.match(/MSIE/i));\r | |
82 | this.isSafari = (navigator.userAgent.match(/safari/i));\r | |
83 | this.isGecko = (navigator.userAgent.match(/gecko/i));\r | |
84 | this.debugID = 'soundmanager-debug';\r | |
85 | this._debugOpen = true;\r | |
86 | this._didAppend = false;\r | |
87 | this._appendSuccess = false;\r | |
88 | this._didInit = false;\r | |
89 | this._disabled = false;\r | |
90 | this._windowLoaded = false;\r | |
91 | this._hasConsole = (typeof console != 'undefined' && typeof console.log != 'undefined');\r | |
92 | this._debugLevels = ['log','info','warn','error'];\r | |
93 | this._defaultFlashVersion = 8;\r | |
94 | this.filePatterns = {\r | |
95 | flash8: /\.(mp3)/i,\r | |
96 | flash9: /\.(mp3)/i\r | |
97 | };\r | |
98 | this.netStreamTypes = ['aac','flv','mov','mp4','m4v','f4v','m4a','mp4v','3gp','3g2']; // Flash v9.0r115+ "moviestar" formats\r | |
99 | this.netStreamPattern = new RegExp('.('+this.netStreamTypes.join('|')+')','i');\r | |
100 | this.filePattern = null;\r | |
101 | this.features = {\r | |
102 | peakData: false,\r | |
103 | waveformData: false,\r | |
104 | eqData: false\r | |
105 | };\r | |
106 | \r | |
107 | this.sandbox = {\r | |
108 | 'type': null,\r | |
109 | 'types': {\r | |
110 | 'remote': 'remote (domain-based) rules',\r | |
111 | 'localWithFile': 'local with file access (no internet access)',\r | |
112 | 'localWithNetwork': 'local with network (internet access only, no local access)',\r | |
113 | 'localTrusted': 'local, trusted (local + internet access)'\r | |
114 | },\r | |
115 | 'description': null,\r | |
116 | 'noRemote': null,\r | |
117 | 'noLocal': null\r | |
118 | };\r | |
119 | \r | |
120 | this._setVersionInfo = function() {\r | |
121 | if (_s.flashVersion != 8 && _s.flashVersion != 9) {\r | |
122 | alert('soundManager.flashVersion must be 8 or 9. "'+_s.flashVersion+'" is invalid. Reverting to '+_s._defaultFlashVersion+'.');\r | |
123 | _s.flashVersion = _s._defaultFlashVersion;\r | |
124 | }\r | |
125 | _s.version = _s.versionNumber+(_s.flashVersion==9?' (AS3/Flash 9)':' (AS2/Flash 8)');\r | |
126 | // set up default options\r | |
127 | if (_s.flashVersion > 8) {\r | |
128 | _s.defaultOptions = _s._mergeObjects(_s.defaultOptions,_s.flash9Options);\r | |
129 | }\r | |
130 | if (_s.flashVersion > 8 && _s.useMovieStar) {\r | |
131 | _s.defaultOptions = _s._mergeObjects(_s.defaultOptions,_s.movieStarOptions);\r | |
132 | _s.filePatterns.flash9 = new RegExp('.(mp3|'+_s.netStreamTypes.join('|')+')','i');\r | |
133 | } else {\r | |
134 | _s.useMovieStar = false;\r | |
135 | }\r | |
136 | _s.filePattern = _s.filePatterns[(_s.flashVersion!=8?'flash9':'flash8')];\r | |
137 | _s.movieURL = (_s.flashVersion==8?'soundmanager2.swf':'soundmanager2_flash9.swf');\r | |
138 | _s.features.peakData = _s.features.waveformData = _s.features.eqData = (_s.flashVersion==9);\r | |
139 | }\r | |
140 | \r | |
141 | this._overHTTP = (document.location?document.location.protocol.match(/http/i):null);\r | |
142 | this._waitingforEI = false;\r | |
143 | this._initPending = false;\r | |
144 | this._tryInitOnFocus = (this.isSafari && typeof document.hasFocus == 'undefined');\r | |
145 | this._isFocused = (typeof document.hasFocus != 'undefined'?document.hasFocus():null);\r | |
146 | this._okToDisable = !this._tryInitOnFocus;\r | |
147 | \r | |
148 | this.useAltURL = !this._overHTTP; // use altURL if not "online"\r | |
149 | \r | |
150 | var flashCPLink = 'http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html';\r | |
151 | \r | |
152 | // --- public methods ---\r | |
153 | \r | |
154 | this.supported = function() {\r | |
155 | return (_s._didInit && !_s._disabled);\r | |
156 | };\r | |
157 | \r | |
158 | this.getMovie = function(smID) {\r | |
159 | return _s.isIE?window[smID]:(_s.isSafari?document.getElementById(smID)||document[smID]:document.getElementById(smID));\r | |
160 | };\r | |
161 | \r | |
162 | this.loadFromXML = function(sXmlUrl) {\r | |
163 | try {\r | |
164 | _s.o._loadFromXML(sXmlUrl);\r | |
165 | } catch(e) {\r | |
166 | _s._failSafely();\r | |
167 | return true;\r | |
168 | };\r | |
169 | };\r | |
170 | \r | |
171 | this.createSound = function(oOptions) {\r | |
172 | if (!_s._didInit) throw new Error('soundManager.createSound(): Not loaded yet - wait for soundManager.onload() before calling sound-related methods');\r | |
173 | if (arguments.length==2) {\r | |
174 | // function overloading in JS! :) ..assume simple createSound(id,url) use case\r | |
175 | var oOptions = {'id':arguments[0],'url':arguments[1]};\r | |
176 | };\r | |
177 | var thisOptions = _s._mergeObjects(oOptions); // inherit SM2 defaults\r | |
178 | var _tO = thisOptions; // alias\r | |
179 | _s._wD('soundManager.createSound(): '+_tO.id+' ('+_tO.url+')',1);\r | |
180 | if (_s._idCheck(_tO.id,true)) {\r | |
181 | _s._wD('soundManager.createSound(): '+_tO.id+' exists',1);\r | |
182 | return _s.sounds[_tO.id];\r | |
183 | };\r | |
184 | if (_s.flashVersion > 8 && _s.useMovieStar) {\r | |
185 | if (_tO.isMovieStar == null) {\r | |
186 | _tO.isMovieStar = (_tO.url.match(_s.netStreamPattern)?true:false);\r | |
187 | }\r | |
188 | if (_tO.isMovieStar) {\r | |
189 | _s._wD('soundManager.createSound(): using MovieStar handling');\r | |
190 | }\r | |
191 | if (_tO.isMovieStar && (_tO.usePeakData || _tO.useWaveformData || _tO.useEQData)) {\r | |
192 | _s._wD('Warning: peak/waveform/eqData features unsupported for non-MP3 formats');\r | |
193 | _tO.usePeakData = false;\r | |
194 | _tO.useWaveformData = false;\r | |
195 | _tO.useEQData = false;\r | |
196 | }\r | |
197 | };\r | |
198 | _s.sounds[_tO.id] = new SMSound(_tO);\r | |
199 | _s.soundIDs[_s.soundIDs.length] = _tO.id;\r | |
200 | // AS2:\r | |
201 | if (_s.flashVersion == 8) {\r | |
202 | _s.o._createSound(_tO.id,_tO.onjustbeforefinishtime);\r | |
203 | } else {\r | |
204 | _s.o._createSound(_tO.id,_tO.url,_tO.onjustbeforefinishtime,_tO.usePeakData,_tO.useWaveformData,_tO.useEQData,_tO.isMovieStar,(_tO.isMovieStar?_tO.useVideo:false));\r | |
205 | };\r | |
206 | if (_tO.autoLoad || _tO.autoPlay) {\r | |
207 | window.setTimeout(function() {\r | |
208 | if (_s.sounds[_tO.id]) {\r | |
209 | _s.sounds[_tO.id].load(_tO);\r | |
210 | }\r | |
211 | },20);\r | |
212 | }\r | |
213 | if (_tO.autoPlay) {\r | |
214 | if (_s.flashVersion == 8) {\r | |
215 | _s.sounds[_tO.id].playState = 1; // we can only assume this sound will be playing soon.\r | |
216 | } else {\r | |
217 | _s.sounds[_tO.id].play(); \r | |
218 | }\r | |
219 | }\r | |
220 | return _s.sounds[_tO.id];\r | |
221 | };\r | |
222 | \r | |
223 | this.createVideo = function(oOptions) {\r | |
224 | if (arguments.length==2) {\r | |
225 | var oOptions = {'id':arguments[0],'url':arguments[1]};\r | |
226 | };\r | |
227 | if (_s.flashVersion >= 9) {\r | |
228 | oOptions.isMovieStar = true;\r | |
229 | oOptions.useVideo = true;\r | |
230 | } else {\r | |
231 | _s._wD('soundManager.createVideo(): flash 9 required for video. Exiting.',2);\r | |
232 | return false;\r | |
233 | }\r | |
234 | if (!_s.useMovieStar) {\r | |
235 | _s._wD('soundManager.createVideo(): MovieStar mode not enabled. Exiting.',2);\r | |
236 | }\r | |
237 | return _s.createSound(oOptions);\r | |
238 | }\r | |
239 | \r | |
240 | this.destroySound = function(sID,bFromSound) {\r | |
241 | // explicitly destroy a sound before normal page unload, etc.\r | |
242 | if (!_s._idCheck(sID)) return false;\r | |
243 | for (var i=0; i<_s.soundIDs.length; i++) {\r | |
244 | if (_s.soundIDs[i] == sID) {\r | |
245 | _s.soundIDs.splice(i,1);\r | |
246 | continue;\r | |
247 | };\r | |
248 | };\r | |
249 | // conservative option: avoid crash with ze flash 8\r | |
250 | // calling destroySound() within a sound onload() might crash firefox, certain flavours of winXP + flash 8??\r | |
251 | // if (_s.flashVersion != 8) {\r | |
252 | _s.sounds[sID].unload();\r | |
253 | // }\r | |
254 | if (!bFromSound) {\r | |
255 | // ignore if being called from SMSound instance\r | |
256 | _s.sounds[sID].destruct();\r | |
257 | };\r | |
258 | delete _s.sounds[sID];\r | |
259 | };\r | |
260 | \r | |
261 | this.destroyVideo = this.destroySound;\r | |
262 | \r | |
263 | this.load = function(sID,oOptions) {\r | |
264 | if (!_s._idCheck(sID)) return false;\r | |
265 | _s.sounds[sID].load(oOptions);\r | |
266 | };\r | |
267 | \r | |
268 | this.unload = function(sID) {\r | |
269 | if (!_s._idCheck(sID)) return false;\r | |
270 | _s.sounds[sID].unload();\r | |
271 | };\r | |
272 | \r | |
273 | this.play = function(sID,oOptions) {\r | |
274 | if (!_s._idCheck(sID)) {\r | |
275 | if (typeof oOptions != 'Object') oOptions = {url:oOptions}; // overloading use case: play('mySound','/path/to/some.mp3');\r | |
276 | if (oOptions && oOptions.url) {\r | |
277 | // overloading use case, creation + playing of sound: .play('someID',{url:'/path/to.mp3'});\r | |
278 | _s._wD('soundController.play(): attempting to create "'+sID+'"',1);\r | |
279 | oOptions.id = sID;\r | |
280 | _s.createSound(oOptions);\r | |
281 | } else {\r | |
282 | return false;\r | |
283 | };\r | |
284 | };\r | |
285 | _s.sounds[sID].play(oOptions);\r | |
286 | };\r | |
287 | \r | |
288 | this.start = this.play; // just for convenience\r | |
289 | \r | |
290 | this.setPosition = function(sID,nMsecOffset) {\r | |
291 | if (!_s._idCheck(sID)) return false;\r | |
292 | nMsecOffset = Math.min((nMsecOffset||0),_s.duration); // don't allow seek past loaded duration\r | |
293 | _s.sounds[sID].setPosition(nMsecOffset);\r | |
294 | };\r | |
295 | \r | |
296 | this.stop = function(sID) {\r | |
297 | if (!_s._idCheck(sID)) return false;\r | |
298 | _s._wD('soundManager.stop('+sID+')',1);\r | |
299 | _s.sounds[sID].stop(); \r | |
300 | };\r | |
301 | \r | |
302 | this.stopAll = function() {\r | |
303 | _s._wD('soundManager.stopAll()',1);\r | |
304 | for (var oSound in _s.sounds) {\r | |
305 | if (_s.sounds[oSound] instanceof SMSound) _s.sounds[oSound].stop(); // apply only to sound objects\r | |
306 | };\r | |
307 | };\r | |
308 | \r | |
309 | this.pause = function(sID) {\r | |
310 | if (!_s._idCheck(sID)) return false;\r | |
311 | _s.sounds[sID].pause();\r | |
312 | };\r | |
313 | \r | |
314 | this.pauseAll = function() {\r | |
315 | for (var i=_s.soundIDs.length; i--;) {\r | |
316 | _s.sounds[_s.soundIDs[i]].pause();\r | |
317 | }\r | |
318 | };\r | |
319 | \r | |
320 | this.resume = function(sID) {\r | |
321 | if (!_s._idCheck(sID)) return false;\r | |
322 | _s.sounds[sID].resume();\r | |
323 | };\r | |
324 | \r | |
325 | this.resumeAll = function() {\r | |
326 | for (var i=_s.soundIDs.length; i--;) {\r | |
327 | _s.sounds[_s.soundIDs[i]].resume();\r | |
328 | }\r | |
329 | };\r | |
330 | \r | |
331 | this.togglePause = function(sID) {\r | |
332 | if (!_s._idCheck(sID)) return false;\r | |
333 | _s.sounds[sID].togglePause();\r | |
334 | };\r | |
335 | \r | |
336 | this.setPan = function(sID,nPan) {\r | |
337 | if (!_s._idCheck(sID)) return false;\r | |
338 | _s.sounds[sID].setPan(nPan);\r | |
339 | };\r | |
340 | \r | |
341 | this.setVolume = function(sID,nVol) {\r | |
342 | if (!_s._idCheck(sID)) return false;\r | |
343 | _s.sounds[sID].setVolume(nVol);\r | |
344 | };\r | |
345 | \r | |
346 | this.mute = function(sID) {\r | |
347 | if (typeof sID != 'string') sID = null;\r | |
348 | if (!sID) {\r | |
349 | var o = null;\r | |
350 | _s._wD('soundManager.mute(): Muting all sounds');\r | |
351 | for (var i=_s.soundIDs.length; i--;) {\r | |
352 | _s.sounds[_s.soundIDs[i]].mute();\r | |
353 | }\r | |
354 | _s.muted = true;\r | |
355 | } else {\r | |
356 | if (!_s._idCheck(sID)) return false;\r | |
357 | _s._wD('soundManager.mute(): Muting "'+sID+'"');\r | |
358 | _s.sounds[sID].mute();\r | |
359 | }\r | |
360 | };\r | |
361 | \r | |
362 | this.muteAll = function() {\r | |
363 | _s.mute();\r | |
364 | };\r | |
365 | \r | |
366 | this.unmute = function(sID) {\r | |
367 | if (typeof sID != 'string') sID = null;\r | |
368 | if (!sID) {\r | |
369 | var o = null;\r | |
370 | _s._wD('soundManager.unmute(): Unmuting all sounds');\r | |
371 | for (var i=_s.soundIDs.length; i--;) {\r | |
372 | _s.sounds[_s.soundIDs[i]].unmute();\r | |
373 | }\r | |
374 | _s.muted = false;\r | |
375 | } else {\r | |
376 | if (!_s._idCheck(sID)) return false;\r | |
377 | _s._wD('soundManager.unmute(): Unmuting "'+sID+'"');\r | |
378 | _s.sounds[sID].unmute();\r | |
379 | }\r | |
380 | };\r | |
381 | \r | |
382 | this.unmuteAll = function() {\r | |
383 | _s.unmute();\r | |
384 | };\r | |
385 | \r | |
386 | this.setPolling = function(bPolling) {\r | |
387 | if (!_s.o || !_s.allowPolling) return false;\r | |
388 | // _s._wD('soundManager.setPolling('+bPolling+')');\r | |
389 | _s.o._setPolling(bPolling);\r | |
390 | };\r | |
391 | \r | |
392 | this.disable = function(bUnload) {\r | |
393 | // destroy all functions\r | |
394 | if (_s._disabled) return false;\r | |
395 | _s._disabled = true;\r | |
396 | _s._wD('soundManager.disable(): Disabling all functions - future calls will return false.',1);\r | |
397 | for (var i=_s.soundIDs.length; i--;) {\r | |
398 | _s._disableObject(_s.sounds[_s.soundIDs[i]]);\r | |
399 | };\r | |
400 | _s.initComplete(); // fire "complete", despite fail\r | |
401 | _s._disableObject(_s);\r | |
402 | };\r | |
403 | \r | |
404 | this.handleFlashBlock = function(bForce) {\r | |
405 | // experimental, removed with >v2.80.\r | |
406 | return false;\r | |
407 | };\r | |
408 | \r | |
409 | this.canPlayURL = function(sURL) {\r | |
410 | return (sURL?(sURL.match(_s.filePattern)?true:false):null); \r | |
411 | };\r | |
412 | \r | |
413 | this.getSoundById = function(sID,suppressDebug) {\r | |
414 | if (!sID) throw new Error('SoundManager.getSoundById(): sID is null/undefined');\r | |
415 | var result = _s.sounds[sID];\r | |
416 | if (!result && !suppressDebug) {\r | |
417 | _s._wD('"'+sID+'" is an invalid sound ID.',2);\r | |
418 | // soundManager._wD('trace: '+arguments.callee.caller);\r | |
419 | };\r | |
420 | return result;\r | |
421 | };\r | |
422 | \r | |
423 | this.onload = function() {\r | |
424 | // window.onload() equivalent for SM2, ready to create sounds etc.\r | |
425 | // this is a stub - you can override this in your own external script, eg. soundManager.onload = function() {}\r | |
426 | soundManager._wD('<em>Warning</em>: soundManager.onload() is undefined.',2);\r | |
427 | };\r | |
428 | \r | |
429 | this.onerror = function() {\r | |
430 | // stub for user handler, called when SM2 fails to load/init\r | |
431 | };\r | |
432 | \r | |
433 | // --- "private" methods ---\r | |
434 | \r | |
435 | this._idCheck = this.getSoundById;\r | |
436 | \r | |
437 | this._disableObject = function(o) {\r | |
438 | for (var oProp in o) {\r | |
439 | if (typeof o[oProp] == 'function' && typeof o[oProp]._protected == 'undefined') o[oProp] = function(){return false;};\r | |
440 | };\r | |
441 | oProp = null;\r | |
442 | };\r | |
443 | \r | |
444 | this._failSafely = function() {\r | |
445 | // exception handler for "object doesn't support this property or method" or general failure\r | |
446 | var fpgssTitle = 'You may need to whitelist this location/domain eg. file:///C:/ or C:/ or mysite.com, or set ALWAYS ALLOW under the Flash Player Global Security Settings page. The latter is probably less-secure.';\r | |
447 | var flashCPL = '<a href="'+flashCPLink+'" title="'+fpgssTitle+'">view/edit</a>';\r | |
448 | var FPGSS = '<a href="'+flashCPLink+'" title="Flash Player Global Security Settings">FPGSS</a>';\r | |
449 | if (!_s._disabled) {\r | |
450 | _s._wD('soundManager: Failed to initialise.',2);\r | |
451 | _s.disable();\r | |
452 | };\r | |
453 | };\r | |
454 | \r | |
455 | this._normalizeMovieURL = function(smURL) {\r | |
456 | if (smURL) {\r | |
457 | if (smURL.match(/\.swf/)) {\r | |
458 | smURL = smURL.substr(0,smURL.lastIndexOf('.swf'));\r | |
459 | }\r | |
460 | if (smURL.lastIndexOf('/') != smURL.length-1) {\r | |
461 | smURL = smURL+'/';\r | |
462 | }\r | |
463 | }\r | |
464 | return(smURL && smURL.lastIndexOf('/')!=-1?smURL.substr(0,smURL.lastIndexOf('/')+1):'./')+_s.movieURL;\r | |
465 | };\r | |
466 | \r | |
467 | this._getDocument = function() {\r | |
468 | return (document.body?document.body:(document.documentElement?document.documentElement:document.getElementsByTagName('div')[0]));\r | |
469 | };\r | |
470 | \r | |
471 | this._getDocument._protected = true;\r | |
472 | \r | |
473 | this._createMovie = function(smID,smURL) {\r | |
474 | if (_s._didAppend && _s._appendSuccess) return false; // ignore if already succeeded\r | |
475 | if (window.location.href.indexOf('debug=1')+1) _s.debugMode = true; // allow force of debug mode via URL\r | |
476 | _s._didAppend = true;\r | |
477 | \r | |
478 | // safety check for legacy (change to Flash 9 URL)\r | |
479 | _s._setVersionInfo();\r | |
480 | var remoteURL = (smURL?smURL:_s.url);\r | |
481 | var localURL = (_s.altURL?_s.altURL:remoteURL);\r | |
482 | _s.url = _s._normalizeMovieURL(_s._overHTTP?remoteURL:localURL);\r | |
483 | smURL = _s.url;\r | |
484 | \r | |
485 | var htmlEmbed = '<embed name="'+smID+'" id="'+smID+'" src="'+smURL+'" width="100%" height="100%" quality="high" allowScriptAccess="always" quality="high" '+(_s.useHighPerformance && !_s.useMovieStar?'wmode="transparent" ':'')+'bgcolor="'+_s.bgColor+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash"></embed>';\r | |
486 | var htmlObject = '<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.useHighPerformance && !_s.useMovieStar?'<param name="wmode" value="transparent" /> ':'')+'<param name="bgcolor" value="'+_s.bgColor+'" /><!-- --></object>';\r | |
487 | var html = (!_s.isIE?htmlEmbed:htmlObject);\r | |
488 | \r | |
489 | var toggleElement = '<div id="'+_s.debugID+'-toggle" style="position:fixed;_position:absolute;right:0px;bottom:0px;_top:0px;width:1.2em;height:1.2em;line-height:1.2em;margin:2px;padding:0px;text-align:center;border:1px solid #999;cursor:pointer;background:#fff;color:#333;z-index:10001" title="Toggle SM2 debug console" onclick="soundManager._toggleDebug()">-</div>';\r | |
490 | var debugHTML = '<div id="'+_s.debugID+'" style="display:'+(_s.debugMode && ((!_s._hasConsole||!_s.useConsole)||(_s.useConsole && _s._hasConsole && !_s.consoleOnly))?'block':'none')+';opacity:0.85"></div>';\r | |
491 | var appXHTML = 'soundManager._createMovie(): appendChild/innerHTML set failed. May be app/xhtml+xml DOM-related.';\r | |
492 | \r | |
493 | var oTarget = _s._getDocument();\r | |
494 | if (oTarget) {\r | |
495 | \r | |
496 | _s.oMC = document.getElementById('sm2-container')?document.getElementById('sm2-container'):document.createElement('div');\r | |
497 | if (!_s.oMC.id) {\r | |
498 | _s.oMC.id = 'sm2-container';\r | |
499 | _s.oMC.className = 'movieContainer';\r | |
500 | // "hide" flash movie\r | |
501 | var s = null;\r | |
502 | if (_s.useHighPerformance) {\r | |
503 | s = {\r | |
504 | position: 'fixed',\r | |
505 | width: '8px',\r | |
506 | height: '8px', // must be at least 6px for flash to run fast. odd? yes.\r | |
507 | bottom: '0px',\r | |
508 | left: '0px',\r | |
509 | zIndex:-1 // sit behind everything else\r | |
510 | }\r | |
511 | } else {\r | |
512 | s = {\r | |
513 | position: 'absolute',\r | |
514 | width: '1px',\r | |
515 | height: '1px',\r | |
516 | bottom: '0px',\r | |
517 | left: '0px'\r | |
518 | }\r | |
519 | }\r | |
520 | var x = null;\r | |
521 | for (x in s) {\r | |
522 | _s.oMC.style[x] = s[x];\r | |
523 | }\r | |
524 | try {\r | |
525 | oTarget.appendChild(_s.oMC);\r | |
526 | _s.oMC.innerHTML = html;\r | |
527 | _s._appendSuccess = true;\r | |
528 | } catch(e) {\r | |
529 | throw new Error(appXHTML);\r | |
530 | }\r | |
531 | } else {\r | |
532 | // it's already in the document.\r | |
533 | _s.oMC.innerHTML = html;\r | |
534 | _s._appendSuccess = true;\r | |
535 | }\r | |
536 | if (!document.getElementById(_s.debugID) && ((!_s._hasConsole||!_s.useConsole)||(_s.useConsole && _s._hasConsole && !_s.consoleOnly))) {\r | |
537 | var oDebug = document.createElement('div');\r | |
538 | oDebug.id = _s.debugID;\r | |
539 | oDebug.style.display = (_s.debugMode?'block':'none');\r | |
540 | if (_s.debugMode) {\r | |
541 | try {\r | |
542 | var oD = document.createElement('div');\r | |
543 | oTarget.appendChild(oD);\r | |
544 | oD.innerHTML = toggleElement;\r | |
545 | } catch(e) {\r | |
546 | throw new Error(appXHTML);\r | |
547 | };\r | |
548 | };\r | |
549 | oTarget.appendChild(oDebug);\r | |
550 | };\r | |
551 | oTarget = null;\r | |
552 | };\r | |
553 | _s._wD('-- SoundManager 2 '+_s.version+(_s.useMovieStar?', MovieStar mode':'')+(_s._wD?', high performance mode':'')+' --',1);\r | |
554 | _s._wD('soundManager._createMovie(): Trying to load '+smURL+(!_s._overHTTP && _s.altURL?'(alternate URL)':''),1);\r | |
555 | };\r | |
556 | \r | |
557 | // aliased to this._wD()\r | |
558 | this._writeDebug = function(sText,sType,bTimestamp) {\r | |
559 | if (!_s.debugMode) return false;\r | |
560 | if (typeof bTimestamp != 'undefined' && bTimestamp) {\r | |
561 | sText = sText + ' | '+new Date().getTime();\r | |
562 | };\r | |
563 | if (_s._hasConsole && _s.useConsole) {\r | |
564 | var sMethod = _s._debugLevels[sType];\r | |
565 | if (typeof console[sMethod] != 'undefined') {\r | |
566 | console[sMethod](sText);\r | |
567 | } else {\r | |
568 | console.log(sText);\r | |
569 | };\r | |
570 | if (_s.useConsoleOnly) return true;\r | |
571 | };\r | |
572 | var sDID = 'soundmanager-debug';\r | |
573 | try {\r | |
574 | var o = document.getElementById(sDID);\r | |
575 | if (!o) return false;\r | |
576 | var oItem = document.createElement('div');\r | |
577 | sText = sText.replace(/\n/g,'<br />');\r | |
578 | if (typeof sType == 'undefined') {\r | |
579 | var sType = 0;\r | |
580 | } else {\r | |
581 | sType = parseInt(sType);\r | |
582 | };\r | |
583 | oItem.innerHTML = sText;\r | |
584 | if (sType) {\r | |
585 | if (sType >= 2) oItem.style.fontWeight = 'bold';\r | |
586 | if (sType == 3) oItem.style.color = '#ff3333';\r | |
587 | };\r | |
588 | // o.appendChild(oItem); // top-to-bottom\r | |
589 | o.insertBefore(oItem,o.firstChild); // bottom-to-top\r | |
590 | } catch(e) {\r | |
591 | // oh well\r | |
592 | };\r | |
593 | o = null;\r | |
594 | };\r | |
595 | this._writeDebug._protected = true;\r | |
596 | this._wD = this._writeDebug;\r | |
597 | \r | |
598 | this._wDAlert = function(sText) { alert(sText); };\r | |
599 | \r | |
600 | if (window.location.href.indexOf('debug=alert')+1 && _s.debugMode) {\r | |
601 | _s._wD = _s._wDAlert;\r | |
602 | };\r | |
603 | \r | |
604 | this._toggleDebug = function() {\r | |
605 | var o = document.getElementById(_s.debugID);\r | |
606 | var oT = document.getElementById(_s.debugID+'-toggle');\r | |
607 | if (!o) return false;\r | |
608 | if (_s._debugOpen) {\r | |
609 | // minimize\r | |
610 | oT.innerHTML = '+';\r | |
611 | o.style.display = 'none';\r | |
612 | } else {\r | |
613 | oT.innerHTML = '-';\r | |
614 | o.style.display = 'block';\r | |
615 | };\r | |
616 | _s._debugOpen = !_s._debugOpen;\r | |
617 | };\r | |
618 | \r | |
619 | this._toggleDebug._protected = true;\r | |
620 | \r | |
621 | this._debug = function() {\r | |
622 | _s._wD('--- soundManager._debug(): Current sound objects ---',1);\r | |
623 | for (var i=0,j=_s.soundIDs.length; i<j; i++) {\r | |
624 | _s.sounds[_s.soundIDs[i]]._debug();\r | |
625 | };\r | |
626 | };\r | |
627 | \r | |
628 | this._mergeObjects = function(oMain,oAdd) {\r | |
629 | // non-destructive merge\r | |
630 | var o1 = {}; // clone o1\r | |
631 | for (var i in oMain) {\r | |
632 | o1[i] = oMain[i];\r | |
633 | }\r | |
634 | var o2 = (typeof oAdd == 'undefined'?_s.defaultOptions:oAdd);\r | |
635 | for (var o in o2) {\r | |
636 | if (typeof o1[o] == 'undefined') o1[o] = o2[o];\r | |
637 | };\r | |
638 | return o1;\r | |
639 | };\r | |
640 | \r | |
641 | this.createMovie = function(sURL) {\r | |
642 | if (sURL) _s.url = sURL;\r | |
643 | _s._initMovie();\r | |
644 | };\r | |
645 | \r | |
646 | this.go = this.createMovie; // nice alias\r | |
647 | \r | |
648 | this._initMovie = function() {\r | |
649 | // attempt to get, or create, movie\r | |
650 | if (_s.o) return false; // pre-init may have fired this function before window.onload(), may already exist\r | |
651 | _s.o = _s.getMovie(_s.id); // try to get flash movie (inline markup)\r | |
652 | if (!_s.o) {\r | |
653 | // try to create\r | |
654 | _s._createMovie(_s.id,_s.url);\r | |
655 | _s.o = _s.getMovie(_s.id);\r | |
656 | };\r | |
657 | if (_s.o) {\r | |
658 | _s._wD('soundManager._initMovie(): Got '+_s.o.nodeName+' element ('+(_s._didAppend?'created via JS':'static HTML')+')',1);\r | |
659 | _s._wD('soundManager._initMovie(): Waiting for ExternalInterface call from Flash..');\r | |
660 | };\r | |
661 | };\r | |
662 | \r | |
663 | this.waitForExternalInterface = function() {\r | |
664 | if (_s._waitingForEI) return false;\r | |
665 | _s._waitingForEI = true;\r | |
666 | if (_s._tryInitOnFocus && !_s._isFocused) {\r | |
667 | _s._wD('soundManager: Special case: Flash may not have started due to non-focused tab (Safari is lame), and/or focus cannot be detected. Waiting for focus-related event..');\r | |
668 | return false;\r | |
669 | };\r | |
670 | if (!_s._didInit) {\r | |
671 | _s._wD('soundManager: Getting impatient, still waiting for Flash.. ;)');\r | |
672 | };\r | |
673 | setTimeout(function() {\r | |
674 | if (!_s._didInit) {\r | |
675 | _s._wD('soundManager: No Flash response within reasonable time after document load.\nPossible causes: Flash version under 8, no support, or Flash security denying JS-Flash communication.',2);\r | |
676 | if (!_s._overHTTP) {\r | |
677 | _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 | |
678 | };\r | |
679 | };\r | |
680 | // if still not initialized and no other options, give up\r | |
681 | if (!_s._didInit && _s._okToDisable) _s._failSafely();\r | |
682 | },750);\r | |
683 | };\r | |
684 | \r | |
685 | this.handleFocus = function() {\r | |
686 | if (_s._isFocused || !_s._tryInitOnFocus) return true;\r | |
687 | _s._okToDisable = true;\r | |
688 | _s._isFocused = true;\r | |
689 | _s._wD('soundManager.handleFocus()');\r | |
690 | if (_s._tryInitOnFocus) {\r | |
691 | // giant Safari 3.1 hack - assume window in focus if mouse is moving, since document.hasFocus() not currently implemented.\r | |
692 | window.removeEventListener('mousemove',_s.handleFocus,false);\r | |
693 | };\r | |
694 | // allow init to restart\r | |
695 | _s._waitingForEI = false;\r | |
696 | setTimeout(_s.waitForExternalInterface,500);\r | |
697 | // detach event\r | |
698 | if (window.removeEventListener) {\r | |
699 | window.removeEventListener('focus',_s.handleFocus,false);\r | |
700 | } else if (window.detachEvent) {\r | |
701 | window.detachEvent('onfocus',_s.handleFocus);\r | |
702 | };\r | |
703 | };\r | |
704 | \r | |
705 | this.initComplete = function() {\r | |
706 | if (_s._didInit) return false;\r | |
707 | _s._didInit = true;\r | |
708 | _s._wD('-- SoundManager 2 '+(_s._disabled?'failed to load':'loaded')+' ('+(_s._disabled?'security/load error':'OK')+') --',1);\r | |
709 | if (_s._disabled) {\r | |
710 | _s._wD('soundManager.initComplete(): calling soundManager.onerror()',1);\r | |
711 | _s.onerror.apply(window);\r | |
712 | return false;\r | |
713 | };\r | |
714 | if (_s.waitForWindowLoad && !_s._windowLoaded) {\r | |
715 | _s._wD('soundManager: Waiting for window.onload()');\r | |
716 | if (window.addEventListener) {\r | |
717 | window.addEventListener('load',_s.initUserOnload,false);\r | |
718 | } else if (window.attachEvent) {\r | |
719 | window.attachEvent('onload',_s.initUserOnload);\r | |
720 | };\r | |
721 | return false;\r | |
722 | } else {\r | |
723 | if (_s.waitForWindowLoad && _s._windowLoaded) {\r | |
724 | _s._wD('soundManager: Document already loaded');\r | |
725 | };\r | |
726 | _s.initUserOnload();\r | |
727 | };\r | |
728 | };\r | |
729 | \r | |
730 | this.initUserOnload = function() {\r | |
731 | _s._wD('soundManager.initComplete(): calling soundManager.onload()',1);\r | |
732 | // call user-defined "onload", scoped to window\r | |
733 | try {\r | |
734 | _s.onload.apply(window);\r | |
735 | } catch(e) {\r | |
736 | // something broke (likely JS error in user function)\r | |
737 | _s._wD('soundManager.onload() threw an exception: '+e.message,2);\r | |
738 | setTimeout(function(){throw new Error(e)},20);\r | |
739 | return false;\r | |
740 | };\r | |
741 | _s._wD('soundManager.onload() complete',1);\r | |
742 | };\r | |
743 | \r | |
744 | this.init = function() {\r | |
745 | _s._wD('-- soundManager.init() --');\r | |
746 | // called after onload()\r | |
747 | _s._initMovie();\r | |
748 | if (_s._didInit) {\r | |
749 | _s._wD('soundManager.init(): Already called?');\r | |
750 | return false;\r | |
751 | };\r | |
752 | // event cleanup\r | |
753 | if (window.removeEventListener) {\r | |
754 | window.removeEventListener('load',_s.beginDelayedInit,false);\r | |
755 | } else if (window.detachEvent) {\r | |
756 | window.detachEvent('onload',_s.beginDelayedInit);\r | |
757 | };\r | |
758 | try {\r | |
759 | _s._wD('Attempting to call JS -> Flash..');\r | |
760 | _s.o._externalInterfaceTest(false); // attempt to talk to Flash\r | |
761 | // _s._wD('Flash ExternalInterface call (JS-Flash) OK',1);\r | |
762 | if (!_s.allowPolling) {\r | |
763 | _s._wD('Polling (whileloading/whileplaying support) is disabled.',1);\r | |
764 | }\r | |
765 | _s.setPolling(true);\r | |
766 | if (!_s.debugMode) _s.o._disableDebug();\r | |
767 | _s.enabled = true;\r | |
768 | } catch(e) {\r | |
769 | _s._failSafely();\r | |
770 | _s.initComplete();\r | |
771 | return false;\r | |
772 | };\r | |
773 | _s.initComplete();\r | |
774 | };\r | |
775 | \r | |
776 | this.beginDelayedInit = function() {\r | |
777 | _s._wD('soundManager.beginDelayedInit(): Document loaded');\r | |
778 | _s._windowLoaded = true;\r | |
779 | setTimeout(_s.waitForExternalInterface,500);\r | |
780 | setTimeout(_s.beginInit,20);\r | |
781 | };\r | |
782 | \r | |
783 | this.beginInit = function() {\r | |
784 | if (_s._initPending) return false;\r | |
785 | _s.createMovie(); // ensure creation if not already done\r | |
786 | _s._initMovie();\r | |
787 | _s._initPending = true;\r | |
788 | return true;\r | |
789 | };\r | |
790 | \r | |
791 | this.domContentLoaded = function() {\r | |
792 | _s._wD('soundManager.domContentLoaded()');\r | |
793 | if (document.removeEventListener) document.removeEventListener('DOMContentLoaded',_s.domContentLoaded,false);\r | |
794 | _s.go();\r | |
795 | };\r | |
796 | \r | |
797 | this._externalInterfaceOK = function() {\r | |
798 | // callback from flash for confirming that movie loaded, EI is working etc.\r | |
799 | if (_s.swfLoaded) return false;\r | |
800 | _s._wD('soundManager._externalInterfaceOK()');\r | |
801 | _s.swfLoaded = true;\r | |
802 | _s._tryInitOnFocus = false;\r | |
803 | if (_s.isIE) {\r | |
804 | // IE needs a timeout OR delay until window.onload - may need TODO: investigating\r | |
805 | setTimeout(_s.init,100);\r | |
806 | } else {\r | |
807 | _s.init();\r | |
808 | };\r | |
809 | };\r | |
810 | \r | |
811 | this._setSandboxType = function(sandboxType) {\r | |
812 | var sb = _s.sandbox;\r | |
813 | sb.type = sandboxType;\r | |
814 | sb.description = sb.types[(typeof sb.types[sandboxType] != 'undefined'?sandboxType:'unknown')];\r | |
815 | _s._wD('Flash security sandbox type: '+sb.type);\r | |
816 | if (sb.type == 'localWithFile') {\r | |
817 | sb.noRemote = true;\r | |
818 | sb.noLocal = false;\r | |
819 | _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 | |
820 | } else if (sb.type == 'localWithNetwork') {\r | |
821 | sb.noRemote = false;\r | |
822 | sb.noLocal = true;\r | |
823 | } else if (sb.type == 'localTrusted') {\r | |
824 | sb.noRemote = false;\r | |
825 | sb.noLocal = false;\r | |
826 | };\r | |
827 | };\r | |
828 | \r | |
829 | this.destruct = function() {\r | |
830 | _s._wD('soundManager.destruct()');\r | |
831 | _s.disable(true);\r | |
832 | };\r | |
833 | \r | |
834 | // SMSound (sound object)\r | |
835 | \r | |
836 | function SMSound(oOptions) {\r | |
837 | var _t = this;\r | |
838 | this.sID = oOptions.id;\r | |
839 | this.url = oOptions.url;\r | |
840 | this.options = _s._mergeObjects(oOptions);\r | |
841 | this.instanceOptions = this.options; // per-play-instance-specific options\r | |
842 | this._iO = this.instanceOptions; // short alias\r | |
843 | \r | |
844 | this._debug = function() {\r | |
845 | if (_s.debugMode) {\r | |
846 | var stuff = null;\r | |
847 | var msg = [];\r | |
848 | var sF = null;\r | |
849 | var sfBracket = null;\r | |
850 | var maxLength = 64; // # of characters of function code to show before truncating\r | |
851 | for (stuff in _t.options) {\r | |
852 | if (_t.options[stuff] != null) {\r | |
853 | if (_t.options[stuff] instanceof Function) {\r | |
854 | // handle functions specially\r | |
855 | sF = _t.options[stuff].toString();\r | |
856 | sF = sF.replace(/\s\s+/g,' '); // normalize spaces\r | |
857 | sfBracket = sF.indexOf('{');\r | |
858 | msg[msg.length] = ' '+stuff+': {'+sF.substr(sfBracket+1,(Math.min(Math.max(sF.indexOf('\n')-1,maxLength),maxLength))).replace(/\n/g,'')+'... }';\r | |
859 | } else {\r | |
860 | msg[msg.length] = ' '+stuff+': '+_t.options[stuff];\r | |
861 | };\r | |
862 | };\r | |
863 | };\r | |
864 | _s._wD('SMSound() merged options: {\n'+msg.join(', \n')+'\n}');\r | |
865 | };\r | |
866 | };\r | |
867 | \r | |
868 | this._debug();\r | |
869 | \r | |
870 | this.id3 = {\r | |
871 | /* \r | |
872 | Name/value pairs set via Flash when available - see reference for names:\r | |
873 | http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001567.html\r | |
874 | (eg., this.id3.songname or this.id3['songname'])\r | |
875 | */\r | |
876 | };\r | |
877 | \r | |
878 | this.resetProperties = function(bLoaded) {\r | |
879 | _t.bytesLoaded = null;\r | |
880 | _t.bytesTotal = null;\r | |
881 | _t.position = null;\r | |
882 | _t.duration = null;\r | |
883 | _t.durationEstimate = null;\r | |
884 | _t.loaded = false;\r | |
885 | _t.playState = 0;\r | |
886 | _t.paused = false;\r | |
887 | _t.readyState = 0; // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success\r | |
888 | _t.muted = false;\r | |
889 | _t.didBeforeFinish = false;\r | |
890 | _t.didJustBeforeFinish = false;\r | |
891 | _t.instanceOptions = {};\r | |
892 | _t.instanceCount = 0;\r | |
893 | _t.peakData = {\r | |
894 | left: 0,\r | |
895 | right: 0\r | |
896 | };\r | |
897 | _t.waveformData = [];\r | |
898 | _t.eqData = [];\r | |
899 | };\r | |
900 | \r | |
901 | _t.resetProperties();\r | |
902 | \r | |
903 | // --- public methods ---\r | |
904 | \r | |
905 | this.load = function(oOptions) {\r | |
906 | if (typeof oOptions != 'undefined') {\r | |
907 | _t._iO = _s._mergeObjects(oOptions);\r | |
908 | _t.instanceOptions = _t._iO;\r | |
909 | } else {\r | |
910 | var oOptions = _t.options;\r | |
911 | _t._iO = oOptions;\r | |
912 | _t.instanceOptions = _t._iO;\r | |
913 | } \r | |
914 | if (typeof _t._iO.url == 'undefined') _t._iO.url = _t.url;\r | |
915 | _s._wD('soundManager.load(): '+_t._iO.url,1);\r | |
916 | if (_t._iO.url == _t.url && _t.readyState != 0 && _t.readyState != 2) {\r | |
917 | _s._wD('soundManager.load(): current URL already assigned.',1);\r | |
918 | return false;\r | |
919 | }\r | |
920 | _t.loaded = false;\r | |
921 | _t.readyState = 1;\r | |
922 | _t.playState = (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 | |
923 | try {\r | |
924 | if (_s.flashVersion==8) {\r | |
925 | _s.o._load(_t.sID,_t._iO.url,_t._iO.stream,_t._iO.autoPlay,(_t._iO.whileloading?1:0));\r | |
926 | } else {\r | |
927 | _s.o._load(_t.sID,_t._iO.url,_t._iO.stream?true:false,_t._iO.autoPlay?true:false); // ,(_tO.whileloading?true:false)\r | |
928 | if (_t._iO.isMovieStar && _t._iO.autoLoad && !_t._iO.autoPlay) {\r | |
929 | // special case: MPEG4 content must start playing to load, then pause to prevent playing.\r | |
930 | _t.pause();\r | |
931 | }\r | |
932 | };\r | |
933 | } catch(e) {\r | |
934 | _s._wD('SMSound.load(): Exception: JS-Flash communication failed, or JS error.',2);\r | |
935 | _s.onerror();\r | |
936 | _s.disable();\r | |
937 | };\r | |
938 | };\r | |
939 | \r | |
940 | this.unload = function() {\r | |
941 | // Flash 8/AS2 can't "close" a stream - fake it by loading an empty MP3\r | |
942 | // Flash 9/AS3: Close stream, preventing further load\r | |
943 | if (_t.readyState != 0) {\r | |
944 | _s._wD('SMSound.unload(): "'+_t.sID+'"');\r | |
945 | if (_t.readyState != 2) { // reset if not error\r | |
946 | _t.setPosition(0); // reset current sound positioning\r | |
947 | }\r | |
948 | _s.o._unload(_t.sID,_s.nullURL);\r | |
949 | // reset load/status flags\r | |
950 | _t.resetProperties();\r | |
951 | }\r | |
952 | };\r | |
953 | \r | |
954 | this.destruct = function() {\r | |
955 | // kill sound within Flash\r | |
956 | _s._wD('SMSound.destruct(): "'+_t.sID+'"');\r | |
957 | _s.o._destroySound(_t.sID);\r | |
958 | _s.destroySound(_t.sID,true); // ensure deletion from controller\r | |
959 | }\r | |
960 | \r | |
961 | this.play = function(oOptions) {\r | |
962 | if (!oOptions) oOptions = {};\r | |
963 | _t._iO = _s._mergeObjects(oOptions,_t._iO);\r | |
964 | _t._iO = _s._mergeObjects(_t._iO,_t.options);\r | |
965 | _t.instanceOptions = _t._iO;\r | |
966 | if (_t.playState == 1) {\r | |
967 | var allowMulti = _t._iO.multiShot;\r | |
968 | if (!allowMulti) {\r | |
969 | _s._wD('SMSound.play(): "'+_t.sID+'" already playing (one-shot)',1);\r | |
970 | return false;\r | |
971 | } else {\r | |
972 | _s._wD('SMSound.play(): "'+_t.sID+'" already playing (multi-shot)',1);\r | |
973 | };\r | |
974 | };\r | |
975 | if (!_t.loaded) {\r | |
976 | if (_t.readyState == 0) {\r | |
977 | _s._wD('SMSound.play(): Attempting to load "'+_t.sID+'"',1);\r | |
978 | // try to get this sound playing ASAP\r | |
979 | _t._iO.stream = true;\r | |
980 | _t._iO.autoPlay = true;\r | |
981 | // TODO: need to investigate when false, double-playing\r | |
982 | // if (typeof oOptions.autoPlay=='undefined') _tO.autoPlay = true; // only set autoPlay if unspecified here\r | |
983 | _t.load(_t._iO); // try to get this sound playing ASAP\r | |
984 | } else if (_t.readyState == 2) {\r | |
985 | _s._wD('SMSound.play(): Could not load "'+_t.sID+'" - exiting',2);\r | |
986 | return false;\r | |
987 | } else {\r | |
988 | _s._wD('SMSound.play(): "'+_t.sID+'" is loading - attempting to play..',1);\r | |
989 | };\r | |
990 | } else {\r | |
991 | _s._wD('SMSound.play(): "'+_t.sID+'"');\r | |
992 | };\r | |
993 | if (_t.paused) {\r | |
994 | _t.resume();\r | |
995 | } else {\r | |
996 | _t.playState = 1;\r | |
997 | if (!_t.instanceCount || _s.flashVersion == 9) _t.instanceCount++;\r | |
998 | _t.position = (typeof _t._iO.position != 'undefined' && !isNaN(_t._iO.position)?_t._iO.position:0);\r | |
999 | if (_t._iO.onplay) _t._iO.onplay.apply(_t);\r | |
1000 | _t.setVolume(_t._iO.volume);\r | |
1001 | _t.setPan(_t._iO.pan);\r | |
1002 | _s.o._start(_t.sID,_t._iO.loop||1,(_s.flashVersion==9?_t.position:_t.position/1000));\r | |
1003 | };\r | |
1004 | };\r | |
1005 | \r | |
1006 | this.start = this.play; // just for convenience\r | |
1007 | \r | |
1008 | this.stop = function(bAll) {\r | |
1009 | if (_t.playState == 1) {\r | |
1010 | _t.playState = 0;\r | |
1011 | _t.paused = false;\r | |
1012 | // if (_s.defaultOptions.onstop) _s.defaultOptions.onstop.apply(_s);\r | |
1013 | if (_t._iO.onstop) _t._iO.onstop.apply(_t);\r | |
1014 | _s.o._stop(_t.sID,bAll);\r | |
1015 | _t.instanceCount = 0;\r | |
1016 | _t._iO = {};\r | |
1017 | // _t.instanceOptions = _t._iO;\r | |
1018 | };\r | |
1019 | };\r | |
1020 | \r | |
1021 | this.setPosition = function(nMsecOffset) {\r | |
1022 | _t._iO.position = nMsecOffset;\r | |
1023 | _s._wD('SMSound.setPosition('+nMsecOffset+')');\r | |
1024 | _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 | |
1025 | };\r | |
1026 | \r | |
1027 | this.pause = function() {\r | |
1028 | if (_t.paused || _t.playState == 0) return false;\r | |
1029 | _s._wD('SMSound.pause()');\r | |
1030 | _t.paused = true;\r | |
1031 | _s.o._pause(_t.sID);\r | |
1032 | if (_t._iO.onpause) _t._iO.onpause.apply(_t);\r | |
1033 | };\r | |
1034 | \r | |
1035 | this.resume = function() {\r | |
1036 | if (!_t.paused || _t.playState == 0) return false;\r | |
1037 | _s._wD('SMSound.resume()');\r | |
1038 | _t.paused = false;\r | |
1039 | _s.o._pause(_t.sID); // flash method is toggle-based (pause/resume)\r | |
1040 | if (_t._iO.onresume) _t._iO.onresume.apply(_t);\r | |
1041 | };\r | |
1042 | \r | |
1043 | this.togglePause = function() {\r | |
1044 | _s._wD('SMSound.togglePause()');\r | |
1045 | if (!_t.playState) {\r | |
1046 | _t.play({position:(_s.flashVersion==9?_t.position:_t.position/1000)});\r | |
1047 | return false;\r | |
1048 | };\r | |
1049 | if (_t.paused) {\r | |
1050 | _t.resume();\r | |
1051 | } else {\r | |
1052 | _t.pause();\r | |
1053 | };\r | |
1054 | };\r | |
1055 | \r | |
1056 | this.setPan = function(nPan) {\r | |
1057 | if (typeof nPan == 'undefined') nPan = 0;\r | |
1058 | _s.o._setPan(_t.sID,nPan);\r | |
1059 | _t._iO.pan = nPan;\r | |
1060 | };\r | |
1061 | \r | |
1062 | this.setVolume = function(nVol) {\r | |
1063 | if (typeof nVol == 'undefined') nVol = 100;\r | |
1064 | _s.o._setVolume(_t.sID,(_s.muted&&!_t.muted)||_t.muted?0:nVol);\r | |
1065 | _t._iO.volume = nVol;\r | |
1066 | };\r | |
1067 | \r | |
1068 | this.mute = function() {\r | |
1069 | _t.muted = true;\r | |
1070 | _s.o._setVolume(_t.sID,0);\r | |
1071 | };\r | |
1072 | \r | |
1073 | this.unmute = function() {\r | |
1074 | _t.muted = false;\r | |
1075 | _s.o._setVolume(_t.sID,typeof _t._iO.volume != 'undefined'?_t._iO.volume:_t.options.volume);\r | |
1076 | };\r | |
1077 | \r | |
1078 | // --- "private" methods called by Flash ---\r | |
1079 | \r | |
1080 | this._whileloading = function(nBytesLoaded,nBytesTotal,nDuration) {\r | |
1081 | if (!_t._iO.isMovieStar) {\r | |
1082 | _t.bytesLoaded = nBytesLoaded;\r | |
1083 | _t.bytesTotal = nBytesTotal;\r | |
1084 | _t.duration = Math.floor(nDuration);\r | |
1085 | _t.durationEstimate = parseInt((_t.bytesTotal/_t.bytesLoaded)*_t.duration); // estimate total time (will only be accurate with CBR MP3s.)\r | |
1086 | if (_t.readyState != 3 && _t._iO.whileloading) _t._iO.whileloading.apply(_t);\r | |
1087 | } else {\r | |
1088 | _t.bytesLoaded = nBytesLoaded;\r | |
1089 | _t.bytesTotal = nBytesTotal;\r | |
1090 | _t.duration = Math.floor(nDuration);\r | |
1091 | _t.durationEstimate = _t.duration;\r | |
1092 | if (_t.readyState != 3 && _t._iO.whileloading) _t._iO.whileloading.apply(_t);\r | |
1093 | }\r | |
1094 | };\r | |
1095 | \r | |
1096 | this._onid3 = function(oID3PropNames,oID3Data) {\r | |
1097 | // oID3PropNames: string array (names)\r | |
1098 | // ID3Data: string array (data)\r | |
1099 | _s._wD('SMSound._onid3(): "'+this.sID+'" ID3 data received.');\r | |
1100 | var oData = [];\r | |
1101 | for (var i=0,j=oID3PropNames.length; i<j; i++) {\r | |
1102 | oData[oID3PropNames[i]] = oID3Data[i];\r | |
1103 | // _s._wD(oID3PropNames[i]+': '+oID3Data[i]);\r | |
1104 | };\r | |
1105 | _t.id3 = _s._mergeObjects(_t.id3,oData);\r | |
1106 | if (_t._iO.onid3) _t._iO.onid3.apply(_t);\r | |
1107 | };\r | |
1108 | \r | |
1109 | this._whileplaying = function(nPosition,oPeakData,oWaveformData,oEQData) {\r | |
1110 | if (isNaN(nPosition) || nPosition == null) return false; // Flash may return NaN at times\r | |
1111 | _t.position = nPosition;\r | |
1112 | if (_t._iO.usePeakData && typeof oPeakData != 'undefined' && oPeakData) {\r | |
1113 | _t.peakData = {\r | |
1114 | left: oPeakData.leftPeak,\r | |
1115 | right: oPeakData.rightPeak\r | |
1116 | };\r | |
1117 | };\r | |
1118 | if (_t._iO.useWaveformData && typeof oWaveformData != 'undefined' && oWaveformData) {\r | |
1119 | _t.waveformData = oWaveformData;\r | |
1120 | /*\r | |
1121 | _t.spectrumData = {\r | |
1122 | left: oSpectrumData.left.split(','),\r | |
1123 | right: oSpectrumData.right.split(',')\r | |
1124 | }\r | |
1125 | */\r | |
1126 | };\r | |
1127 | if (_t._iO.useEQData && typeof oEQData != 'undefined' && oEQData) {\r | |
1128 | _t.eqData = oEQData;\r | |
1129 | };\r | |
1130 | if (_t.playState == 1) {\r | |
1131 | if (_t._iO.whileplaying) {\r | |
1132 | _t._iO.whileplaying.apply(_t); // flash may call after actual finish\r | |
1133 | };\r | |
1134 | if (_t.loaded && _t._iO.onbeforefinish && _t._iO.onbeforefinishtime && !_t.didBeforeFinish && _t.duration-_t.position <= _t._iO.onbeforefinishtime) {\r | |
1135 | _s._wD('duration-position <= onbeforefinishtime: '+_t.duration+' - '+_t.position+' <= '+_t._iO.onbeforefinishtime+' ('+(_t.duration-_t.position)+')');\r | |
1136 | _t._onbeforefinish();\r | |
1137 | };\r | |
1138 | };\r | |
1139 | };\r | |
1140 | \r | |
1141 | this._onload = function(bSuccess) {\r | |
1142 | bSuccess = (bSuccess==1?true:false);\r | |
1143 | _s._wD('SMSound._onload(): "'+_t.sID+'"'+(bSuccess?' loaded.':' failed to load? - '+_t.url));\r | |
1144 | if (!bSuccess) {\r | |
1145 | if (_s.sandbox.noRemote == true) {\r | |
1146 | _s._wD('SMSound._onload(): Reminder: Flash security is denying network/internet access',1);\r | |
1147 | };\r | |
1148 | if (_s.sandbox.noLocal == true) {\r | |
1149 | _s._wD('SMSound._onload(): Reminder: Flash security is denying local access',1);\r | |
1150 | };\r | |
1151 | };\r | |
1152 | _t.loaded = bSuccess;\r | |
1153 | _t.readyState = bSuccess?3:2;\r | |
1154 | if (_t._iO.onload) {\r | |
1155 | _t._iO.onload.apply(_t);\r | |
1156 | };\r | |
1157 | };\r | |
1158 | \r | |
1159 | this._onbeforefinish = function() {\r | |
1160 | if (!_t.didBeforeFinish) {\r | |
1161 | _t.didBeforeFinish = true;\r | |
1162 | if (_t._iO.onbeforefinish) {\r | |
1163 | _s._wD('SMSound._onbeforefinish(): "'+_t.sID+'"');\r | |
1164 | _t._iO.onbeforefinish.apply(_t);\r | |
1165 | }\r | |
1166 | };\r | |
1167 | };\r | |
1168 | \r | |
1169 | this._onjustbeforefinish = function(msOffset) {\r | |
1170 | // msOffset: "end of sound" delay actual value (eg. 200 msec, value at event fire time was 187)\r | |
1171 | if (!_t.didJustBeforeFinish) {\r | |
1172 | _t.didJustBeforeFinish = true;\r | |
1173 | if (_t._iO.onjustbeforefinish) {\r | |
1174 | _s._wD('SMSound._onjustbeforefinish(): "'+_t.sID+'"');\r | |
1175 | _t._iO.onjustbeforefinish.apply(_t);\r | |
1176 | }\r | |
1177 | };\r | |
1178 | };\r | |
1179 | \r | |
1180 | this._onfinish = function() {\r | |
1181 | // sound has finished playing\r | |
1182 | _t.playState = 0;\r | |
1183 | _t.paused = false;\r | |
1184 | if (_t._iO.onfinish) {\r | |
1185 | _s._wD('SMSound._onfinish(): "'+_t.sID+'"');\r | |
1186 | _t._iO.onfinish.apply(_t);\r | |
1187 | }\r | |
1188 | if (_t._iO.onbeforefinishcomplete) _t._iO.onbeforefinishcomplete.apply(_t);\r | |
1189 | // reset some state items\r | |
1190 | _t.setPosition(0);\r | |
1191 | _t.didBeforeFinish = false;\r | |
1192 | _t.didJustBeforeFinish = false;\r | |
1193 | if (_t.instanceCount) {\r | |
1194 | _t.instanceCount--;\r | |
1195 | if (!_t.instanceCount) {\r | |
1196 | // reset instance options\r | |
1197 | _t.instanceCount = 0;\r | |
1198 | _t.instanceOptions = {};\r | |
1199 | }\r | |
1200 | }\r | |
1201 | };\r | |
1202 | \r | |
1203 | this._onmetadata = function(oMetaData) {\r | |
1204 | // movieStar mode only\r | |
1205 | _s._wD('SMSound.onmetadata()');\r | |
1206 | // Contains a subset of metadata. Note that files may have their own unique metadata.\r | |
1207 | // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000267.html\r | |
1208 | if (!oMetaData.width && !oMetaData.height) {\r | |
1209 | _s._wD('No width/height given, assuming defaults');\r | |
1210 | oMetaData.width = 320;\r | |
1211 | oMetaData.height = 240;\r | |
1212 | };\r | |
1213 | _t.metadata = oMetaData; // potentially-large object from flash\r | |
1214 | _t.width = oMetaData.width;\r | |
1215 | _t.height = oMetaData.height;\r | |
1216 | if (_t._iO.onmetadata) {\r | |
1217 | _s._wD('SMSound._onmetadata(): "'+_t.sID+'"');\r | |
1218 | _t._iO.onmetadata.apply(_t);\r | |
1219 | }\r | |
1220 | _s.wD('SMSound.onmetadata() complete');\r | |
1221 | };\r | |
1222 | \r | |
1223 | }; // SMSound()\r | |
1224 | \r | |
1225 | // register a few event handlers\r | |
1226 | if (window.addEventListener) {\r | |
1227 | window.addEventListener('focus',_s.handleFocus,false);\r | |
1228 | window.addEventListener('load',_s.beginDelayedInit,false);\r | |
1229 | window.addEventListener('unload',_s.destruct,false);\r | |
1230 | if (_s._tryInitOnFocus) window.addEventListener('mousemove',_s.handleFocus,false); // massive Safari focus hack\r | |
1231 | } else if (window.attachEvent) {\r | |
1232 | window.attachEvent('onfocus',_s.handleFocus);\r | |
1233 | window.attachEvent('onload',_s.beginDelayedInit);\r | |
1234 | window.attachEvent('unload',_s.destruct);\r | |
1235 | } else {\r | |
1236 | // no add/attachevent support - safe to assume no JS -> Flash either.\r | |
1237 | soundManager.onerror();\r | |
1238 | soundManager.disable();\r | |
1239 | };\r | |
1240 | \r | |
1241 | if (document.addEventListener) document.addEventListener('DOMContentLoaded',_s.domContentLoaded,false);\r | |
1242 | \r | |
1243 | }; // SoundManager()\r | |
1244 | \r | |
1245 | var soundManager = new SoundManager();\r |