PageRenderTime 74ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/themes/reesenews.old/scripts/soundmanager2/src/SoundManager2_AS3.as

https://github.com/digitalstrategyworks/Reese-WordPress
ActionScript | 970 lines | 777 code | 77 blank | 116 comment | 194 complexity | 727ea94ccd309cb6b11010845bd6a386 MD5 | raw file
  1. /*
  2. SoundManager 2: Javascript Sound for the Web
  3. ----------------------------------------------
  4. http://schillmania.com/projects/soundmanager2/
  5. Copyright (c) 2007, Scott Schiller. All rights reserved.
  6. Code licensed under the BSD License:
  7. http://www.schillmania.com/projects/soundmanager2/license.txt
  8. Flash 9 / ActionScript 3 version
  9. */
  10. package {
  11. import flash.display.Sprite;
  12. import flash.events.Event;
  13. import flash.events.IOErrorEvent;
  14. import flash.events.MouseEvent;
  15. import flash.events.SecurityErrorEvent;
  16. import flash.events.AsyncErrorEvent;
  17. import flash.events.NetStatusEvent;
  18. import flash.events.TimerEvent;
  19. import flash.external.ExternalInterface; // woo
  20. import flash.media.Sound;
  21. import flash.media.SoundChannel;
  22. import flash.media.SoundMixer;
  23. import flash.net.URLLoader;
  24. import flash.net.URLRequest;
  25. import flash.system.Security;
  26. import flash.system.System;
  27. import flash.text.TextField;
  28. import flash.text.TextFormat;
  29. import flash.text.TextFieldAutoSize;
  30. import flash.ui.ContextMenu;
  31. import flash.ui.ContextMenuItem;
  32. import flash.utils.setInterval;
  33. import flash.utils.clearInterval;
  34. import flash.utils.Dictionary;
  35. import flash.utils.Timer;
  36. import flash.xml.XMLDocument;
  37. import flash.xml.XMLNode;
  38. public class SoundManager2_AS3 extends Sprite {
  39. public var version:String = "V2.97a.20101010";
  40. public var version_as:String = "(AS3/Flash 9)";
  41. /*
  42. * Cross-domain security options
  43. * HTML on foo.com loading .swf hosted on bar.com? Define your "HTML domain" here to allow JS+Flash communication to work.
  44. * // allow_xdomain_scripting = true;
  45. * // xdomain = "foo.com";
  46. * For all domains (possible security risk?), use xdomain = "*"; which ends up as System.security.allowDomain("*");
  47. * When loading from HTTPS, use System.security.allowInsecureDomain();
  48. * See http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/Security.html#allowDomain()
  49. */
  50. public var allow_xdomain_scripting:Boolean = false;
  51. public var xdomain:String = "*";
  52. // externalInterface references (for Javascript callbacks)
  53. public var baseJSController:String = "soundManager";
  54. public var baseJSObject:String = baseJSController + ".sounds";
  55. // internal objects
  56. public var sounds:Array = []; // indexed string array
  57. public var soundObjects: Dictionary = new Dictionary(); // associative Sound() object Dictionary type
  58. public var timerInterval: uint = 50;
  59. public var timerIntervalHighPerformance: uint = 10; // ~30fps (in Safari on OSX, anyway..)
  60. public var timer: Timer = null;
  61. public var pollingEnabled: Boolean = false; // polling (timer) flag - disabled by default, enabled by JS->Flash call
  62. public var debugEnabled: Boolean = true; // Flash debug output enabled by default, disabled by JS call
  63. public var flashDebugEnabled: Boolean = false; // Flash internal debug output (write to visible SWF in browser)
  64. public var loaded: Boolean = false;
  65. public var currentObject: SoundManager2_SMSound_AS3 = null;
  66. public var paramList:Object = null;
  67. public var messages:Array = [];
  68. public var textField: TextField = null;
  69. public var textStyle: TextFormat = new TextFormat();
  70. public var didSandboxMessage: Boolean = false;
  71. public var caughtFatal: Boolean = false;
  72. public function SoundManager2_AS3() {
  73. if (allow_xdomain_scripting && xdomain) {
  74. Security.allowDomain(xdomain);
  75. version_as += ' - cross-domain enabled';
  76. }
  77. this.paramList = this.root.loaderInfo.parameters;
  78. // <d>
  79. if (this.paramList['debug'] == 1) {
  80. this.flashDebugEnabled = true;
  81. }
  82. if (this.flashDebugEnabled) {
  83. var canvas: Sprite = new Sprite();
  84. canvas.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
  85. addChild(canvas);
  86. }
  87. // </d>
  88. flashDebug('SM2 SWF ' + version + ' ' + version_as);
  89. // context menu item with version info
  90. var sm2Menu:ContextMenu = new ContextMenu();
  91. var sm2MenuItem:ContextMenuItem = new ContextMenuItem('SoundManager ' + version + ' ' + version_as);
  92. sm2MenuItem.enabled = false;
  93. sm2Menu.customItems.push(sm2MenuItem);
  94. contextMenu = sm2Menu;
  95. if (ExternalInterface.available) {
  96. flashDebug('ExternalInterface available');
  97. try {
  98. flashDebug('Adding ExternalInterface callbacks...');
  99. ExternalInterface.addCallback('_load', _load);
  100. ExternalInterface.addCallback('_unload', _unload);
  101. ExternalInterface.addCallback('_stop', _stop);
  102. ExternalInterface.addCallback('_start', _start);
  103. ExternalInterface.addCallback('_pause', _pause);
  104. ExternalInterface.addCallback('_setPosition', _setPosition);
  105. ExternalInterface.addCallback('_setPan', _setPan);
  106. ExternalInterface.addCallback('_setVolume', _setVolume);
  107. ExternalInterface.addCallback('_setPolling', _setPolling);
  108. ExternalInterface.addCallback('_externalInterfaceTest', _externalInterfaceTest);
  109. ExternalInterface.addCallback('_disableDebug', _disableDebug);
  110. ExternalInterface.addCallback('_getMemoryUse', _getMemoryUse);
  111. ExternalInterface.addCallback('_loadFromXML', _loadFromXML);
  112. ExternalInterface.addCallback('_createSound', _createSound);
  113. ExternalInterface.addCallback('_destroySound', _destroySound);
  114. ExternalInterface.addCallback('_setAutoPlay', _setAutoPlay);
  115. } catch(e: Error) {
  116. flashDebug('Fatal: ExternalInterface error: ' + e.toString());
  117. }
  118. } else {
  119. flashDebug('Fatal: ExternalInterface (Flash &lt;-&gt; JS) not available');
  120. };
  121. // call after delay, to be safe (ensure callbacks are registered by the time JS is called below)
  122. var timer: Timer = new Timer(20, 0);
  123. timer.addEventListener(TimerEvent.TIMER, function() : void {
  124. timer.reset();
  125. _externalInterfaceTest(true);
  126. // timer.reset();
  127. // flashDebug('Init OK');
  128. });
  129. timer.start();
  130. // delayed, see above
  131. // _externalInterfaceTest(true);
  132. } // SoundManager2()
  133. public function flashDebug (txt:String) : void {
  134. // <d>
  135. messages.push(txt);
  136. if (this.flashDebugEnabled) {
  137. var didCreate: Boolean = false;
  138. textStyle.font = 'Arial';
  139. textStyle.size = 12;
  140. // 320x240 if no stage dimensions (happens in IE, apparently 0 before stage resize event fires.)
  141. var w:Number = this.stage.width?this.stage.width:320;
  142. var h:Number = this.stage.height?this.stage.height:240;
  143. if (textField == null) {
  144. didCreate = true;
  145. textField = new TextField();
  146. textField.autoSize = TextFieldAutoSize.LEFT;
  147. textField.x = 0;
  148. textField.y = 0;
  149. textField.multiline = true;
  150. textField.textColor = 0;
  151. textField.wordWrap = true;
  152. }
  153. textField.htmlText = messages.join('\n');
  154. textField.setTextFormat(textStyle);
  155. textField.width = w;
  156. textField.height = h;
  157. if (didCreate) {
  158. this.addChild(textField);
  159. }
  160. }
  161. // </d>
  162. }
  163. public function _setAutoPlay(sID:String, autoPlay:Boolean) : void {
  164. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  165. if (s) {
  166. s.setAutoPlay(autoPlay);
  167. }
  168. }
  169. // methods
  170. // -----------------------------------
  171. public function writeDebug (s:String, bTimestamp: Boolean = false) : Boolean {
  172. if (!debugEnabled) return false;
  173. // <d>
  174. ExternalInterface.call(baseJSController + "['_writeDebug']", "(Flash): " + s, null, bTimestamp);
  175. // </d>
  176. return true;
  177. }
  178. public function _externalInterfaceTest(isFirstCall: Boolean) : Boolean {
  179. var sandboxType:String = flash.system.Security['sandboxType'];
  180. if (!didSandboxMessage && sandboxType != 'localTrusted' && sandboxType != 'remote') {
  181. didSandboxMessage = true;
  182. flashDebug('<br><b>Fatal: Security sandbox error: Got "' + sandboxType + '", expected "remote" or "localTrusted".<br>Additional security permissions need to be granted.<br>See <a href="http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html">flash security settings panel</a> for non-HTTP, eg., file:// use.</b><br>http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html');
  183. }
  184. try {
  185. if (isFirstCall == true) {
  186. flashDebug('Testing Flash -&gt; JS...');
  187. var d: Date = new Date();
  188. ExternalInterface.call(baseJSController + "._externalInterfaceOK", d.getTime());
  189. flashDebug('Flash -&gt; JS OK');
  190. } else {
  191. writeDebug('SM2 SWF ' + version + ' ' + version_as);
  192. flashDebug('JS -> Flash OK');
  193. ExternalInterface.call(baseJSController + "._setSandboxType", sandboxType);
  194. writeDebug('JS to/from Flash OK');
  195. }
  196. } catch(e: Error) {
  197. flashDebug('Fatal: Flash &lt;-&gt; JS error: ' + e.toString());
  198. writeDebug('_externalInterfaceTest: Error: ' + e.toString());
  199. if (!caughtFatal) {
  200. caughtFatal = true;
  201. }
  202. return false;
  203. }
  204. return true; // to verify that a call from JS to here, works. (eg. JS receives "true", thus OK.)
  205. }
  206. public function _disableDebug() : void {
  207. // prevent future debug calls from Flash going to client (maybe improve performance)
  208. writeDebug('_disableDebug()');
  209. debugEnabled = false;
  210. }
  211. public function checkLoadProgress(e: Event) : void {
  212. try {
  213. var oSound:Object = e.target;
  214. var bL: int = oSound.bytesLoaded;
  215. var bT: int = oSound.bytesTotal;
  216. var nD: int = oSound.length || oSound.duration || 0;
  217. var sMethod:String = baseJSObject + "['" + oSound.sID + "']._whileloading";
  218. ExternalInterface.call(sMethod, bL, bT, nD);
  219. if (bL && bT && bL != oSound.lastValues.bytes) {
  220. oSound.lastValues.bytes = bL;
  221. ExternalInterface.call(sMethod, bL, bT, nD);
  222. }
  223. } catch(e: Error) {
  224. writeDebug('checkLoadProgress(): ' + e.toString());
  225. }
  226. }
  227. public function checkProgress() : void {
  228. var bL: int = 0;
  229. var bT: int = 0;
  230. var nD: int = 0;
  231. var nP: int = 0;
  232. var bufferLength: int = 0;
  233. var lP:Number = 0;
  234. var rP:Number = 0;
  235. var isBuffering:Object = null;
  236. var oSound: SoundManager2_SMSound_AS3 = null;
  237. var oSoundChannel: flash.media.SoundChannel = null;
  238. var sMethod:String = null;
  239. var newPeakData: Boolean = false;
  240. var newWaveformData: Boolean = false;
  241. var newEQData: Boolean = false;
  242. var areSoundsInaccessible: Boolean = SoundMixer.areSoundsInaccessible();
  243. var isPlaying: Boolean = true; // special case for NetStream when ending
  244. var hasNew:Boolean = false;
  245. var hasNewLoaded:Boolean = false;
  246. for (var i: int = 0, j: int = sounds.length; i < j; i++) {
  247. oSound = soundObjects[sounds[i]];
  248. sMethod = baseJSObject + "['" + sounds[i] + "']._whileloading";
  249. if (!oSound || !oSound.useEvents || oSound.failed || !oSound.connected) {
  250. // various cases for ignoring
  251. continue; // if sounds are destructed within event handlers while this loop is running, may be null
  252. }
  253. if (oSound.useNetstream) {
  254. // Don't do anything if there is no NetStream object yet
  255. if (!oSound.ns) {
  256. continue;
  257. }
  258. // stream
  259. bufferLength = oSound.ns.bufferLength;
  260. bL = oSound.ns.bytesLoaded;
  261. bT = oSound.ns.bytesTotal;
  262. nD = int(oSound.duration || 0); // can sometimes be null with short MP3s? Wack.
  263. nP = oSound.ns.time * 1000;
  264. if (nP != oSound.lastValues.position) {
  265. oSound.lastValues.position = nP;
  266. hasNew = true;
  267. }
  268. if (nD > oSound.lastValues.duration) {
  269. oSound.lastValues.duration = nD;
  270. hasNew = true;
  271. }
  272. if (bL > oSound.lastValues.bytesLoaded) {
  273. oSound.lastValues.bytesLoaded = bL;
  274. hasNew = true;
  275. }
  276. if (bT > oSound.lastValues.bytes) {
  277. oSound.lastValues.bytes = bT;
  278. hasNew = true;
  279. }
  280. if (bufferLength != oSound.lastValues.bufferLength) {
  281. oSound.lastValues.bufferLength = bufferLength;
  282. hasNew = true;
  283. }
  284. // Don't set loaded for streams because bytesLoaded and bytesTotal are always 0
  285. // writeDebug('ns: time/duration, bytesloaded/total: '+nP+'/'+nD+', '+bL+'/'+bT);
  286. if (oSound.loaded != true && nD > 0 && bL == bT && bL != 0 && bT != 0) {
  287. // non-MP3 has loaded
  288. oSound.loaded = true;
  289. try {
  290. ExternalInterface.call(sMethod, bL, bT, nD, bufferLength);
  291. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onload", oSound.duration > 0 ? 1 : 0);
  292. } catch(e: Error) {
  293. writeDebug('_whileLoading/_onload error: ' + e.toString());
  294. }
  295. } else if (oSound.loaded != true && hasNew) {
  296. ExternalInterface.call(sMethod, bL, bT, nD, bufferLength);
  297. }
  298. } else {
  299. // MP3 sound
  300. oSoundChannel = oSound.soundChannel;
  301. bL = oSound.bytesLoaded;
  302. bT = oSound.bytesTotal;
  303. nD = int(oSound.length || 0); // can sometimes be null with short MP3s? Wack.
  304. isBuffering = oSound.isBuffering;
  305. if (oSoundChannel) {
  306. nP = (oSoundChannel.position || 0);
  307. if (oSound.lastValues.loops > 1 && nP > oSound.length) {
  308. // round down to nearest loop
  309. var playedLoops:Number = Math.floor(nP/oSound.length);
  310. nP = nP - (oSound.length*playedLoops);
  311. }
  312. if (oSound.usePeakData) {
  313. lP = int((oSoundChannel.leftPeak) * 1000) / 1000;
  314. rP = int((oSoundChannel.rightPeak) * 1000) / 1000;
  315. } else {
  316. lP = 0;
  317. rP = 0;
  318. }
  319. } else {
  320. // stopped, not loaded or feature not used
  321. nP = 0;
  322. }
  323. if (nP != oSound.lastValues.position) {
  324. oSound.lastValues.position = nP;
  325. hasNew = true;
  326. }
  327. if (nD > oSound.lastValues.duration) { // original sound duration * number of sound loops
  328. oSound.lastValues.duration = nD;
  329. hasNew = true;
  330. }
  331. if (bL > oSound.lastValues.bytesLoaded) {
  332. oSound.lastValues.bytesLoaded = bL;
  333. hasNew = true;
  334. }
  335. if (bT > oSound.lastValues.bytes) {
  336. oSound.lastValues.bytes = bT;
  337. hasNew = true;
  338. hasNewLoaded = true;
  339. }
  340. // loading progress
  341. if (hasNewLoaded) {
  342. oSound.lastValues.bytes = bL;
  343. ExternalInterface.call(sMethod, bL, bT, nD);
  344. }
  345. }
  346. // peak data
  347. if (oSoundChannel && oSound.usePeakData) {
  348. if (lP != oSound.lastValues.leftPeak) {
  349. oSound.lastValues.leftPeak = lP;
  350. newPeakData = true;
  351. }
  352. if (rP != oSound.lastValues.rightPeak) {
  353. oSound.lastValues.rightPeak = rP;
  354. newPeakData = true;
  355. }
  356. }
  357. var newDataError:Boolean = false;
  358. var dataErrors:Array = [];
  359. // special case: Netstream may try to fire whileplaying() after finishing. check that stop hasn't fired.
  360. isPlaying = (oSound.didLoad && !oSound.paused && (!oSound.useNetstream || (oSound.useNetstream && oSound.lastNetStatus != "NetStream.Play.Stop"))); // don't update if stream has ended
  361. // raw waveform + EQ spectrum data
  362. if (isPlaying && oSoundChannel || oSound.useNetstream) {
  363. if (oSound.useWaveformData) {
  364. if (areSoundsInaccessible == false) {
  365. try {
  366. oSound.getWaveformData();
  367. } catch(e: Error) {
  368. // this shouldn't happen, but does seem to fire from time to time.
  369. writeDebug('getWaveformData() warning: ' + e.toString());
  370. }
  371. } else if (oSound.handledDataError != true && oSound.ignoreDataError != true) {
  372. try {
  373. oSound.getWaveformData();
  374. } catch(e: Error) {
  375. writeDebug('getWaveformData() (waveform data) '+e.toString());
  376. // oSound.useWaveformData = false;
  377. newDataError = true;
  378. dataErrors.push(e.toString());
  379. oSound.handledDataError = true;
  380. }
  381. }
  382. }
  383. if (oSound.useEQData) {
  384. if (areSoundsInaccessible == false) {
  385. try {
  386. oSound.getEQData();
  387. } catch(e: Error) {
  388. writeDebug('getEQData() warning: ' + e.toString());
  389. newDataError = true;
  390. dataErrors.push(e.toString());
  391. oSound.handledDataError = true;
  392. }
  393. } else if (oSound.handledDataError != true && oSound.ignoreDataError != true) {
  394. try {
  395. oSound.getEQData();
  396. } catch(e: Error) {
  397. // writeDebug('computeSpectrum() (EQ data) '+e.toString());
  398. // oSound.useEQData = false;
  399. newDataError = true;
  400. dataErrors.push(e.toString());
  401. oSound.handledDataError = true;
  402. }
  403. }
  404. }
  405. if (oSound.waveformDataArray != oSound.lastValues.waveformDataArray) {
  406. oSound.lastValues.waveformDataArray = oSound.waveformDataArray;
  407. newWaveformData = true;
  408. }
  409. if (oSound.eqDataArray != oSound.lastValues.eqDataArray) {
  410. oSound.lastValues.eqDataArray = oSound.eqDataArray;
  411. newEQData = true;
  412. }
  413. }
  414. if (newDataError) {
  415. sMethod = baseJSObject + "['" + sounds[i] + "']._ondataerror";
  416. var errors:String = dataErrors.join('<br>\n');
  417. ExternalInterface.call(sMethod, 'data unavailable: ' + errors);
  418. }
  419. if (typeof nP != 'undefined' && hasNew) { // && isPlaying - removed to allow updates while paused, eg. from setPosition() calls
  420. // oSound.lastValues.position = nP;
  421. sMethod = baseJSObject + "['" + sounds[i] + "']._whileplaying";
  422. var waveDataLeft:String = (newWaveformData ? oSound.waveformDataArray.slice(0, 256).join(',') : null);
  423. var waveDataRight:String = (newWaveformData ? oSound.waveformDataArray.slice(256).join(',') : null);
  424. var eqDataLeft:String = (newEQData ? oSound.eqDataArray.slice(0, 256).join(',') : null);
  425. var eqDataRight:String = (newEQData ? oSound.eqDataArray.slice(256).join(',') : null);
  426. ExternalInterface.call(sMethod, nP, (newPeakData ? {
  427. leftPeak: lP,
  428. rightPeak: rP
  429. } : null), waveDataLeft, waveDataRight, (newEQData ? {
  430. leftEQ: eqDataLeft,
  431. rightEQ: eqDataRight
  432. } : null));
  433. // if position changed, check for near-end
  434. if (oSound.didJustBeforeFinish != true && oSound.loaded == true && oSound.justBeforeFinishOffset > 0 && nD - nP <= oSound.justBeforeFinishOffset) {
  435. // fully-loaded, near end and haven't done this yet..
  436. sMethod = baseJSObject + "['" + sounds[i] + "']._onjustbeforefinish";
  437. ExternalInterface.call(sMethod, (nD - nP));
  438. oSound.didJustBeforeFinish = true;
  439. }
  440. }
  441. // check isBuffering
  442. if (!oSound.useNetstream && oSound.isBuffering != oSound.lastValues.isBuffering) {
  443. // property has changed
  444. oSound.lastValues.isBuffering = oSound.isBuffering;
  445. sMethod = baseJSObject + "['" + sounds[i] + "']._onbufferchange";
  446. ExternalInterface.call(sMethod, oSound.isBuffering ? 1 : 0);
  447. }
  448. }
  449. }
  450. public function onLoadError(oSound:Object) : void {
  451. // something went wrong. 404, bad format etc.
  452. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onload", 0);
  453. }
  454. public function onLoad(e: Event) : void {
  455. checkProgress(); // ensure progress stats are up-to-date
  456. var oSound:Object = e.target;
  457. if (!oSound.useNetstream) { // FLV must also have metadata
  458. oSound.loaded = true;
  459. // force duration update (doesn't seem to be always accurate)
  460. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._whileloading", oSound.bytesLoaded, oSound.bytesTotal, oSound.length || oSound.duration);
  461. // TODO: Determine if loaded or failed - bSuccess?
  462. // ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._onload",bSuccess?1:0);
  463. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onload", 1);
  464. }
  465. }
  466. public function onID3(e: Event) : void {
  467. // --- NOTE: BUGGY (Flash 8 only? Haven't really checked 9 + 10.) ---
  468. // TODO: Investigate holes in ID3 parsing - for some reason, Album will be populated with Date if empty and date is provided. (?)
  469. // ID3V1 seem to parse OK, but "holes" / blanks in ID3V2 data seem to get messed up (eg. missing album gets filled with date.)
  470. // iTunes issues: onID3 was not called with a test MP3 encoded with iTunes 7.01, and what appeared to be valid ID3V2 data.
  471. // May be related to thumbnails for album art included in MP3 file by iTunes. See http://mabblog.com/blog/?p=33
  472. try {
  473. var oSound:Object = e.target;
  474. var id3Data:Array = [];
  475. var id3Props:Array = [];
  476. for (var prop:String in oSound.id3) {
  477. id3Props.push(prop);
  478. id3Data.push(oSound.id3[prop]);
  479. // writeDebug('id3['+prop+']: '+oSound.id3[prop]);
  480. }
  481. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onid3", id3Props, id3Data);
  482. // unhook own event handler, prevent second call (can fire twice as data is received - ID3V2 at beginning, ID3V1 at end.)
  483. // Therefore if ID3V2 data is received, ID3V1 is ignored.
  484. // soundObjects[oSound.sID].onID3 = null;
  485. } catch(e: Error) {
  486. writeDebug('onID3(): Unable to get ID3 info for ' + oSound.sID + '.');
  487. }
  488. oSound.removeEventListener(Event.ID3, onID3);
  489. }
  490. public function registerOnComplete(sID:String) : void {
  491. var oSound: SoundManager2_SMSound_AS3 = soundObjects[sID];
  492. if (oSound && oSound.soundChannel) {
  493. oSound.soundChannel.addEventListener(Event.SOUND_COMPLETE, function() : void {
  494. if (oSound) {
  495. oSound.didJustBeforeFinish = false; // reset
  496. checkProgress();
  497. try {
  498. oSound.ignoreDataError = true; // workaround: avoid data error handling for this manual step..
  499. oSound.start(0, 1); // go back to 0
  500. oSound.soundChannel.stop();
  501. } catch(e: Error) {
  502. writeDebug('Could not set position on ' + sID + ': ' + e.toString());
  503. }
  504. oSound.ignoreDataError = false; // ..and reset
  505. oSound.handledDataError = false; // reset this flag
  506. }
  507. // checkProgress();
  508. ExternalInterface.call(baseJSObject + "['" + sID + "']._onfinish");
  509. });
  510. }
  511. }
  512. public function doSecurityError(oSound: SoundManager2_SMSound_AS3, e: SecurityErrorEvent) : void {
  513. writeDebug('securityError: ' + e.text);
  514. // when this happens, you don't have security rights on the server containing the FLV file
  515. // a crossdomain.xml file would fix the problem easily
  516. }
  517. public function _setPosition(sID:String, nSecOffset:Number, isPaused: Boolean) : void {
  518. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  519. if (!s) return void;
  520. // writeDebug('_setPosition()');
  521. // stop current channel, start new one.
  522. if (s.lastValues) {
  523. s.lastValues.position = nSecOffset; // s.soundChannel.position;
  524. }
  525. if (s.useNetstream) {
  526. // Minimize the buffer so playback starts ASAP
  527. s.setBuffer(s.getStartBuffer());
  528. writeDebug('setPosition: setting buffer to '+s.ns.bufferTime+' secs');
  529. nSecOffset = nSecOffset > 0 ? nSecOffset / 1000 : 0;
  530. writeDebug('setPosition: ' + nSecOffset);
  531. s.ns.seek(nSecOffset);
  532. checkProgress(); // force UI update
  533. } else {
  534. if (s.soundChannel) {
  535. s.soundChannel.stop();
  536. }
  537. writeDebug('setPosition: ' + nSecOffset); // +', '+(s.lastValues.loops?s.lastValues.loops:1));
  538. if (s.lastValues.loops > 1 && nSecOffset != 0) {
  539. writeDebug('Warning: Looping functionality being disabled due to Flash limitation.');
  540. s.lastValues.loops = 1;
  541. }
  542. try {
  543. s.start(nSecOffset, s.lastValues.loops || 1); // start playing at new position
  544. } catch(e: Error) {
  545. writeDebug('Warning: Could not set position on ' + sID + ': ' + e.toString());
  546. }
  547. checkProgress(); // force UI update
  548. try {
  549. registerOnComplete(sID);
  550. } catch(e: Error) {
  551. writeDebug('_setPosition(): Could not register onComplete');
  552. }
  553. if (isPaused && s.soundChannel) {
  554. // writeDebug('_setPosition: stopping (paused) sound');
  555. // writeDebug('last position: '+s.lastValues.position+' vs '+s.soundChannel.position);
  556. s.soundChannel.stop();
  557. }
  558. }
  559. }
  560. public function _load(sID:String, sURL:String, bStream: Boolean, bAutoPlay: Boolean, nLoops: Number, bAutoLoad: Boolean, bCheckPolicyFile: Boolean) : void {
  561. // writeDebug('_load()');
  562. if (typeof bAutoPlay == 'undefined') bAutoPlay = false;
  563. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  564. if (!s) return void;
  565. var didRecreate: Boolean = false;
  566. if (s.didLoad == true) {
  567. // need to recreate sound
  568. didRecreate = true;
  569. writeDebug('recreating sound ' + sID + ' in order to load ' + sURL);
  570. var ns:Object = new Object();
  571. ns.sID = s.sID;
  572. ns.loops = nLoops||1;
  573. ns.justBeforeFinishOffset = s.justBeforeFinishOffset;
  574. ns.usePeakData = s.usePeakData;
  575. ns.useWaveformData = s.useWaveformData;
  576. ns.useEQData = s.useEQData;
  577. ns.useNetstream = s.useNetstream;
  578. ns.bufferTime = s.bufferTime;
  579. ns.bufferTimes = s.bufferTimes;
  580. ns.serverUrl = s.serverUrl;
  581. ns.duration = s.duration;
  582. ns.recordStats = s.recordStats;
  583. ns.checkPolicyFile = s.checkPolicyFile;
  584. ns.useEvents = true;
  585. _destroySound(s.sID);
  586. _createSound(ns.sID, sURL, ns.justBeforeFinishOffset, ns.usePeakData, ns.useWaveformData, ns.useEQData, ns.useNetstream, ns.bufferTime, ns.loops, ns.serverUrl, ns.duration, bAutoPlay, ns.useEvents, ns.bufferTimes, ns.recordStats, bAutoLoad, ns.checkPolicyFile);
  587. s = soundObjects[sID];
  588. // writeDebug('Sound object replaced');
  589. }
  590. checkProgress();
  591. if (!s.didLoad) {
  592. try {
  593. s.addEventListener(Event.ID3, onID3);
  594. s.addEventListener(Event.COMPLETE, onLoad);
  595. } catch(e: Error) {
  596. writeDebug('_load(): could not assign ID3/complete event handlers');
  597. }
  598. }
  599. // don't try to load if same request already made
  600. s.sURL = sURL;
  601. if (s.useNetstream) {
  602. try {
  603. s.useEvents = true;
  604. s.ns.play(sURL);
  605. } catch(e: Error) {
  606. writeDebug('_load(): error: ' + e.toString());
  607. }
  608. } else {
  609. try {
  610. s.addEventListener(IOErrorEvent.IO_ERROR, function(e: IOErrorEvent) : void {
  611. s.doIOError(e);
  612. });
  613. s.loadSound(sURL, bStream);
  614. } catch(e: Error) {
  615. // oh well
  616. writeDebug('_load: Error loading ' + sURL + '. Flash error detail: ' + e.toString());
  617. }
  618. }
  619. s.didJustBeforeFinish = false;
  620. }
  621. public function _unload(sID:String) : void {
  622. var s: SoundManager2_SMSound_AS3 = (soundObjects[sID] || null);
  623. if (!s) return void;
  624. var sURL:String = s.sURL; // save existing sound URL for object recreation
  625. try {
  626. removeEventListener(Event.ID3, onID3);
  627. removeEventListener(Event.COMPLETE, onLoad);
  628. } catch(e: Error) {
  629. writeDebug('_unload() warn: Could not remove ID3/complete events');
  630. }
  631. s.paused = false;
  632. if (s.soundChannel) {
  633. s.soundChannel.stop();
  634. }
  635. try {
  636. if (s.didLoad && !s.loaded && !s.useNetstream) {
  637. s.close(); // close stream only if still loading?
  638. }
  639. } catch(e: Error) {
  640. // stream may already have closed if sound loaded, etc.
  641. writeDebug(sID + '._unload(): Note: Unable to close stream: ' + e.toString());
  642. // oh well
  643. }
  644. // destroy and recreate Flash sound object, try to reclaim memory
  645. // writeDebug('sound._unload(): recreating sound '+sID+' to free memory');
  646. if (s.useNetstream) {
  647. // writeDebug('_unload(): closing netStream stuff');
  648. try {
  649. s.removeNetstreamEvents();
  650. s.ns.close();
  651. s.nc.close();
  652. // s.nc = null;
  653. // s.ns = null;
  654. } catch(e: Error) {
  655. // oh well
  656. writeDebug('_unload(): caught exception during netConnection/netStream close');
  657. }
  658. }
  659. var ns:Object = new Object();
  660. ns.sID = s.sID;
  661. ns.loops = s.loops;
  662. ns.justBeforeFinishOffset = s.justBeforeFinishOffset;
  663. ns.usePeakData = s.usePeakData;
  664. ns.useWaveformData = s.useWaveformData;
  665. ns.useEQData = s.useEQData;
  666. ns.useNetstream = s.useNetstream;
  667. ns.bufferTime = s.bufferTime;
  668. ns.bufferTimes = s.bufferTimes;
  669. ns.serverUrl = s.serverUrl;
  670. ns.duration = s.duration;
  671. ns.autoPlay = s.autoPlay;
  672. ns.recordStats = s.recordStats;
  673. ns.autoLoad = s.autoLoad;
  674. ns.checkPolicyFile = s.checkPolicyFile;
  675. _destroySound(s.sID);
  676. _createSound(ns.sID, sURL, ns.justBeforeFinishOffset, ns.usePeakData, ns.useWaveformData, ns.useEQData, ns.useNetstream, ns.bufferTime, ns.loops, ns.serverUrl, ns.duration, ns.autoPlay, false, ns.bufferTimes, ns.recordStats, ns.autoLoad, ns.checkPolicyFile); // false: don't allow events just yet
  677. soundObjects[sID].connected = true; // fake it?
  678. writeDebug(s.sID + '.unload(): ok');
  679. }
  680. public function _createSound(sID:String, sURL:String, justBeforeFinishOffset: int, usePeakData: Boolean, useWaveformData: Boolean, useEQData: Boolean, useNetstream: Boolean, bufferTime:Number, loops:Number, serverUrl:String, duration:Number, autoPlay:Boolean, useEvents:Boolean, bufferTimes:Array, recordStats:Boolean, autoLoad:Boolean, checkPolicyFile:Boolean) : void {
  681. var s: SoundManager2_SMSound_AS3 = new SoundManager2_SMSound_AS3(this, sID, sURL, usePeakData, useWaveformData, useEQData, useNetstream, bufferTime, serverUrl, duration, autoPlay, useEvents, bufferTimes, recordStats, autoLoad, checkPolicyFile);
  682. if (!soundObjects[sID]) {
  683. sounds.push(sID);
  684. }
  685. soundObjects[sID] = s;
  686. this.currentObject = s;
  687. s.didJustBeforeFinish = false;
  688. s.sID = sID;
  689. s.sURL = sURL;
  690. s.paused = false;
  691. s.loaded = false;
  692. s.justBeforeFinishOffset = justBeforeFinishOffset || 0;
  693. s.checkPolicyFile = checkPolicyFile;
  694. s.lastValues = {
  695. bytes: 0,
  696. position: 0,
  697. loops: loops||1,
  698. leftPeak: 0,
  699. rightPeak: 0,
  700. bufferLength: 0
  701. };
  702. }
  703. public function _destroySound(sID:String) : void {
  704. // for the power of garbage collection! .. er, Greyskull!
  705. var s: SoundManager2_SMSound_AS3 = (soundObjects[sID] || null);
  706. if (!s) return void;
  707. // try to unload the sound
  708. for (var i: int = 0, j: int = sounds.length; i < j; i++) {
  709. if (sounds[i] == sID) {
  710. sounds.splice(i, 1);
  711. break;
  712. }
  713. }
  714. if (s.soundChannel) {
  715. s.soundChannel.stop();
  716. }
  717. // if is a movie, remove that as well.
  718. if (s.useNetstream) {
  719. // s.nc.client = null;
  720. try {
  721. s.removeNetstreamEvents();
  722. // s.nc.removeEventListener(NetStatusEvent.NET_STATUS, s.doNetStatus);
  723. } catch(e: Error) {
  724. writeDebug('_destroySound(): Events already removed from netStream/netConnection?');
  725. }
  726. if (s.didLoad) {
  727. // TODO: figure out if stream is still open first, can't close an already-closed stream.
  728. try {
  729. s.ns.close();
  730. s.nc.close();
  731. } catch(e: Error) {
  732. // oh well
  733. writeDebug('_destroySound(): caught exception: '+e.toString());
  734. }
  735. }
  736. } else if (s.didLoad) {
  737. // non-netstream case
  738. try {
  739. s.close(); // close stream only if still loading?
  740. } catch(e: Error) {
  741. // oh well
  742. }
  743. }
  744. s = null;
  745. soundObjects[sID] = null;
  746. delete soundObjects[sID];
  747. }
  748. public function _stop(sID:String, bStopAll: Boolean) : void {
  749. // stop this particular instance (or "all", based on parameter)
  750. if (bStopAll) {
  751. SoundMixer.stopAll();
  752. } else {
  753. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  754. if (!s) return void;
  755. if (s.useNetstream && s.ns) {
  756. s.ns.pause();
  757. } else if (s.soundChannel) {
  758. s.soundChannel.stop();
  759. }
  760. s.paused = false;
  761. s.didJustBeforeFinish = false;
  762. }
  763. }
  764. public function _start(sID:String, nLoops: int, nMsecOffset: int) : void {
  765. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  766. if (!s) return void;
  767. writeDebug('start: ' + nMsecOffset+(nLoops?', loops: '+nLoops:''));
  768. s.lastValues.paused = false; // reset pause if applicable
  769. s.lastValues.loops = (nLoops || 1);
  770. if (!s.useNetstream) {
  771. s.lastValues.position = nMsecOffset;
  772. }
  773. s.handledDataError = false; // reset this flag
  774. try {
  775. s.start(nMsecOffset, nLoops);
  776. } catch(e: Error) {
  777. writeDebug('Could not start ' + sID + ': ' + e.toString());
  778. }
  779. try {
  780. registerOnComplete(sID);
  781. } catch(e: Error) {
  782. writeDebug('_start(): registerOnComplete failed');
  783. }
  784. }
  785. public function _pause(sID:String) : void {
  786. // writeDebug('_pause()');
  787. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  788. if (!s) return void;
  789. // writeDebug('s.paused: '+s.paused);
  790. if (!s.paused) {
  791. // reference current position, stop sound
  792. s.paused = true;
  793. // writeDebug('_pause(): position: '+s.lastValues.position);
  794. if (s.useNetstream) {
  795. if (s.ns) {
  796. s.lastValues.position = s.ns.time;
  797. s.ns.pause();
  798. } else if (s.autoPlay) {
  799. s.setAutoPlay(false);
  800. }
  801. } else {
  802. if (s.soundChannel) {
  803. s.lastValues.position = s.soundChannel.position;
  804. s.soundChannel.stop();
  805. }
  806. }
  807. } else {
  808. // resume playing from last position
  809. // writeDebug('resuming - playing at '+s.lastValues.position+', '+s.lastValues.loops+' times');
  810. s.paused = false;
  811. if (s.useNetstream) {
  812. s.ns.resume();
  813. } else {
  814. s.start(s.lastValues.position, s.lastValues.loops);
  815. }
  816. try {
  817. registerOnComplete(sID);
  818. } catch(e: Error) {
  819. writeDebug('_pause(): registerOnComplete() failed');
  820. }
  821. }
  822. }
  823. public function _setPan(sID:String, nPan:Number) : void {
  824. if (soundObjects[sID]) {
  825. soundObjects[sID].setPan(nPan);
  826. }
  827. }
  828. public function _setVolume(sID:String, nVol:Number) : void {
  829. // writeDebug('_setVolume: '+nVol);
  830. if (soundObjects[sID]) {
  831. soundObjects[sID].setVolume(nVol);
  832. }
  833. }
  834. public function _setPolling(bPolling: Boolean = false, bUseHighPerformanceTimer: Boolean = false) : void {
  835. pollingEnabled = bPolling;
  836. if (timer == null && pollingEnabled) {
  837. var nTimerInterval: uint = (bUseHighPerformanceTimer ? timerIntervalHighPerformance : timerInterval);
  838. writeDebug('Enabling polling, ' + nTimerInterval + ' ms interval');
  839. timer = new Timer(nTimerInterval, 0);
  840. timer.addEventListener(TimerEvent.TIMER, function() : void {
  841. checkProgress();
  842. }); // direct reference eg. checkProgress doesn't work? .. odd.
  843. timer.start();
  844. } else if (timer && !pollingEnabled) {
  845. writeDebug('Disabling polling');
  846. // flash.utils.clearInterval(timer);
  847. timer.reset();
  848. }
  849. }
  850. public function _getMemoryUse() : String {
  851. return System.totalMemory.toString();
  852. }
  853. // XML handler stuff
  854. public function _loadFromXML(sURL:String) : void {
  855. var loader: URLLoader = new URLLoader();
  856. loader.addEventListener(Event.COMPLETE, parseXML);
  857. writeDebug('Attempting to load XML: ' + sURL);
  858. try {
  859. loader.load(new URLRequest(sURL));
  860. } catch(e: Error) {
  861. writeDebug('Error loading XML: ' + e.toString());
  862. }
  863. }
  864. public function parseXML(e: Event) : void {
  865. try {
  866. var oXML: XMLDocument = new XMLDocument();
  867. oXML.ignoreWhite = true;
  868. oXML.parseXML(e.target.data);
  869. var xmlRoot: XMLNode = oXML.firstChild;
  870. var xmlAttr:Object = xmlRoot.attributes;
  871. var oOptions:Object = {};
  872. var i: int = 0;
  873. var j: int = 0;
  874. for (i = 0, j = xmlRoot.childNodes.length; i < j; i++) {
  875. xmlAttr = xmlRoot.childNodes[i].attributes;
  876. oOptions = {
  877. id: xmlAttr.id,
  878. url: xmlRoot.attributes.baseHref + xmlAttr.href,
  879. stream: xmlAttr.stream
  880. }
  881. ExternalInterface.call(baseJSController + ".createSound", oOptions);
  882. }
  883. } catch(e: Error) {
  884. writeDebug('Error parsing XML: ' + e.toString());
  885. }
  886. }
  887. // -----------------------------------
  888. // end methods
  889. }
  890. // package
  891. }