PageRenderTime 70ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/BARN/Server/barn/public/javascripts/soundmanager2/src/SoundManager2_AS3.as

http://xbat-devel.googlecode.com/
ActionScript | 1177 lines | 922 code | 95 blank | 160 comment | 267 complexity | b924ed1983830e51a1dc3f5a5cd019c2 MD5 | raw file
Possible License(s): AGPL-1.0, AGPL-3.0, GPL-2.0, BSD-3-Clause, LGPL-2.1, MIT, BSD-2-Clause, LGPL-2.0
  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.display.StageAlign;
  13. import flash.display.StageDisplayState;
  14. import flash.display.StageScaleMode;
  15. import flash.events.Event;
  16. import flash.events.FullScreenEvent;
  17. import flash.events.IOErrorEvent;
  18. import flash.events.MouseEvent;
  19. import flash.events.SecurityErrorEvent;
  20. import flash.events.AsyncErrorEvent;
  21. import flash.events.NetStatusEvent;
  22. import flash.events.TimerEvent;
  23. import flash.external.ExternalInterface; // woo
  24. import flash.geom.Rectangle;
  25. import flash.media.Sound;
  26. import flash.media.SoundChannel;
  27. import flash.media.SoundMixer;
  28. import flash.net.URLLoader;
  29. import flash.net.URLRequest;
  30. import flash.system.Security;
  31. import flash.system.System;
  32. import flash.text.TextField;
  33. import flash.text.TextFormat;
  34. import flash.text.TextFieldAutoSize;
  35. import flash.ui.ContextMenu;
  36. import flash.ui.ContextMenuItem;
  37. import flash.utils.setInterval;
  38. import flash.utils.clearInterval;
  39. import flash.utils.Dictionary;
  40. import flash.utils.Timer;
  41. import flash.xml.XMLDocument;
  42. import flash.xml.XMLNode;
  43. public class SoundManager2_AS3 extends Sprite {
  44. public var version:String = "V2.96a.20100606";
  45. public var version_as:String = "(AS3/Flash 9)";
  46. /*
  47. * Cross-domain security options
  48. * HTML on foo.com loading .swf hosted on bar.com? Define your "HTML domain" here to allow JS+Flash communication to work.
  49. * // allow_xdomain_scripting = true;
  50. * // xdomain = "foo.com";
  51. * For all domains (possible security risk?), use xdomain = "*"; which ends up as System.security.allowDomain("*");
  52. * When loading from HTTPS, use System.security.allowInsecureDomain();
  53. * See http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/Security.html#allowDomain()
  54. */
  55. public var allow_xdomain_scripting:Boolean = false;
  56. public var xdomain:String = "*";
  57. // externalInterface references (for Javascript callbacks)
  58. public var baseJSController:String = "soundManager";
  59. public var baseJSObject:String = baseJSController + ".sounds";
  60. // internal objects
  61. public var sounds:Array = []; // indexed string array
  62. public var soundObjects: Dictionary = new Dictionary(); // associative Sound() object Dictionary type
  63. public var timerInterval: uint = 50;
  64. public var timerIntervalHighPerformance: uint = 10; // ~30fps (in Safari on OSX, anyway..)
  65. public var timer: Timer = null;
  66. public var pollingEnabled: Boolean = false; // polling (timer) flag - disabled by default, enabled by JS->Flash call
  67. public var debugEnabled: Boolean = true; // Flash debug output enabled by default, disabled by JS call
  68. public var flashDebugEnabled: Boolean = false; // Flash internal debug output (write to visible SWF in browser)
  69. public var loaded: Boolean = false;
  70. public var isFullScreen: Boolean = false;
  71. public var currentObject: SoundManager2_SMSound_AS3 = null;
  72. public var paramList:Object = null;
  73. public var messages:Array = [];
  74. public var textField: TextField = null;
  75. public var textStyle: TextFormat = new TextFormat();
  76. public var didSandboxMessage: Boolean = false;
  77. public var caughtFatal: Boolean = false;
  78. public function SoundManager2_AS3() {
  79. if (allow_xdomain_scripting && xdomain) {
  80. Security.allowDomain(xdomain);
  81. version_as += ' - cross-domain enabled';
  82. }
  83. this.setDefaultStageScale();
  84. this.paramList = this.root.loaderInfo.parameters;
  85. // <d>
  86. if (this.paramList['debug'] == 1) {
  87. this.flashDebugEnabled = true;
  88. }
  89. if (this.flashDebugEnabled) {
  90. var canvas: Sprite = new Sprite();
  91. canvas.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
  92. addChild(canvas);
  93. }
  94. // </d>
  95. flashDebug('SM2 SWF ' + version + ' ' + version_as);
  96. // context menu item with version info
  97. var sm2Menu:ContextMenu = new ContextMenu();
  98. var sm2MenuItem:ContextMenuItem = new ContextMenuItem('SoundManager ' + version + ' ' + version_as);
  99. sm2MenuItem.enabled = false;
  100. sm2Menu.customItems.push(sm2MenuItem);
  101. contextMenu = sm2Menu;
  102. if (ExternalInterface.available) {
  103. flashDebug('ExternalInterface available');
  104. try {
  105. flashDebug('Adding ExternalInterface callbacks...');
  106. ExternalInterface.addCallback('_load', _load);
  107. ExternalInterface.addCallback('_unload', _unload);
  108. ExternalInterface.addCallback('_stop', _stop);
  109. ExternalInterface.addCallback('_start', _start);
  110. ExternalInterface.addCallback('_pause', _pause);
  111. ExternalInterface.addCallback('_setPosition', _setPosition);
  112. ExternalInterface.addCallback('_setPan', _setPan);
  113. ExternalInterface.addCallback('_setVolume', _setVolume);
  114. ExternalInterface.addCallback('_setPolling', _setPolling);
  115. ExternalInterface.addCallback('_externalInterfaceTest', _externalInterfaceTest);
  116. ExternalInterface.addCallback('_disableDebug', _disableDebug);
  117. ExternalInterface.addCallback('_getMemoryUse', _getMemoryUse);
  118. ExternalInterface.addCallback('_loadFromXML', _loadFromXML);
  119. ExternalInterface.addCallback('_createSound', _createSound);
  120. ExternalInterface.addCallback('_destroySound', _destroySound);
  121. ExternalInterface.addCallback('_setAutoPlay', _setAutoPlay);
  122. } catch(e: Error) {
  123. flashDebug('Fatal: ExternalInterface error: ' + e.toString());
  124. }
  125. } else {
  126. flashDebug('Fatal: ExternalInterface (Flash &lt;-&gt; JS) not available');
  127. };
  128. // call after delay, to be safe (ensure callbacks are registered by the time JS is called below)
  129. var timer: Timer = new Timer(20, 0);
  130. timer.addEventListener(TimerEvent.TIMER, function () : void {
  131. timer.reset();
  132. _externalInterfaceTest(true);
  133. // timer.reset();
  134. // flashDebug('Init OK');
  135. });
  136. timer.start();
  137. // delayed, see above
  138. // _externalInterfaceTest(true);
  139. this.stage.addEventListener(MouseEvent.DOUBLE_CLICK, toggleFullScreen);
  140. this.stage.doubleClickEnabled = true;
  141. this.stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullscreenHandler);
  142. } // SoundManager2()
  143. public function flashDebug (txt:String) : void {
  144. // <d>
  145. messages.push(txt);
  146. if (this.flashDebugEnabled) {
  147. var didCreate: Boolean = false;
  148. textStyle.font = 'Arial';
  149. textStyle.size = 12;
  150. // 320x240 if no stage dimensions (happens in IE, apparently 0 before stage resize event fires.)
  151. var w:Number = this.stage.width?this.stage.width:320;
  152. var h:Number = this.stage.height?this.stage.height:240;
  153. if (textField == null) {
  154. didCreate = true;
  155. textField = new TextField();
  156. textField.autoSize = TextFieldAutoSize.LEFT;
  157. textField.x = 0;
  158. textField.y = 0;
  159. textField.multiline = true;
  160. textField.textColor = 0;
  161. textField.wordWrap = true;
  162. }
  163. textField.htmlText = messages.join('\n');
  164. textField.setTextFormat(textStyle);
  165. textField.width = w;
  166. textField.height = h;
  167. if (didCreate) {
  168. this.addChild(textField);
  169. }
  170. }
  171. // </d>
  172. }
  173. public function _setAutoPlay(sID:String, autoPlay:Boolean) : void {
  174. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  175. s.setAutoPlay(autoPlay);
  176. }
  177. public function fullscreenHandler(e: FullScreenEvent) : void {
  178. writeDebug('fullscreenHandler(): ' + e.toString());
  179. if (e.fullScreen == true) {
  180. this.isFullScreen = true;
  181. } else {
  182. // user left full-screen
  183. this.isFullScreen = false;
  184. }
  185. ExternalInterface.call(baseJSController + "['_onfullscreenchange']", e.fullScreen == true ? 1 : 0);
  186. }
  187. public function toggleFullScreen(e: MouseEvent) : void {
  188. writeDebug('SoundManager2_AS3.toggleFullScreen()');
  189. if (this.currentObject && this.currentObject.useVideo) {
  190. if (this.currentObject.videoWidth == 0) {
  191. writeDebug('toggleFullScreen(): video width is 0 (metadata missing/not loaded yet?) Trying stage width/height');
  192. this.currentObject.videoWidth = this.stage.width;
  193. this.currentObject.videoHeight = this.stage.height;
  194. }
  195. try {
  196. stage.scaleMode = StageScaleMode.NO_SCALE;
  197. stage.align = StageAlign.TOP_LEFT;
  198. stage.fullScreenSourceRect = new Rectangle(0, 0, this.currentObject.videoWidth, this.currentObject.videoHeight);
  199. stage.displayState = StageDisplayState.FULL_SCREEN;
  200. } catch(e: Error) {
  201. // write debug message?
  202. writeDebug('Unable to switch to full-screen. ' + e.toString());
  203. }
  204. } else {
  205. writeDebug('toggleFullScreen(): No active video to show?');
  206. }
  207. }
  208. public function setDefaultStageScale() : void {
  209. stage.scaleMode = StageScaleMode.NO_SCALE;
  210. stage.align = StageAlign.TOP_LEFT;
  211. }
  212. // methods
  213. // -----------------------------------
  214. public function _exitFullScreen() : void {
  215. try {
  216. stage.displayState = StageDisplayState.NORMAL;
  217. this.setDefaultStageScale();
  218. this.isFullScreen = false;
  219. ExternalInterface.call(baseJSController + "._onfullscreenchange", 0);
  220. } catch(e: Error) {
  221. // oh well
  222. writeDebug('exitFullScreen error: ' + e.toString());
  223. }
  224. }
  225. public function writeDebug (s:String, bTimestamp: Boolean = false) : Boolean {
  226. if (!debugEnabled) return false;
  227. // <d>
  228. ExternalInterface.call(baseJSController + "['_writeDebug']", "(Flash): " + s, null, bTimestamp);
  229. // </d>
  230. return true;
  231. }
  232. public function _externalInterfaceTest(isFirstCall: Boolean) : Boolean {
  233. var sandboxType:String = flash.system.Security['sandboxType'];
  234. if (!didSandboxMessage && sandboxType != 'localTrusted' && sandboxType != 'remote') {
  235. didSandboxMessage = true;
  236. 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');
  237. }
  238. try {
  239. if (isFirstCall == true) {
  240. flashDebug('Testing Flash -&gt; JS...');
  241. var d: Date = new Date();
  242. ExternalInterface.call(baseJSController + "._externalInterfaceOK", d.getTime());
  243. flashDebug('Flash -&gt; JS OK');
  244. } else {
  245. writeDebug('SM2 SWF ' + version + ' ' + version_as);
  246. flashDebug('JS -> Flash OK');
  247. ExternalInterface.call(baseJSController + "._setSandboxType", sandboxType);
  248. writeDebug('JS to/from Flash OK');
  249. }
  250. } catch(e: Error) {
  251. flashDebug('Fatal: Flash &lt;-&gt; JS error: ' + e.toString());
  252. writeDebug('_externalInterfaceTest: Error: ' + e.toString());
  253. if (!caughtFatal) {
  254. caughtFatal = true;
  255. }
  256. return false;
  257. }
  258. return true; // to verify that a call from JS to here, works. (eg. JS receives "true", thus OK.)
  259. }
  260. public function _disableDebug() : void {
  261. // prevent future debug calls from Flash going to client (maybe improve performance)
  262. writeDebug('_disableDebug()');
  263. debugEnabled = false;
  264. }
  265. public function checkLoadProgress(e: Event) : void {
  266. try {
  267. var oSound:Object = e.target;
  268. var bL: int = oSound.bytesLoaded;
  269. var bT: int = oSound.bytesTotal || oSound.totalBytes;
  270. var nD: int = oSound.length || oSound.duration || 0;
  271. var sMethod:String = baseJSObject + "['" + oSound.sID + "']._whileloading";
  272. ExternalInterface.call(sMethod, bL, bT, nD);
  273. if (bL && bT && bL != oSound.lastValues.bytes) {
  274. oSound.lastValues.bytes = bL;
  275. ExternalInterface.call(sMethod, bL, bT, nD);
  276. }
  277. } catch(e: Error) {
  278. writeDebug('checkLoadProgress(): ' + e.toString());
  279. }
  280. }
  281. public function checkProgress() : void {
  282. var bL: int = 0;
  283. var bT: int = 0;
  284. var nD: int = 0;
  285. var nP: int = 0;
  286. var lP:Number = 0;
  287. var rP:Number = 0;
  288. var isBuffering:Object = null;
  289. var oSound: SoundManager2_SMSound_AS3 = null;
  290. var oSoundChannel: flash.media.SoundChannel = null;
  291. var sMethod:String = null;
  292. var newPeakData: Boolean = false;
  293. var newWaveformData: Boolean = false;
  294. var newEQData: Boolean = false;
  295. var areSoundsInaccessible: Boolean = SoundMixer.areSoundsInaccessible();
  296. var isPlaying: Boolean = true; // special case for NetStream when ending
  297. for (var i: int = 0, j: int = sounds.length; i < j; i++) {
  298. oSound = soundObjects[sounds[i]];
  299. sMethod = baseJSObject + "['" + sounds[i] + "']._whileloading";
  300. if (!oSound || !oSound.useEvents || oSound.failed || !oSound.connected) {
  301. // various cases for ignoring
  302. continue; // if sounds are destructed within event handlers while this loop is running, may be null
  303. }
  304. var hasNew:Boolean = false;
  305. var hasNewLoaded:Boolean = false;
  306. if (oSound.useNetstream) {
  307. // video stream
  308. bL = oSound.ns.bytesLoaded;
  309. bT = oSound.ns.bytesTotal || oSound.totalBytes;
  310. nD = int(oSound.duration || 0); // can sometimes be null with short MP3s? Wack.
  311. nP = oSound.ns.time * 1000;
  312. if (nP != oSound.lastValues.position) {
  313. oSound.lastValues.position = nP;
  314. hasNew = true;
  315. }
  316. if (nD > oSound.lastValues.duration) {
  317. oSound.lastValues.duration = nD;
  318. hasNew = true;
  319. }
  320. if (bL > oSound.lastValues.bytesLoaded) {
  321. oSound.lastValues.bytesLoaded = bL;
  322. hasNew = true;
  323. }
  324. if (bT > oSound.lastValues.bytes) {
  325. oSound.lastValues.bytes = bT;
  326. hasNew = true;
  327. }
  328. if (oSound.loaded != true && nD > 0 && bL == bT) {
  329. // non-MP3 has loaded
  330. // writeDebug('ns: time/duration, bytesloaded/total: '+nP+'/'+nD+', '+bL+'/'+bT);
  331. oSound.loaded = true;
  332. try {
  333. ExternalInterface.call(sMethod, bL, bT, nD); // _whileloading()
  334. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onload", oSound.duration > 0 ? 1 : 0);
  335. } catch(e: Error) {
  336. writeDebug('_whileLoading/_onload error: ' + e.toString());
  337. }
  338. } else if (oSound.loaded != true && hasNew) {
  339. // writeDebug('whileloading() loaded/total/duration: '+bL+', '+bT+', '+nD);
  340. ExternalInterface.call(sMethod, bL, bT, nD); // _whileloading()
  341. } else if (!oSound.loaded && bL == 0 && bT && oSound.ns.bufferLength != oSound.lastValues.bufferLength) {
  342. // TODO: Verify if this merge is correct with above logic.
  343. // KJV For our RTMP streams bytesLoaded is always 0!
  344. // writeDebug('updating position with bufferLength ' + oSound.ns.bufferLength);
  345. oSound.lastValues.bufferLength = oSound.ns.bufferLength;
  346. ExternalInterface.call(sMethod, bL, bT, nD, oSound.ns.bufferLength);
  347. }
  348. } else {
  349. // MP3 sound
  350. oSoundChannel = oSound.soundChannel;
  351. bL = oSound.bytesLoaded;
  352. bT = oSound.bytesTotal;
  353. nD = int(oSound.length || 0); // can sometimes be null with short MP3s? Wack.
  354. isBuffering = oSound.isBuffering;
  355. if (oSoundChannel) {
  356. nP = (oSoundChannel.position || 0);
  357. if (oSound.lastValues.loops > 1 && nP > oSound.length) {
  358. // round down to nearest loop
  359. var playedLoops:Number = Math.floor(nP/oSound.length);
  360. nP = nP - (oSound.length*playedLoops);
  361. }
  362. if (oSound.usePeakData) {
  363. lP = int((oSoundChannel.leftPeak) * 1000) / 1000;
  364. rP = int((oSoundChannel.rightPeak) * 1000) / 1000;
  365. } else {
  366. lP = 0;
  367. rP = 0;
  368. }
  369. } else {
  370. // stopped, not loaded or feature not used
  371. nP = 0;
  372. }
  373. if (nP != oSound.lastValues.position) {
  374. oSound.lastValues.position = nP;
  375. hasNew = true;
  376. }
  377. if (nD > oSound.lastValues.duration) { // original sound duration * number of sound loops
  378. oSound.lastValues.duration = nD;
  379. hasNew = true;
  380. }
  381. if (bL > oSound.lastValues.bytesLoaded) {
  382. oSound.lastValues.bytesLoaded = bL;
  383. hasNew = true;
  384. }
  385. if (bT > oSound.lastValues.bytes) {
  386. oSound.lastValues.bytes = bT;
  387. hasNew = true;
  388. hasNewLoaded = true;
  389. }
  390. // loading progress
  391. if (hasNewLoaded) {
  392. oSound.lastValues.bytes = bL;
  393. ExternalInterface.call(sMethod, bL, bT, nD);
  394. }
  395. }
  396. // peak data
  397. if (oSoundChannel && oSound.usePeakData) {
  398. if (lP != oSound.lastValues.leftPeak) {
  399. oSound.lastValues.leftPeak = lP;
  400. newPeakData = true;
  401. }
  402. if (rP != oSound.lastValues.rightPeak) {
  403. oSound.lastValues.rightPeak = rP;
  404. newPeakData = true;
  405. }
  406. }
  407. var newDataError:Boolean = false;
  408. var dataErrors:Array = [];
  409. // raw waveform + EQ spectrum data
  410. if (oSoundChannel || oSound.useNetstream) {
  411. if (oSound.useWaveformData) {
  412. if (areSoundsInaccessible == false) {
  413. try {
  414. oSound.getWaveformData();
  415. } catch(e: Error) {
  416. // this shouldn't happen, but does seem to fire from time to time.
  417. writeDebug('getWaveformData() warning: ' + e.toString());
  418. }
  419. } else if (oSound.handledDataError != true && oSound.ignoreDataError != true) {
  420. try {
  421. oSound.getWaveformData();
  422. } catch(e: Error) {
  423. writeDebug('getWaveformData() (waveform data) '+e.toString());
  424. // oSound.useWaveformData = false;
  425. newDataError = true;
  426. dataErrors.push(e.toString());
  427. oSound.handledDataError = true;
  428. }
  429. }
  430. }
  431. if (oSound.useEQData) {
  432. if (areSoundsInaccessible == false) {
  433. try {
  434. oSound.getEQData();
  435. } catch(e: Error) {
  436. writeDebug('getEQData() warning: ' + e.toString());
  437. newDataError = true;
  438. dataErrors.push(e.toString());
  439. oSound.handledDataError = true;
  440. }
  441. } else if (oSound.handledDataError != true && oSound.ignoreDataError != true) {
  442. try {
  443. oSound.getEQData();
  444. } catch(e: Error) {
  445. // writeDebug('computeSpectrum() (EQ data) '+e.toString());
  446. // oSound.useEQData = false;
  447. newDataError = true;
  448. dataErrors.push(e.toString());
  449. oSound.handledDataError = true;
  450. }
  451. }
  452. }
  453. if (oSound.waveformDataArray != oSound.lastValues.waveformDataArray) {
  454. oSound.lastValues.waveformDataArray = oSound.waveformDataArray;
  455. newWaveformData = true;
  456. }
  457. if (oSound.eqDataArray != oSound.lastValues.eqDataArray) {
  458. oSound.lastValues.eqDataArray = oSound.eqDataArray;
  459. newEQData = true;
  460. }
  461. }
  462. if (newDataError) {
  463. sMethod = baseJSObject + "['" + sounds[i] + "']._ondataerror";
  464. var errors:String = dataErrors.join('<br>\n');
  465. ExternalInterface.call(sMethod, 'data unavailable: ' + errors);
  466. }
  467. // special case: Netstream may try to fire whileplaying() after finishing. check that stop hasn't fired.
  468. isPlaying = (!oSound.useNetstream || (oSound.useNetstream && oSound.lastNetStatus != "NetStream.Play.Stop")); // don't update if stream has ended
  469. if (typeof nP != 'undefined' && hasNew && isPlaying) { // and IF VIDEO, is still playing?
  470. // oSound.lastValues.position = nP;
  471. sMethod = baseJSObject + "['" + sounds[i] + "']._whileplaying";
  472. var waveDataLeft:String = (newWaveformData ? oSound.waveformDataArray.slice(0, 256).join(',') : null);
  473. var waveDataRight:String = (newWaveformData ? oSound.waveformDataArray.slice(256).join(',') : null);
  474. var eqDataLeft:String = (newEQData ? oSound.eqDataArray.slice(0, 256).join(',') : null);
  475. var eqDataRight:String = (newEQData ? oSound.eqDataArray.slice(256).join(',') : null);
  476. ExternalInterface.call(sMethod, nP, (newPeakData ? {
  477. leftPeak: lP,
  478. rightPeak: rP
  479. } : null), waveDataLeft, waveDataRight, (newEQData ? {
  480. leftEQ: eqDataLeft,
  481. rightEQ: eqDataRight
  482. } : null));
  483. // if position changed, check for near-end
  484. if (oSound.didJustBeforeFinish != true && oSound.loaded == true && oSound.justBeforeFinishOffset > 0 && nD - nP <= oSound.justBeforeFinishOffset) {
  485. // fully-loaded, near end and haven't done this yet..
  486. sMethod = baseJSObject + "['" + sounds[i] + "']._onjustbeforefinish";
  487. ExternalInterface.call(sMethod, (nD - nP));
  488. oSound.didJustBeforeFinish = true;
  489. }
  490. }
  491. // check isBuffering
  492. if (!oSound.useNetstream && oSound.isBuffering != oSound.lastValues.isBuffering) {
  493. // property has changed
  494. oSound.lastValues.isBuffering = oSound.isBuffering;
  495. sMethod = baseJSObject + "['" + sounds[i] + "']._onbufferchange";
  496. ExternalInterface.call(sMethod, oSound.isBuffering ? 1 : 0);
  497. }
  498. }
  499. }
  500. public function onLoadError(oSound:Object) : void {
  501. // something went wrong. 404, bad format etc.
  502. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onload", 0);
  503. }
  504. public function onLoad(e: Event) : void {
  505. checkProgress(); // ensure progress stats are up-to-date
  506. var oSound:Object = e.target;
  507. if (!oSound.useNetstream) { // FLV must also have metadata
  508. oSound.loaded = true;
  509. // force duration update (doesn't seem to be always accurate)
  510. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._whileloading", oSound.bytesLoaded, oSound.bytesTotal, oSound.length || oSound.duration);
  511. // TODO: Determine if loaded or failed - bSuccess?
  512. // ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._onload",bSuccess?1:0);
  513. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onload", 1);
  514. }
  515. }
  516. public function onID3(e: Event) : void {
  517. // --- NOTE: BUGGY (Flash 8 only? Haven't really checked 9 + 10.) ---
  518. // TODO: Investigate holes in ID3 parsing - for some reason, Album will be populated with Date if empty and date is provided. (?)
  519. // ID3V1 seem to parse OK, but "holes" / blanks in ID3V2 data seem to get messed up (eg. missing album gets filled with date.)
  520. // iTunes issues: onID3 was not called with a test MP3 encoded with iTunes 7.01, and what appeared to be valid ID3V2 data.
  521. // May be related to thumbnails for album art included in MP3 file by iTunes. See http://mabblog.com/blog/?p=33
  522. try {
  523. var oSound:Object = e.target;
  524. var id3Data:Array = [];
  525. var id3Props:Array = [];
  526. for (var prop:String in oSound.id3) {
  527. id3Props.push(prop);
  528. id3Data.push(oSound.id3[prop]);
  529. // writeDebug('id3['+prop+']: '+oSound.id3[prop]);
  530. }
  531. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onid3", id3Props, id3Data);
  532. // unhook own event handler, prevent second call (can fire twice as data is received - ID3V2 at beginning, ID3V1 at end.)
  533. // Therefore if ID3V2 data is received, ID3V1 is ignored.
  534. // soundObjects[oSound.sID].onID3 = null;
  535. } catch(e: Error) {
  536. writeDebug('onID3(): Unable to get ID3 info for ' + oSound.sID + '.');
  537. }
  538. oSound.removeEventListener(Event.ID3, onID3);
  539. }
  540. public function registerOnComplete(sID:String) : void {
  541. var oSound: SoundManager2_SMSound_AS3 = soundObjects[sID];
  542. if (oSound && oSound.soundChannel) {
  543. oSound.soundChannel.addEventListener(Event.SOUND_COMPLETE, function () : void {
  544. if (oSound) {
  545. oSound.didJustBeforeFinish = false; // reset
  546. checkProgress();
  547. try {
  548. oSound.ignoreDataError = true; // workaround: avoid data error handling for this manual step..
  549. oSound.start(0, 1); // go back to 0
  550. oSound.soundChannel.stop();
  551. } catch(e: Error) {
  552. writeDebug('Could not set position on ' + sID + ': ' + e.toString());
  553. }
  554. oSound.ignoreDataError = false; // ..and reset
  555. oSound.handledDataError = false; // reset this flag
  556. }
  557. // checkProgress();
  558. ExternalInterface.call(baseJSObject + "['" + sID + "']._onfinish");
  559. });
  560. }
  561. }
  562. public function doSecurityError(oSound: SoundManager2_SMSound_AS3, e: SecurityErrorEvent) : void {
  563. writeDebug('securityError: ' + e.text);
  564. // when this happens, you don't have security rights on the server containing the FLV file
  565. // a crossdomain.xml file would fix the problem easily
  566. }
  567. public function doIOError(oSound: SoundManager2_SMSound_AS3, e: IOErrorEvent) : void {
  568. // writeDebug('ioError: '+e.text);
  569. // call checkProgress()?
  570. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onload", 0); // call onload, assume it failed.
  571. // there was a connection drop, a loss of internet connection, or something else wrong. 404 error too.
  572. }
  573. public function doAsyncError(oSound: SoundManager2_SMSound_AS3, e: AsyncErrorEvent) : void {
  574. writeDebug('asyncError: ' + e.text);
  575. // this is more related to streaming server from my experience, but you never know
  576. }
  577. public function doNetStatus(oSound: SoundManager2_SMSound_AS3, e: NetStatusEvent) : void {
  578. // this will eventually let us know what is going on.. is the stream loading, empty, full, stopped?
  579. oSound.lastNetStatus = e.info.code;
  580. if (e.info.code != "NetStream.Buffer.Full" && e.info.code != "NetStream.Buffer.Empty" && e.info.code != "NetStream.Seek.Notify") {
  581. writeDebug('netStatusEvent: ' + e.info.code);
  582. }
  583. // When streaming, Stop is called when buffering stops, not when the stream is actually finished.
  584. // @see http://www.actionscript.org/forums/archive/index.php3/t-159194.html
  585. if (e.info.code == "NetStream.Play.Stop") { // && !oSound.didFinish && oSound.loaded == true && nD == nP
  586. writeDebug('NetStream.Play.Stop');
  587. // if (!oSound.useNetstream) {
  588. // finished playing
  589. // oSound.didFinish = true; // will be reset via JS callback
  590. oSound.didJustBeforeFinish = false; // reset
  591. writeDebug('calling onfinish for a sound');
  592. // reset the sound? Move back to position 0?
  593. checkProgress();
  594. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onfinish");
  595. // and exit full-screen mode, too?
  596. stage.displayState = StageDisplayState.NORMAL;
  597. } else if (e.info.code == "NetStream.Play.FileStructureInvalid" || e.info.code == "NetStream.Play.FileStructureInvalid" || e.info.code == "NetStream.Play.StreamNotFound") {
  598. writeDebug('NetStream load error: '+e.info.code);
  599. this.onLoadError(oSound);
  600. } else if (e.info.code == "NetStream.Play.Start" || e.info.code == "NetStream.Buffer.Empty" || e.info.code == "NetStream.Buffer.Full") {
  601. // RTMP case..
  602. // We wait for the buffer to fill up before pausing the just-loaded song because only if the
  603. // buffer is full will the song continue to buffer until the user hits play.
  604. if (oSound.serverUrl && e.info.code == "NetStream.Buffer.Full" && oSound.pauseOnBufferFull) {
  605. oSound.ns.pause();
  606. oSound.paused = true;
  607. oSound.pauseOnBufferFull = false;
  608. // Call pause in JS. This will call back to us to pause again, but
  609. // that should be harmless.
  610. writeDebug('Pausing song because buffer is now full.');
  611. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "'].pause", false);
  612. }
  613. // Increase the size of the buffer
  614. if (e.info.code == "NetStream.Buffer.Full") {
  615. if (oSound.ns.bufferTime == oSound.bufferTime) {
  616. oSound.ns.bufferTime = 15;
  617. writeDebug('increasing buffer to 15 secs');
  618. }/* else if (oSound.ns.bufferTime == 15) {
  619. oSound.ns.bufferTime = 30;
  620. writeDebug('increasing buffer to 30 secs');
  621. }*/
  622. }
  623. var isNetstreamBuffering: Boolean = (e.info.code == "NetStream.Buffer.Empty" || e.info.code == "NetStream.Play.Start");
  624. // assume buffering when we start playing, eg. initial load.
  625. if (isNetstreamBuffering != oSound.lastValues.isBuffering) {
  626. oSound.lastValues.isBuffering = isNetstreamBuffering;
  627. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onbufferchange", oSound.lastValues.isBuffering ? 1 : 0);
  628. }
  629. // We can detect the end of the stream when Play.Stop is called followed by Buffer.Empty.
  630. // However, if you pause and let the whole song buffer, Buffer.Flush is called followed by
  631. // Buffer.Empty, so handle that case too.
  632. if (e.info.code == "NetStream.Buffer.Empty" && (oSound.lastNetStatus == 'NetStream.Play.Stop' || oSound.lastNetStatus == 'NetStream.Buffer.Flush')) {
  633. //writeDebug('Buffer empty and last net status was Play.Stop or Buffer.Flush. This must be the end!');
  634. oSound.didJustBeforeFinish = false; // reset
  635. oSound.finished = true;
  636. writeDebug('calling onfinish for sound '+oSound.sID);
  637. checkProgress();
  638. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onfinish");
  639. } else if (e.info.code == "NetStream.Buffer.Empty" && oSound.ns.bufferTime != oSound.bufferTime) {
  640. oSound.ns.bufferTime = oSound.bufferTime;
  641. writeDebug('setting buffer to '+oSound.ns.bufferTime+' secs');
  642. }
  643. // Recover from failures
  644. } else if (e.info.code == "NetConnection.Connect.Closed"
  645. || e.info.code == "NetStream.Failed"
  646. || e.info.code == "NetStream.Play.FileStructureInvalid"
  647. || e.info.code == "NetStream.Play.StreamNotFound") {
  648. if (oSound.failed) {
  649. writeDebug('doNetStatus: ignoring, already reported failure.');
  650. } else {
  651. oSound.failed = true;
  652. ExternalInterface.call(baseJSObject + "['" + oSound.sID + "']._onfailure");
  653. }
  654. }
  655. oSound.lastNetStatus = e.info.code;
  656. }
  657. public function addNetstreamEvents(oSound: SoundManager2_SMSound_AS3) : void {
  658. oSound.ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, function (e: AsyncErrorEvent) : void {
  659. doAsyncError(oSound, e)
  660. });
  661. oSound.ns.addEventListener(NetStatusEvent.NET_STATUS, function (e: NetStatusEvent) : void {
  662. doNetStatus(oSound, e)
  663. });
  664. oSound.ns.addEventListener(IOErrorEvent.IO_ERROR, function (e: IOErrorEvent) : void {
  665. doIOError(oSound, e)
  666. });
  667. }
  668. public function removeNetstreamEvents(oSound: SoundManager2_SMSound_AS3) : void {
  669. // for the record, I'm sure this is completely wrong. ;)
  670. oSound.ns.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, function (e: AsyncErrorEvent) : void {
  671. doAsyncError(oSound, e)
  672. });
  673. oSound.ns.removeEventListener(NetStatusEvent.NET_STATUS, function (e: NetStatusEvent) : void {
  674. doNetStatus(oSound, e)
  675. });
  676. oSound.ns.removeEventListener(IOErrorEvent.IO_ERROR, function (e: IOErrorEvent) : void {
  677. doIOError(oSound, e)
  678. });
  679. }
  680. public function _setPosition(sID:String, nSecOffset:Number, isPaused: Boolean) : void {
  681. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  682. if (!s) return void;
  683. // writeDebug('_setPosition()');
  684. // don't allow seek past loaded duration. (Will stop + fail.)
  685. if (s.useVideo && nSecOffset > s.duration*1000) {
  686. writeDebug('setPosition: Cannot seek past current duration of '+s.duration+', using this value');
  687. nSecOffset = s.duration*1000;
  688. }
  689. // stop current channel, start new one.
  690. if (s.lastValues) {
  691. s.lastValues.position = nSecOffset; // s.soundChannel.position;
  692. }
  693. if (s.useNetstream) {
  694. // Minimize the buffer so playback starts ASAP
  695. s.ns.bufferTime = s.bufferTime;
  696. writeDebug('setPosition: setting buffer to '+s.ns.bufferTime+' secs');
  697. nSecOffset = nSecOffset > 0 ? nSecOffset / 1000 : 0;
  698. // writeDebug('setPosition: ' + nSecOffset/(!s.useVideo?1000:1));
  699. writeDebug('setPosition: ' + nSecOffset);
  700. s.ns.seek(nSecOffset);
  701. checkProgress(); // force UI update
  702. } else {
  703. if (s.soundChannel) {
  704. s.soundChannel.stop();
  705. }
  706. writeDebug('setPosition: ' + nSecOffset); // +', '+(s.lastValues.loops?s.lastValues.loops:1));
  707. if (s.lastValues.loops > 1 && nSecOffset != 0) {
  708. writeDebug('Warning: Looping functionality being disabled due to Flash limitation.');
  709. s.lastValues.loops = 1;
  710. }
  711. try {
  712. s.start(nSecOffset, s.lastValues.loops || 1); // start playing at new position
  713. } catch(e: Error) {
  714. writeDebug('Warning: Could not set position on ' + sID + ': ' + e.toString());
  715. }
  716. checkProgress(); // force UI update
  717. try {
  718. registerOnComplete(sID);
  719. } catch(e: Error) {
  720. writeDebug('_setPosition(): Could not register onComplete');
  721. }
  722. if (isPaused && s.soundChannel) {
  723. // writeDebug('_setPosition: stopping (paused) sound');
  724. // writeDebug('last position: '+s.lastValues.position+' vs '+s.soundChannel.position);
  725. s.soundChannel.stop();
  726. }
  727. }
  728. }
  729. public function _load(sID:String, sURL:String, bStream: Boolean, bAutoPlay: Boolean, nLoops:Number) : void {
  730. // writeDebug('_load()');
  731. if (typeof bAutoPlay == 'undefined') bAutoPlay = false;
  732. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  733. if (!s) return void;
  734. var didRecreate: Boolean = false;
  735. if (s.didLoad == true) {
  736. // need to recreate sound
  737. didRecreate = true;
  738. writeDebug('recreating sound ' + sID + ' in order to load ' + sURL);
  739. var ns:Object = new Object();
  740. ns.sID = s.sID;
  741. ns.loops = nLoops||1;
  742. ns.justBeforeFinishOffset = s.justBeforeFinishOffset;
  743. ns.usePeakData = s.usePeakData;
  744. ns.useWaveformData = s.useWaveformData;
  745. ns.useEQData = s.useEQData;
  746. ns.useNetstream = s.useNetstream;
  747. ns.useVideo = s.useVideo;
  748. ns.bufferTime = s.bufferTime;
  749. ns.serverUrl = s.serverUrl;
  750. ns.duration = s.duration;
  751. ns.totalBytes = s.totalBytes;
  752. ns.useEvents = true;
  753. _destroySound(s.sID);
  754. _createSound(ns.sID, sURL, ns.justBeforeFinishOffset, ns.usePeakData, ns.useWaveformData, ns.useEQData, ns.useNetstream, ns.useVideo, ns.bufferTime, ns.loops, ns.serverUrl, ns.duration, ns.totalBytes, bAutoPlay, ns.useEvents);
  755. s = soundObjects[sID];
  756. // writeDebug('Sound object replaced');
  757. }
  758. checkProgress();
  759. if (!s.didLoad) {
  760. try {
  761. s.addEventListener(Event.ID3, onID3);
  762. s.addEventListener(Event.COMPLETE, onLoad);
  763. } catch(e: Error) {
  764. writeDebug('_load(): could not assign ID3/complete event handlers');
  765. }
  766. }
  767. // s.addEventListener(ProgressEvent.PROGRESS, checkLoadProgress); // May be called often, potential CPU drain
  768. // s.addEventListener(Event.FINISH, onFinish);
  769. // s.loaded = true; // TODO: Investigate - Flash 9 non-FLV bug??
  770. // s.didLoad = true; // TODO: Investigate - bug?
  771. // if (didRecreate || s.sURL != sURL) {
  772. // don't try to load if same request already made
  773. s.sURL = sURL;
  774. if (s.useNetstream) {
  775. try {
  776. // s.ns.close();
  777. s.useEvents = true;
  778. if (s.ns) {
  779. this.addNetstreamEvents(s);
  780. ExternalInterface.call(baseJSObject + "['" + s.sID + "']._whileloading", s.ns.bytesLoaded, s.ns.bytesTotal || s.totalBytes, int(s.duration || 0));
  781. s.ns.play(sURL);
  782. if (!bAutoPlay) {
  783. s.ns.pause();
  784. }
  785. } else {
  786. writeDebug('_load(): Note: No netStream found.'+(!s.connected?' (Not connected yet.)':''));
  787. }
  788. } catch(e: Error) {
  789. writeDebug('_load(): error: ' + e.toString());
  790. }
  791. } else {
  792. try {
  793. s.addEventListener(IOErrorEvent.IO_ERROR, function (e: IOErrorEvent) : void {
  794. doIOError(s, e)
  795. });
  796. s.loadSound(sURL, bStream);
  797. } catch(e: Error) {
  798. // oh well
  799. writeDebug('_load: Error loading ' + sURL + '. Flash error detail: ' + e.toString());
  800. }
  801. }
  802. s.didJustBeforeFinish = false;
  803. }
  804. public function _unload(sID:String) : void {
  805. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  806. if (!s) return void;
  807. var sURL:String = s.sURL; // save existing sound URL for object recreation
  808. try {
  809. removeEventListener(Event.ID3, onID3);
  810. removeEventListener(Event.COMPLETE, onLoad);
  811. } catch(e: Error) {
  812. writeDebug('_unload() warn: Could not remove ID3/complete events');
  813. }
  814. s.paused = false;
  815. if (s.soundChannel) {
  816. s.soundChannel.stop();
  817. }
  818. try {
  819. if (s.didLoad && !s.loaded && !s.useNetstream) {
  820. s.close(); // close stream only if still loading?
  821. }
  822. } catch(e: Error) {
  823. // stream may already have closed if sound loaded, etc.
  824. writeDebug(sID + '._unload(): Note: Unable to close stream: ' + e.toString());
  825. // oh well
  826. }
  827. // destroy and recreate Flash sound object, try to reclaim memory
  828. // writeDebug('sound._unload(): recreating sound '+sID+' to free memory');
  829. if (s.useNetstream) {
  830. // writeDebug('_unload(): closing netStream stuff');
  831. try {
  832. this.removeNetstreamEvents(s);
  833. s.ns.close();
  834. s.nc.close();
  835. // s.nc = null;
  836. // s.ns = null;
  837. } catch(e: Error) {
  838. // oh well
  839. writeDebug('_unload(): caught exception during netConnection/netStream close');
  840. }
  841. if (s.useVideo) {
  842. writeDebug('_unload(): clearing video');
  843. s.oVideo.clear();
  844. // s.oVideo = null;
  845. }
  846. }
  847. var ns:Object = new Object();
  848. ns.sID = s.sID;
  849. ns.loops = s.loops;
  850. ns.justBeforeFinishOffset = s.justBeforeFinishOffset;
  851. ns.usePeakData = s.usePeakData;
  852. ns.useWaveformData = s.useWaveformData;
  853. ns.useEQData = s.useEQData;
  854. ns.useNetstream = s.useNetstream;
  855. ns.useVideo = s.useVideo;
  856. ns.bufferTime = s.bufferTime;
  857. ns.serverUrl = s.serverUrl;
  858. ns.duration = s.duration;
  859. ns.totalBytes = s.totalBytes;
  860. ns.autoPlay = s.autoPlay;
  861. _destroySound(s.sID);
  862. _createSound(ns.sID, sURL, ns.justBeforeFinishOffset, ns.usePeakData, ns.useWaveformData, ns.useEQData, ns.useNetstream, ns.useVideo, ns.bufferTime, ns.loops, ns.serverUrl, ns.duration, ns.totalBytes, ns.autoPlay, false); // false: don't allow events just yet
  863. soundObjects[sID].connected = true; // fake it?
  864. writeDebug(s.sID + '.unload(): ok');
  865. }
  866. public function _createSound(sID:String, sURL:String, justBeforeFinishOffset: int, usePeakData: Boolean, useWaveformData: Boolean, useEQData: Boolean, useNetstream: Boolean, useVideo: Boolean, bufferTime:Number, loops:Number, serverUrl:String, duration:Number, totalBytes:Number, autoPlay:Boolean, useEvents:Boolean) : void {
  867. soundObjects[sID] = new SoundManager2_SMSound_AS3(this, sID, sURL, usePeakData, useWaveformData, useEQData, useNetstream, useVideo, bufferTime, serverUrl, duration, totalBytes, autoPlay, useEvents);
  868. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  869. if (!s) return void;
  870. this.currentObject = s;
  871. // s.setVolume(100);
  872. s.didJustBeforeFinish = false;
  873. s.sID = sID;
  874. s.sURL = sURL;
  875. s.paused = false;
  876. s.loaded = false;
  877. s.justBeforeFinishOffset = justBeforeFinishOffset || 0;
  878. s.lastValues = {
  879. bytes: 0,
  880. position: 0,
  881. loops: loops||1,
  882. leftPeak: 0,
  883. rightPeak: 0,
  884. bufferLength: 0
  885. };
  886. if (! (sID in sounds)) sounds.push(sID);
  887. // sounds.push(sID);
  888. }
  889. public function _destroySound(sID:String) : void {
  890. // for the power of garbage collection! .. er, Greyskull!
  891. var s: SoundManager2_SMSound_AS3 = (soundObjects[sID] || null);
  892. if (!s) return void;
  893. // try to unload the sound
  894. for (var i: int = 0, j: int = sounds.length; i < j; i++) {
  895. if (sounds[i] == s) {
  896. sounds.splice(i, 1);
  897. continue;
  898. }
  899. }
  900. if (s.soundChannel) {
  901. s.soundChannel.stop();
  902. }
  903. this.stage.removeEventListener(Event.RESIZE, s.resizeHandler);
  904. // if is a movie, remove that as well.
  905. if (s.useNetstream) {
  906. // s.nc.client = null;
  907. try {
  908. this.removeNetstreamEvents(s);
  909. // s.nc.removeEventListener(NetStatusEvent.NET_STATUS, s.doNetStatus);
  910. } catch(e: Error) {
  911. writeDebug('_destroySound(): Events already removed from netStream/netConnection?');
  912. }
  913. if (s.useVideo) {
  914. try {
  915. this.removeChild(s.oVideo);
  916. } catch(e: Error) {
  917. writeDebug('_destoySound(): could not remove video?');
  918. }
  919. }
  920. if (s.didLoad) {
  921. // TODO: figure out if stream is still open first, can't close an already-closed stream.
  922. try {
  923. s.ns.close();
  924. s.nc.close();
  925. } catch(e: Error) {
  926. // oh well
  927. writeDebug('_destroySound(): caught exception: '+e.toString());
  928. }
  929. }
  930. } else if (s.didLoad) {
  931. // non-netstream case
  932. try {
  933. s.close(); // close stream only if still loading?
  934. } catch(e: Error) {
  935. // oh well
  936. }
  937. }
  938. s = null;
  939. soundObjects[sID] = null;
  940. delete soundObjects[sID];
  941. }
  942. public function _stop(sID:String, bStopAll: Boolean) : void {
  943. // stop this particular instance (or "all", based on parameter)
  944. if (bStopAll) {
  945. SoundMixer.stopAll();
  946. } else {
  947. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  948. if (!s) return void;
  949. if (s.useNetstream && s.ns) {
  950. s.ns.pause();
  951. if (s.oVideo) {
  952. s.oVideo.visible = false;
  953. }
  954. } else if (s.soundChannel) {
  955. s.soundChannel.stop();
  956. }
  957. s.paused = false;
  958. s.didJustBeforeFinish = false;
  959. }
  960. }
  961. public function _start(sID:String, nLoops: int, nMsecOffset: int) : void {
  962. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  963. if (!s) return void;
  964. writeDebug('start: ' + nMsecOffset+(nLoops?', loops: '+nLoops:''));
  965. s.lastValues.paused = false; // reset pause if applicable
  966. s.lastValues.loops = (nLoops || 1);
  967. s.lastValues.position = nMsecOffset;
  968. s.handledDataError = false; // reset this flag
  969. try {
  970. s.start(nMsecOffset, nLoops);
  971. } catch(e: Error) {
  972. writeDebug('Could not start ' + sID + ': ' + e.toString());
  973. }
  974. try {
  975. registerOnComplete(sID);
  976. } catch(e: Error) {
  977. writeDebug('_start(): registerOnComplete failed');
  978. }
  979. }
  980. public function _pause(sID:String) : void {
  981. // writeDebug('_pause()');
  982. var s: SoundManager2_SMSound_AS3 = soundObjects[sID];
  983. if (!s) return void;
  984. // writeDebug('s.paused: '+s.paused);
  985. if (!s.paused) {
  986. // reference current position, stop sound
  987. s.paused = true;
  988. // writeDebug('_pause(): position: '+s.lastValues.position);
  989. if (s.useNetstream) {
  990. if (s.ns) {
  991. s.lastValues.position = s.ns.time;
  992. s.ns.pause();
  993. }
  994. } else {
  995. if (s.soundChannel) {
  996. s.lastValues.position = s.soundChannel.position;
  997. s.soundChannel.stop();
  998. }
  999. }
  1000. } else {
  1001. // resume playing from last position
  1002. // writeDebug('resuming - playing at '+s.lastValues.position+', '+s.lastValues.loops+' times');
  1003. s.paused = false;
  1004. if (s.useNetstream) {
  1005. s.ns.resume();
  1006. } else {
  1007. s.start(s.lastValues.position, s.lastValues.loops);
  1008. }
  1009. try {
  1010. registerOnComplete(sID);
  1011. } catch(e: Error) {
  1012. writeDebug('_pause(): registerOnComplete() failed');
  1013. }
  1014. }
  1015. }
  1016. public function _setPan(sID:String, nPan:Number) : void {
  1017. soundObjects[sID].setPan(nPan);
  1018. }
  1019. public function _setVolume(sID:String, nVol:Number) : void {
  1020. // writeDebug('_setVolume: '+nVol);
  1021. soundObjects[sID].setVolume(nVol);
  1022. }
  1023. public function _setPolling(bPolling: Boolean = false, bUseHighPerformanceTimer: Boolean = false) : void {
  1024. pollingEnabled = bPolling;
  1025. if (timer == null && pollingEnabled) {
  1026. var nTimerInterval: uint = (bUseHighPerformanceTimer ? timerIntervalHighPerformance : timerInterval);
  1027. writeDebug('Enabling polling, ' + nTimerInterval + ' ms interval');
  1028. timer = new Timer(nTimerInterval, 0);
  1029. timer.addEventListener(TimerEvent.TIMER, function () : void {
  1030. checkProgress();
  1031. }); // direct reference eg. checkProgress doesn't work? .. odd.
  1032. timer.start();
  1033. } else if (timer && !pollingEnabled) {
  1034. writeDebug('Disabling polling');
  1035. // flash.utils.clearInterval(timer);
  1036. timer.reset();
  1037. }
  1038. }
  1039. public function _getMemoryUse() : String {
  1040. return System.totalMemory.toString();
  1041. }
  1042. // XML handler stuff
  1043. public function _loadFromXML(sURL:String) : void {
  1044. var loader: URLLoader = new URLLoader();
  1045. loader.addEventListener(Event.COMPLETE, parseXML);
  1046. writeDebug('Attempting to load XML: ' + sURL);
  1047. try {
  1048. loader.load(new URLRequest(sURL));
  1049. } catch(e: Error) {
  1050. writeDebug('Error loading XML: ' + e.toString());
  1051. }
  1052. }
  1053. public function parseXML(e: Event) : void {
  1054. try {
  1055. var oXML: XMLDocument = new XMLDocument();
  1056. oXML.ignoreWhite = true;
  1057. oXML.parseXML(e.target.data);
  1058. var xmlRoot: XMLNode = oXML.firstChild;
  1059. var xmlAttr:Object = xmlRoot.attributes;
  1060. var oOptions:Object = {};
  1061. var i: int = 0;
  1062. var j: int = 0;
  1063. for (i = 0, j = xmlRoot.childNodes.length; i < j; i++) {
  1064. xmlAttr = xmlRoot.childNodes[i].attributes;
  1065. oOptions = {
  1066. id: xmlAttr.id,
  1067. url: xmlRoot.attributes.baseHref + xmlAttr.href,
  1068. stream: xmlAttr.stream
  1069. }
  1070. ExternalInterface.call(baseJSController + ".createSound", oOptions);
  1071. }
  1072. } catch(e: Error) {
  1073. writeDebug('Error parsing XML: ' + e.toString());
  1074. }
  1075. }
  1076. // -----------------------------------
  1077. // end methods
  1078. }
  1079. // package
  1080. }