PageRenderTime 54ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

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

http://xbat-devel.googlecode.com/
ActionScript | 765 lines | 582 code | 65 blank | 118 comment | 136 complexity | 55d37f224243fc2dc33c0d80eec944d6 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) 2008, Scott Schiller. All rights reserved.
  6. Code licensed under the BSD License:
  7. http://www.schillmania.com/projects/soundmanager2/license.txt
  8. V2.93a.20090117
  9. Flash 9 / ActionScript 3 version
  10. */
  11. package {
  12. import flash.system.*;
  13. import flash.events.*;
  14. import flash.display.Sprite;
  15. import flash.display.StageAlign;
  16. import flash.display.StageScaleMode;
  17. import flash.media.Sound;
  18. import flash.media.SoundChannel;
  19. import flash.media.SoundMixer;
  20. import flash.utils.setInterval;
  21. import flash.utils.clearInterval;
  22. import flash.utils.Dictionary;
  23. import flash.utils.Timer;
  24. import flash.net.URLLoader;
  25. import flash.net.URLRequest;
  26. import flash.xml.*;
  27. import flash.external.ExternalInterface; // woo
  28. public class SoundManager2_AS3 extends Sprite {
  29. // Cross-domain security exception stuffs
  30. // HTML on foo.com loading .swf hosted on bar.com? Define your "HTML domain" here to allow JS+Flash communication to work.
  31. // See http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/Security.html#allowDomain()
  32. // Security.allowDomain("foo.com");
  33. // externalInterface references (for Javascript callbacks)
  34. public var baseJSController:String = "soundManager";
  35. public var baseJSObject:String = baseJSController+".sounds";
  36. // internal objects
  37. public var sounds:Array = []; // indexed string array
  38. public var soundObjects:Dictionary = new Dictionary(); // associative Sound() object Dictionary type
  39. public var timerInterval:uint = 20;
  40. public var timer:Timer = null;
  41. public var pollingEnabled:Boolean = false; // polling (timer) flag - disabled by default, enabled by JS->Flash call
  42. public var debugEnabled:Boolean = true; // Flash debug output enabled by default, disabled by JS call
  43. public var loaded:Boolean = false;
  44. public function SoundManager2_AS3() {
  45. stage.scaleMode = StageScaleMode.NO_SCALE; // SHOW_ALL vs. NO_SCALE vs. EXACT_FIT
  46. stage.align = StageAlign.TOP_LEFT;
  47. ExternalInterface.addCallback('_load', _load);
  48. ExternalInterface.addCallback('_unload', _unload);
  49. ExternalInterface.addCallback('_stop', _stop);
  50. ExternalInterface.addCallback('_start', _start);
  51. ExternalInterface.addCallback('_pause', _pause);
  52. ExternalInterface.addCallback('_setPosition', _setPosition);
  53. ExternalInterface.addCallback('_setPan', _setPan);
  54. ExternalInterface.addCallback('_setVolume', _setVolume);
  55. ExternalInterface.addCallback('_setPolling', _setPolling);
  56. ExternalInterface.addCallback('_externalInterfaceTest', _externalInterfaceTest);
  57. ExternalInterface.addCallback('_disableDebug', _disableDebug);
  58. ExternalInterface.addCallback('_getMemoryUse', _getMemoryUse);
  59. ExternalInterface.addCallback('_loadFromXML', _loadFromXML);
  60. ExternalInterface.addCallback('_createSound', _createSound);
  61. ExternalInterface.addCallback('_destroySound', _destroySound);
  62. // call after delay, to be safe (ensure callbacks are registered by the time JS is called below)
  63. var timer:Timer = new Timer(20,0);
  64. timer.addEventListener(TimerEvent.TIMER, function():void {
  65. _externalInterfaceTest(true);
  66. timer.reset();
  67. });
  68. timer.start();
  69. // delayed, see above
  70. // _externalInterfaceTest(true);
  71. } // SoundManager2()
  72. // methods
  73. // -----------------------------------
  74. public function writeDebug(s:String,bTimestamp:Boolean=false):Boolean {
  75. if (!debugEnabled) return false;
  76. ExternalInterface.call(baseJSController+"['_writeDebug']","(Flash): "+s,null,bTimestamp);
  77. return true;
  78. }
  79. public function _externalInterfaceTest(isFirstCall:Boolean):Boolean {
  80. if (isFirstCall == true) {
  81. writeDebug('Flash to JS OK');
  82. ExternalInterface.call(baseJSController+"._externalInterfaceOK");
  83. } else {
  84. writeDebug('_externalInterfaceTest(): JS to/from Flash OK');
  85. var sandboxType:String = flash.system.Security['sandboxType'];
  86. ExternalInterface.call(baseJSController+"._setSandboxType",sandboxType);
  87. }
  88. return true; // to verify that a call from JS to here, works. (eg. JS receives "true", thus OK.)
  89. }
  90. public function _disableDebug():void {
  91. // prevent future debug calls from Flash going to client (maybe improve performance)
  92. writeDebug('_disableDebug()');
  93. debugEnabled = false;
  94. }
  95. public function checkLoadProgress(e:Event):void {
  96. try {
  97. var oSound:Object = e.target;
  98. var bL:int = oSound.bytesLoaded;
  99. var bT:int = oSound.bytesTotal;
  100. var nD:int = oSound.length||oSound.duration||0;
  101. var sMethod:String = baseJSObject+"['"+oSound.sID+"']._whileloading";
  102. ExternalInterface.call(sMethod,bL,bT,nD);
  103. if (bL && bT && bL != oSound.lastValues.bytes) {
  104. oSound.lastValues.bytes = bL;
  105. ExternalInterface.call(sMethod,bL,bT,nD);
  106. }
  107. } catch(e:Error) {
  108. writeDebug('checkLoadProgress(): '+e.toString());
  109. }
  110. }
  111. public function checkProgress():void {
  112. var bL:int = 0;
  113. var bT:int = 0;
  114. var nD:int = 0;
  115. var nP:int = 0;
  116. var lP:Number = 0;
  117. var rP:Number = 0;
  118. var oSound:SoundManager2_SMSound_AS3 = null;
  119. var oSoundChannel:flash.media.SoundChannel = null;
  120. var sMethod:String = null;
  121. var newPeakData:Boolean = false;
  122. var newWaveformData:Boolean = false;
  123. var newEQData:Boolean = false;
  124. for (var i:int=0,j:int=sounds.length; i<j; i++) {
  125. oSound = soundObjects[sounds[i]];
  126. sMethod = baseJSObject+"['"+sounds[i]+"']._whileloading";
  127. if (!oSound) continue; // if sounds are destructed within event handlers while this loop is running, may be null
  128. if (oSound.useNetstream) {
  129. bL = oSound.ns.bytesLoaded;
  130. bT = oSound.ns.bytesTotal;
  131. nD = int(oSound.duration||0); // can sometimes be null with short MP3s? Wack.
  132. nP = oSound.ns.time*1000;
  133. if (oSound.loaded != true && nD > 0 && bL == bT) {
  134. // non-MP3 has loaded
  135. // writeDebug('ns: time/duration/bytesloaded,total: '+(oSound.ns.time*1000)+', '+oSound.duration+', '+oSound.ns.bytesLoaded+'/'+oSound.ns.bytesTotal);
  136. oSound.loaded = true;
  137. try {
  138. ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._whileloading",oSound.ns.bytesLoaded,oSound.ns.bytesTotal,nD);
  139. ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._onload",oSound.duration>0?1:0);
  140. } catch(e:Error) {
  141. writeDebug('_whileLoading/_onload error: '+e.toString());
  142. }
  143. } else if (!oSound.loaded && bL && bT && bL != oSound.lastValues.bytes) {
  144. oSound.lastValues.bytes = bL;
  145. ExternalInterface.call(sMethod,bL,bT,nD);
  146. }
  147. } else {
  148. oSoundChannel = oSound.soundChannel;
  149. bL = oSound.bytesLoaded;
  150. bT = oSound.bytesTotal;
  151. nD = int(oSound.length||0); // can sometimes be null with short MP3s? Wack.
  152. // writeDebug('loaded/total/duration: '+bL+', '+bT+', '+nD);
  153. if (oSoundChannel) {
  154. nP = (oSoundChannel.position||0);
  155. if (oSound.usePeakData) {
  156. lP = int((oSoundChannel.leftPeak)*1000)/1000;
  157. rP = int((oSoundChannel.rightPeak)*1000)/1000;
  158. } else {
  159. lP = 0;
  160. rP = 0;
  161. }
  162. } else {
  163. // stopped, not loaded or feature not used
  164. nP = 0;
  165. }
  166. // loading progress
  167. if (bL && bT && bL != oSound.lastValues.bytes) {
  168. oSound.lastValues.bytes = bL;
  169. ExternalInterface.call(sMethod,bL,bT,nD);
  170. }
  171. }
  172. // peak data
  173. if (oSoundChannel && oSound.usePeakData) {
  174. if (lP != oSound.lastValues.leftPeak) {
  175. oSound.lastValues.leftPeak = lP;
  176. newPeakData = true;
  177. }
  178. if (rP != oSound.lastValues.rightPeak) {
  179. oSound.lastValues.rightPeak = rP;
  180. newPeakData = true;
  181. }
  182. }
  183. // raw waveform + EQ spectrum data
  184. if (oSoundChannel) {
  185. if (oSound.useWaveformData) {
  186. try {
  187. oSound.getWaveformData();
  188. } catch(e:Error) {
  189. writeDebug('computeSpectrum() (waveform data) '+e.toString());
  190. oSound.useWaveformData = false;
  191. }
  192. }
  193. if (oSound.useEQData) {
  194. try {
  195. oSound.getEQData();
  196. } catch(e:Error) {
  197. writeDebug('computeSpectrum() (EQ data) '+e.toString());
  198. oSound.useEQData = false;
  199. }
  200. }
  201. if (oSound.waveformDataArray != oSound.lastValues.waveformDataArray) {
  202. oSound.lastValues.waveformDataArray = oSound.waveformDataArray;
  203. newWaveformData = true;
  204. }
  205. if (oSound.eqDataArray != oSound.lastValues.eqDataArray) {
  206. oSound.lastValues.eqDataArray = oSound.eqDataArray;
  207. newEQData = true;
  208. }
  209. }
  210. if (typeof nP != 'undefined' && nP != oSound.lastValues.position) {
  211. oSound.lastValues.position = nP;
  212. sMethod = baseJSObject+"['"+sounds[i]+"']._whileplaying";
  213. // writeDebug('whileplaying(): '+nP+','+(newPeakData?lP+','+rP:null)+','+(newWaveformData?oSound.waveformDataArray:null)+','+(newEQData?oSound.eqDataArray:null));
  214. if (oSound.useNetstream != true) {
  215. ExternalInterface.call(sMethod,nP,(newPeakData?{leftPeak:lP,rightPeak:rP}:null),(newWaveformData?oSound.waveformDataArray:null),(newEQData?oSound.eqDataArray:null));
  216. } else {
  217. ExternalInterface.call(sMethod,nP,null,null,null);
  218. }
  219. // if position changed, check for near-end
  220. if (oSound.didJustBeforeFinish != true && oSound.loaded == true && oSound.justBeforeFinishOffset > 0 && nD-nP <= oSound.justBeforeFinishOffset) {
  221. // fully-loaded, near end and haven't done this yet..
  222. sMethod = baseJSObject+"['"+sounds[i]+"']._onjustbeforefinish";
  223. ExternalInterface.call(sMethod,(nD-nP));
  224. oSound.didJustBeforeFinish = true;
  225. }
  226. }
  227. }
  228. }
  229. public function onLoadError(oSound:Object):void {
  230. // something went wrong. 404, bad format etc.
  231. ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._onload",0);
  232. }
  233. public function onLoad(e:Event):void {
  234. checkProgress(); // ensure progress stats are up-to-date
  235. var oSound:Object = e.target;
  236. if (!oSound.useNetstream) { // FLV must also have metadata
  237. oSound.loaded = true;
  238. // force duration update (doesn't seem to be always accurate)
  239. ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._whileloading",oSound.bytesLoaded,oSound.bytesTotal,oSound.length||oSound.duration);
  240. // TODO: Determine if loaded or failed - bSuccess?
  241. // ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._onload",bSuccess?1:0);
  242. ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._onload",1);
  243. }
  244. }
  245. public function onID3(e:Event):void {
  246. // --- NOTE: BUGGY (Flash 8 only? Haven't really checked 9 + 10.) ---
  247. // TODO: Investigate holes in ID3 parsing - for some reason, Album will be populated with Date if empty and date is provided. (?)
  248. // ID3V1 seem to parse OK, but "holes" / blanks in ID3V2 data seem to get messed up (eg. missing album gets filled with date.)
  249. // iTunes issues: onID3 was not called with a test MP3 encoded with iTunes 7.01, and what appeared to be valid ID3V2 data.
  250. // May be related to thumbnails for album art included in MP3 file by iTunes. See http://mabblog.com/blog/?p=33
  251. try {
  252. var oSound:Object = e.target;
  253. var id3Data:Array = [];
  254. var id3Props:Array = [];
  255. for (var prop:String in oSound.id3) {
  256. id3Props.push(prop);
  257. id3Data.push(oSound.id3[prop]);
  258. // writeDebug('id3['+prop+']: '+oSound.id3[prop]);
  259. }
  260. ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._onid3",id3Props,id3Data);
  261. // unhook own event handler, prevent second call (can fire twice as data is received - ID3V2 at beginning, ID3V1 at end.)
  262. // Therefore if ID3V2 data is received, ID3V1 is ignored.
  263. // soundObjects[oSound.sID].onID3 = null;
  264. } catch(e:Error) {
  265. writeDebug('onID3(): Unable to get ID3 info for '+oSound.sID+'.');
  266. }
  267. oSound.removeEventListener(Event.ID3,onID3);
  268. }
  269. public function registerOnComplete(sID:String):void {
  270. if (soundObjects[sID] && soundObjects[sID].soundChannel) {
  271. soundObjects[sID].soundChannel.addEventListener(Event.SOUND_COMPLETE, function():void {
  272. this.didJustBeforeFinish = false; // reset
  273. if (soundObjects[sID]) {
  274. checkProgress();
  275. try {
  276. soundObjects[sID].start(0,1); // go back to 0
  277. soundObjects[sID].soundChannel.stop();
  278. } catch(e:Error) {
  279. writeDebug('Could not set position on '+sID+': '+e.toString());
  280. }
  281. }
  282. // checkProgress();
  283. ExternalInterface.call(baseJSObject+"['"+sID+"']._onfinish");
  284. });
  285. }
  286. }
  287. public function doSecurityError(oSound:SoundManager2_SMSound_AS3,e:SecurityErrorEvent):void {
  288. writeDebug('securityError: '+e.text);
  289. // when this happens, you don't have security rights on the server containing the FLV file
  290. // a crossdomain.xml file would fix the problem easily
  291. }
  292. public function doIOError(oSound:SoundManager2_SMSound_AS3,e:IOErrorEvent):void {
  293. // writeDebug('ioError: '+e.text);
  294. // call checkProgress()?
  295. ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._onload",0); // call onload, assume it failed.
  296. // there was a connection drop, a loss of internet connection, or something else wrong. 404 error too.
  297. }
  298. public function doAsyncError(oSound:SoundManager2_SMSound_AS3,e:AsyncErrorEvent):void {
  299. writeDebug('asyncError: '+e.text);
  300. // this is more related to streaming server from my experience, but you never know
  301. }
  302. public function doNetStatus(oSound:SoundManager2_SMSound_AS3,e:NetStatusEvent):void {
  303. // this will eventually let us know what is going on.. is the stream loading, empty, full, stopped?
  304. if (e.info.code != "NetStream.Buffer.Full" && e.info.code != "NetStream.Buffer.Empty" && e.info.code != "NetStream.Seek.Notify") {
  305. writeDebug('netStatusEvent: '+e.info.code);
  306. }
  307. if (e.info.code == "NetStream.Play.Stop") { // && !oSound.didFinish && oSound.loaded == true && nD == nP
  308. // finished playing
  309. // oSound.didFinish = true; // will be reset via JS callback
  310. oSound.didJustBeforeFinish = false; // reset
  311. writeDebug('calling onfinish for a sound');
  312. // writeDebug('sound, nD, nP: '+oSound.sID+', '+nD+', '+nP);
  313. // reset the sound
  314. oSound.ns.pause();
  315. oSound.ns.seek(0);
  316. // whileplaying()?
  317. ExternalInterface.call(baseJSObject+"['"+oSound.sID+"']._onfinish");
  318. }
  319. if (e.info.code == "NetStream.Play.FileStructureInvalid" || e.info.code == "NetStream.Play.FileStructureInvalid" || e.info.code == "NetStream.Play.StreamNotFound") {
  320. this.onLoadError(oSound);
  321. }
  322. }
  323. public function addNetstreamEvents(oSound:SoundManager2_SMSound_AS3):void {
  324. oSound.ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, function(e:AsyncErrorEvent):void{doAsyncError(oSound,e)});
  325. oSound.ns.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{doNetStatus(oSound,e)});
  326. oSound.ns.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void{doIOError(oSound,e)});
  327. oSound.nc.addEventListener(NetStatusEvent.NET_STATUS, oSound.doNetStatus);
  328. }
  329. public function removeNetstreamEvents(oSound:SoundManager2_SMSound_AS3):void {
  330. oSound.ns.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, function(e:AsyncErrorEvent):void{doAsyncError(oSound,e)});
  331. oSound.ns.removeEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{doNetStatus(oSound,e)});
  332. oSound.ns.removeEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void{doIOError(oSound,e)});
  333. oSound.nc.removeEventListener(NetStatusEvent.NET_STATUS, oSound.doNetStatus);
  334. }
  335. public function _setPosition(sID:String,nSecOffset:Number,isPaused:Boolean):void {
  336. var s:SoundManager2_SMSound_AS3 = soundObjects[sID];
  337. if (!s) return void;
  338. // writeDebug('_setPosition()');
  339. // stop current channel, start new one.
  340. if (s.lastValues) {
  341. s.lastValues.position = nSecOffset; // s.soundChannel.position;
  342. }
  343. if (s.useNetstream) {
  344. // writeDebug('setPosition: seeking to '+nSecOffset/1000);
  345. s.ns.seek(nSecOffset>0?nSecOffset/1000:0);
  346. checkProgress(); // force UI update
  347. } else {
  348. if (s.soundChannel) {
  349. s.soundChannel.stop();
  350. }
  351. // writeDebug('setPosition: '+nSecOffset+', '+(s.lastValues.nLoops?s.lastValues.nLoops:1));
  352. try {
  353. s.start(nSecOffset,s.lastValues.nLoops||1); // start playing at new position
  354. } catch(e:Error) {
  355. writeDebug('Warning: Could not set position on '+sID+': '+e.toString());
  356. }
  357. checkProgress(); // force UI update
  358. try {
  359. registerOnComplete(sID);
  360. } catch(e:Error) {
  361. writeDebug('_setPosition(): Could not register onComplete');
  362. }
  363. if (isPaused && s.soundChannel) {
  364. // writeDebug('_setPosition: stopping (paused) sound');
  365. // writeDebug('last position: '+s.lastValues.position+' vs '+s.soundChannel.position);
  366. s.soundChannel.stop();
  367. }
  368. }
  369. }
  370. public function _load(sID:String,sURL:String,bStream:Boolean,bAutoPlay:Boolean):void {
  371. writeDebug('_load()');
  372. if (typeof bAutoPlay == 'undefined') bAutoPlay = false;
  373. var s:SoundManager2_SMSound_AS3 = soundObjects[sID];
  374. if (!s) return void;
  375. var didRecreate:Boolean = false;
  376. if (s.didLoad == true) {
  377. // need to recreate sound
  378. didRecreate = true;
  379. writeDebug('recreating sound '+sID+' in order to load '+sURL);
  380. var ns:Object = new Object();
  381. ns.sID = s.sID;
  382. ns.justBeforeFinishOffset = s.justBeforeFinishOffset;
  383. ns.usePeakData = s.usePeakData;
  384. ns.useWaveformData = s.useWaveformData;
  385. ns.useEQData = s.useEQData;
  386. ns.useNetstream = s.useNetstream;
  387. ns.useVideo = s.useVideo;
  388. _destroySound(s.sID);
  389. _createSound(ns.sID,sURL,ns.justBeforeFinishOffset,ns.usePeakData,ns.useWaveformData,ns.useEQData,ns.useNetstream,ns.useVideo);
  390. s = soundObjects[sID];
  391. // writeDebug('Sound object replaced');
  392. }
  393. checkProgress();
  394. if (!s.didLoad) {
  395. try {
  396. s.addEventListener(Event.ID3, onID3);
  397. s.addEventListener(Event.COMPLETE, onLoad);
  398. } catch(e:Error) {
  399. writeDebug('_load(): could not assign ID3/complete event handlers');
  400. }
  401. }
  402. // s.addEventListener(ProgressEvent.PROGRESS, checkLoadProgress); // May be called often, potential CPU drain
  403. // s.addEventListener(Event.FINISH, onFinish);
  404. // s.loaded = true; // TODO: Investigate - Flash 9 non-FLV bug??
  405. // s.didLoad = true; // TODO: Investigate - bug?
  406. // if (didRecreate || s.sURL != sURL) {
  407. // don't try to load if same request already made
  408. s.sURL = sURL;
  409. if (s.useNetstream) {
  410. try {
  411. // s.ns.close();
  412. this.addNetstreamEvents(s);
  413. s.ns.play(sURL);
  414. } catch(e:Error) {
  415. writeDebug('_load(): error: '+e.toString());
  416. }
  417. } else {
  418. try {
  419. s.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void{doIOError(s,e)});
  420. s.loadSound(sURL,bStream);
  421. } catch(e:Error) {
  422. // oh well
  423. writeDebug('_load: Error loading '+sURL+'. Flash error detail: '+e.toString());
  424. }
  425. }
  426. s.didJustBeforeFinish = false;
  427. if (bAutoPlay != true) {
  428. // s.soundChannel.stop(); // prevent default auto-play behaviour
  429. // writeDebug('auto-play stopped');
  430. } else {
  431. // writeDebug('auto-play allowed');
  432. // s.start(0,1);
  433. // registerOnComplete(sID);
  434. }
  435. }
  436. public function _unload(sID:String,sURL:String):void {
  437. var s:SoundManager2_SMSound_AS3 = soundObjects[sID];
  438. if (!s) return void;
  439. try {
  440. removeEventListener(Event.ID3,onID3);
  441. removeEventListener(Event.COMPLETE, onLoad);
  442. } catch(e:Error) {
  443. writeDebug('_unload() warn: Could not remove ID3/complete events');
  444. }
  445. s.paused = false;
  446. if (s.soundChannel) {
  447. s.soundChannel.stop();
  448. }
  449. try {
  450. if (s.didLoad && !s.useNetstream) {
  451. s.close(); // close stream only if still loading?
  452. }
  453. } catch(e:Error) {
  454. // stream may already have closed if sound loaded, etc.
  455. writeDebug('sound._unload(): '+sID+' already unloaded?');
  456. // oh well
  457. }
  458. // destroy and recreate Flash sound object, try to reclaim memory
  459. // writeDebug('sound._unload(): recreating sound '+sID+' to free memory');
  460. if (s.useNetstream) {
  461. // writeDebug('_unload(): closing netStream stuff');
  462. try {
  463. this.removeNetstreamEvents(s);
  464. s.ns.close();
  465. s.nc.close();
  466. // s.nc = null;
  467. // s.ns = null;
  468. } catch(e:Error) {
  469. // oh well
  470. writeDebug('_unload(): caught exception during netConnection/netStream close');
  471. }
  472. if (s.useVideo) {
  473. writeDebug('_unload(): clearing video');
  474. s.oVideo.clear();
  475. // s.oVideo = null;
  476. }
  477. }
  478. var ns:Object = new Object();
  479. ns.sID = s.sID;
  480. ns.justBeforeFinishOffset = s.justBeforeFinishOffset;
  481. ns.usePeakData = s.usePeakData;
  482. ns.useWaveformData = s.useWaveformData;
  483. ns.useEQData = s.useEQData;
  484. ns.useNetstream = s.useNetstream;
  485. ns.useVideo = s.useVideo;
  486. _destroySound(s.sID);
  487. _createSound(ns.sID,sURL,ns.justBeforeFinishOffset,ns.usePeakData,ns.useWaveformData,ns.useEQData,ns.useNetstream,ns.useVideo);
  488. }
  489. public function _createSound(sID:String,sURL:String,justBeforeFinishOffset:int,usePeakData:Boolean,useWaveformData:Boolean,useEQData:Boolean,useNetstream:Boolean,useVideo:Boolean):void {
  490. soundObjects[sID] = new SoundManager2_SMSound_AS3(this,sID,sURL,usePeakData,useWaveformData,useEQData,useNetstream,useVideo);
  491. var s:SoundManager2_SMSound_AS3 = soundObjects[sID];
  492. if (!s) return void;
  493. // s.setVolume(100);
  494. s.didJustBeforeFinish = false;
  495. s.sID = sID;
  496. s.sURL = sURL;
  497. s.paused = false;
  498. s.loaded = false;
  499. s.justBeforeFinishOffset = justBeforeFinishOffset||0;
  500. s.lastValues = {
  501. bytes: 0,
  502. position: 0,
  503. nLoops: 1,
  504. leftPeak: 0,
  505. rightPeak: 0
  506. };
  507. if (!(sID in sounds)) sounds.push(sID);
  508. // sounds.push(sID);
  509. }
  510. public function _destroySound(sID:String):void {
  511. // for the power of garbage collection! .. er, Greyskull!
  512. var s:SoundManager2_SMSound_AS3 = (soundObjects[sID]||null);
  513. if (!s) return void;
  514. // try to unload the sound
  515. for (var i:int=0, j:int=sounds.length; i<j; i++) {
  516. if (sounds[i] == s) {
  517. sounds.splice(i,1);
  518. continue;
  519. }
  520. }
  521. if (s.soundChannel) {
  522. s.soundChannel.stop();
  523. }
  524. this.stage.removeEventListener(Event.RESIZE, s.resizeHandler);
  525. // if is a movie, remove that as well.
  526. if (s.useNetstream) {
  527. // s.nc.client = null;
  528. try {
  529. this.removeNetstreamEvents(s);
  530. // s.nc.removeEventListener(NetStatusEvent.NET_STATUS, s.doNetStatus);
  531. } catch(e:Error) {
  532. writeDebug('_destroySound(): Events already removed from netStream/netConnection?');
  533. }
  534. if (s.useVideo) {
  535. try {
  536. this.removeChild(s.oVideo);
  537. } catch(e:Error) {
  538. writeDebug('_destoySound(): could not remove video?');
  539. }
  540. }
  541. if (s.didLoad) {
  542. try {
  543. s.ns.close();
  544. s.nc.close();
  545. } catch(e:Error) {
  546. // oh well
  547. writeDebug('_destroySound(): error during netConnection/netStream close and null');
  548. }
  549. }
  550. } else if (s.didLoad) {
  551. // non-netstream case
  552. try {
  553. s.close(); // close stream only if still loading?
  554. } catch(e:Error) {
  555. // oh well
  556. }
  557. }
  558. s = null;
  559. soundObjects[sID] = null;
  560. delete soundObjects[sID];
  561. }
  562. public function _stop(sID:String,bStopAll:Boolean):void {
  563. // stop this particular instance (or "all", based on parameter)
  564. if (bStopAll) {
  565. SoundMixer.stopAll();
  566. // ExternalInterface.call('alert','Flash: need _stop for all sounds');
  567. // SoundManager2_AS3.display.stage.stop(); // _root.stop();
  568. // this.soundChannel.stop();
  569. // soundMixer.stop();
  570. } else {
  571. var s:SoundManager2_SMSound_AS3 = soundObjects[sID];
  572. if (!s) return void;
  573. if (s.useNetstream) {
  574. s.ns.pause();
  575. if (s.oVideo) {
  576. s.oVideo.visible = false;
  577. }
  578. } else {
  579. s.soundChannel.stop();
  580. }
  581. s.paused = false;
  582. s.didJustBeforeFinish = false;
  583. }
  584. }
  585. public function _start(sID:String,nLoops:int,nMsecOffset:int):void {
  586. var s:SoundManager2_SMSound_AS3 = soundObjects[sID];
  587. if (!s) return void;
  588. s.lastValues.paused = false; // reset pause if applicable
  589. s.lastValues.nLoops = (nLoops||1);
  590. s.lastValues.position = nMsecOffset;
  591. try {
  592. s.start(nMsecOffset,nLoops);
  593. } catch(e:Error) {
  594. writeDebug('Could not start '+sID+': '+e.toString());
  595. }
  596. try {
  597. registerOnComplete(sID);
  598. } catch(e:Error) {
  599. writeDebug('_start(): registerOnComplete failed');
  600. }
  601. }
  602. public function _pause(sID:String):void {
  603. // writeDebug('_pause()');
  604. var s:SoundManager2_SMSound_AS3 = soundObjects[sID];
  605. if (!s) return void;
  606. // writeDebug('s.paused: '+s.paused);
  607. if (!s.paused) {
  608. // reference current position, stop sound
  609. s.paused = true;
  610. // writeDebug('_pause(): position: '+s.lastValues.position);
  611. if (s.useNetstream) {
  612. s.lastValues.position = s.ns.time;
  613. s.ns.pause();
  614. } else {
  615. if (s.soundChannel) {
  616. s.lastValues.position = s.soundChannel.position;
  617. s.soundChannel.stop();
  618. }
  619. }
  620. } else {
  621. // resume playing from last position
  622. // writeDebug('resuming - playing at '+s.lastValues.position+', '+s.lastValues.nLoops+' times');
  623. s.paused = false;
  624. if (s.useNetstream) {
  625. s.ns.resume();
  626. } else {
  627. s.start(s.lastValues.position,s.lastValues.nLoops);
  628. }
  629. try {
  630. registerOnComplete(sID);
  631. } catch(e:Error) {
  632. writeDebug('_pause(): registerOnComplete() failed');
  633. }
  634. }
  635. }
  636. public function _setPan(sID:String,nPan:Number):void {
  637. soundObjects[sID].setPan(nPan);
  638. }
  639. public function _setVolume(sID:String,nVol:Number):void {
  640. // writeDebug('_setVolume: '+nVol);
  641. soundObjects[sID].setVolume(nVol);
  642. }
  643. public function _setPolling(bPolling:Boolean):void {
  644. pollingEnabled = bPolling;
  645. if (timer == null && pollingEnabled) {
  646. writeDebug('Enabling polling');
  647. timer = new Timer(timerInterval,0);
  648. timer.addEventListener(TimerEvent.TIMER, function():void{checkProgress();}); // direct reference eg. checkProgress doesn't work? .. odd.
  649. timer.start();
  650. } else if (timer && !pollingEnabled) {
  651. writeDebug('Disabling polling');
  652. // flash.utils.clearInterval(timer);
  653. timer.reset();
  654. }
  655. }
  656. public function _getMemoryUse():String {
  657. return System.totalMemory.toString();
  658. }
  659. // XML handler stuff
  660. public function _loadFromXML(sURL:String):void {
  661. var loader:URLLoader = new URLLoader();
  662. loader.addEventListener(Event.COMPLETE, parseXML);
  663. writeDebug('Attempting to load XML: '+sURL);
  664. try {
  665. loader.load(new URLRequest(sURL));
  666. } catch(e:Error) {
  667. writeDebug('Error loading XML: '+e.toString());
  668. }
  669. }
  670. public function parseXML(e:Event):void {
  671. try {
  672. var oXML:XMLDocument = new XMLDocument();
  673. oXML.ignoreWhite = true;
  674. oXML.parseXML(e.target.data);
  675. var xmlRoot:XMLNode = oXML.firstChild;
  676. var xmlAttr:Object = xmlRoot.attributes;
  677. var oOptions:Object = {};
  678. var i:int = 0;
  679. var j:int = 0;
  680. for (i=0,j=xmlRoot.childNodes.length; i<j; i++) {
  681. xmlAttr = xmlRoot.childNodes[i].attributes;
  682. oOptions = {
  683. id : xmlAttr.id,
  684. url : xmlRoot.attributes.baseHref+xmlAttr.href,
  685. stream : xmlAttr.stream
  686. }
  687. ExternalInterface.call(baseJSController+".createSound",oOptions);
  688. }
  689. } catch(e:Error) {
  690. writeDebug('Error parsing XML: '+e.toString());
  691. }
  692. }
  693. // -----------------------------------
  694. // end methods
  695. }
  696. // package
  697. }