1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
|
/*
SoundManager 2: Javascript Sound for the Web
----------------------------------------------
http://schillmania.com/projects/soundmanager2/
Copyright (c) 2007, Scott Schiller. All rights reserved.
Code licensed under the BSD License:
http://www.schillmania.com/projects/soundmanager2/license.txt
Flash 9 / ActionScript 3 version
*/
package {
import flash.external.*;
import flash.events.*;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundLoaderContext;
import flash.media.SoundTransform;
import flash.media.SoundMixer;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.utils.getTimer;
import flash.net.NetConnection;
import flash.net.NetStream;
public class SoundManager2_SMSound_AS3 extends Sound {
public var sm: SoundManager2_AS3 = null;
// externalInterface references (for Javascript callbacks)
public var baseJSController: String = "soundManager";
public var baseJSObject: String = baseJSController + ".sounds";
public var soundChannel: SoundChannel = new SoundChannel();
public var urlRequest: URLRequest;
public var soundLoaderContext: SoundLoaderContext;
public var waveformData: ByteArray = new ByteArray();
public var waveformDataArray: Array = [];
public var eqData: ByteArray = new ByteArray();
public var eqDataArray: Array = [];
public var usePeakData: Boolean = false;
public var useWaveformData: Boolean = false;
public var useEQData: Boolean = false;
public var sID: String;
public var sURL: String;
public var justBeforeFinishOffset: int;
public var didJustBeforeFinish: Boolean;
public var didFinish: Boolean;
public var loaded: Boolean;
public var connected: Boolean;
public var failed: Boolean;
public var paused: Boolean;
public var finished: Boolean;
public var duration: Number;
public var handledDataError: Boolean = false;
public var ignoreDataError: Boolean = false;
public var autoPlay: Boolean = false;
public var autoLoad: Boolean = false;
public var pauseOnBufferFull: Boolean = true;
public var loops: Number = 1;
public var lastValues: Object = {
bytes: 0,
position: 0,
volume: 100,
pan: 0,
loops: 1,
leftPeak: 0,
rightPeak: 0,
waveformDataArray: null,
eqDataArray: null,
isBuffering: null,
bufferLength: 0
};
public var didLoad: Boolean = false;
public var useEvents: Boolean = false;
public var sound: Sound = new Sound();
public var cc: Object;
public var nc: NetConnection;
public var ns: NetStream = null;
public var st: SoundTransform;
public var useNetstream: Boolean;
public var bufferTime: Number = 3; // previously 0.1
public var bufferTimes: Array; // an array of integers (for specifying multiple buffers)
public var lastNetStatus: String = null;
public var serverUrl: String = null;
public var start_time: Number;
public var connect_time: Number;
public var play_time: Number;
public var recordStats: Boolean = false;
public var checkPolicyFile:Boolean = false;
public function SoundManager2_SMSound_AS3(oSoundManager: SoundManager2_AS3, sIDArg: String = null, sURLArg: String = null, usePeakData: Boolean = false, useWaveformData: Boolean = false, useEQData: Boolean = false, useNetstreamArg: Boolean = false, netStreamBufferTime: Number = 1, serverUrl: String = null, duration: Number = 0, autoPlay: Boolean = false, useEvents: Boolean = false, bufferTimes: Array = null, recordStats: Boolean = false, autoLoad: Boolean = false, checkPolicyFile: Boolean = false) {
this.sm = oSoundManager;
this.sID = sIDArg;
this.sURL = sURLArg;
this.usePeakData = usePeakData;
this.useWaveformData = useWaveformData;
this.useEQData = useEQData;
this.urlRequest = new URLRequest(sURLArg);
this.justBeforeFinishOffset = 0;
this.didJustBeforeFinish = false;
this.didFinish = false; // non-MP3 formats only
this.loaded = false;
this.connected = false;
this.failed = false;
this.finished = false;
this.soundChannel = null;
this.lastNetStatus = null;
this.useNetstream = useNetstreamArg;
this.serverUrl = serverUrl;
this.duration = duration;
this.recordStats = recordStats;
this.useEvents = useEvents;
this.autoLoad = autoLoad;
if (netStreamBufferTime) {
this.bufferTime = netStreamBufferTime;
}
// Use bufferTimes instead of bufferTime
if (bufferTimes !== null) {
this.bufferTimes = bufferTimes;
} else {
this.bufferTimes = [this.bufferTime];
}
setAutoPlay(autoPlay);
if (recordStats) {
this.start_time = getTimer();
}
this.checkPolicyFile = checkPolicyFile;
writeDebug('SoundManager2_SMSound_AS3: Got duration: '+duration+', autoPlay: '+autoPlay);
if (this.useNetstream) {
this.cc = new Object();
this.nc = new NetConnection();
// Handle FMS bandwidth check callback.
// @see onBWDone
// @see http://www.adobe.com/devnet/flashmediaserver/articles/dynamic_stream_switching_04.html
// @see http://www.johncblandii.com/index.php/2007/12/fms-a-quick-fix-for-missing-onbwdone-onfcsubscribe-etc.html
this.nc.client = this;
// TODO: security/IO error handling
// this.nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, doSecurityError);
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
if (this.serverUrl != null) {
writeDebug('SoundManager2_SMSound_AS3: NetConnection: connecting to server ' + this.serverUrl + '...');
}
this.nc.connect(serverUrl);
} else {
this.connect_time = this.start_time;
this.connected = true;
}
}
public function netStatusHandler(event:NetStatusEvent):void {
if (this.useEvents) {
writeDebug('netStatusHandler: '+event.info.code);
}
switch (event.info.code) {
case "NetConnection.Connect.Success":
writeDebug('NetConnection: connected');
try {
this.ns = new NetStream(this.nc);
this.ns.checkPolicyFile = this.checkPolicyFile;
// bufferTime reference: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/net/NetStream.html#bufferTime
this.ns.bufferTime = getStartBuffer(); // set to 0.1 or higher. 0 is reported to cause playback issues with static files.
this.st = new SoundTransform();
this.cc.onMetaData = this.metaDataHandler;
this.ns.client = this.cc;
this.ns.receiveAudio(true);
this.addNetstreamEvents();
this.connected = true;
if (recordStats) {
this.recordConnectTime();
}
if (this.useEvents) {
writeDebug('firing _onconnect for '+this.sID);
ExternalInterface.call(this.sm.baseJSObject + "['" + this.sID + "']._onconnect", 1);
}
} catch(e: Error) {
this.failed = true;
writeDebug('netStream error: ' + e.toString());
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onfailure", 'Connection failed!', event.info.level, event.info.code);
}
break;
case "NetStream.Play.StreamNotFound":
this.failed = true;
writeDebug("NetConnection: Stream not found!");
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onfailure", 'Stream not found!', event.info.level, event.info.code);
break;
// This is triggered when the sound loses the connection with the server.
// In some cases one could just try to reconnect to the server and resume playback.
// However for streams protected by expiring tokens, I don't think that will work.
//
// Flash says that this is not an error code, but a status code...
// should this call the onFailure handler?
case "NetConnection.Connect.Closed":
this.failed = true;
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onfailure", 'Connection closed!', event.info.level, event.info.code);
writeDebug("NetConnection: Connection closed!");
break;
// Couldn't establish a connection with the server. Attempts to connect to the server
// can also fail if the permissible number of socket connections on either the client
// or the server computer is at its limit. This also happens when the internet
// connection is lost.
case "NetConnection.Connect.Failed":
this.failed = true;
writeDebug("NetConnection: Connection failed! Lost internet connection? Try again... Description: " + event.info.description);
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onfailure", 'Connection failed!', event.info.level, event.info.code);
break;
// A change has occurred to the network status. This could mean that the network
// connection is back, or it could mean that it has been lost...just try to resume
// playback.
// KJV: Can't use this yet because by the time you get your connection back the
// song has reached it's maximum retries, so it doesn't retry again. We need
// a new _ondisconnect handler.
//case "NetConnection.Connect.NetworkChange":
// this.failed = true;
// writeDebug("NetConnection: Network connection status changed");
// ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onfailure", 'Reconnecting...');
// break;
// Consider everything else a failure...
default:
this.failed = true;
writeDebug("NetConnection: got unhandled code '" + event.info.code + "'! Description: " + event.info.description);
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onfailure", '', event.info.level, event.info.code);
break;
}
}
// Set the buffer size on the current NetSream instance to <tt>buffer</tt> secs
// Only set the buffer if it's different to the current buffer.
public function setBuffer(buffer: int) : void {
if (buffer != this.ns.bufferTime) {
this.ns.bufferTime = buffer;
writeDebug('set buffer to '+this.ns.bufferTime+' secs');
}
}
// Return the size of the starting buffer.
public function getStartBuffer() : int {
return this.bufferTimes[0];
}
// Return the size of the next buffer, given the size of the current buffer.
// If there are no more buffers, returns the current buffer size.
public function getNextBuffer(current_buffer: int) : int {
var i: int = bufferTimes.indexOf(current_buffer);
if (i == -1) {
// Couldn't find the buffer, start from the start buffer size
return getStartBuffer();
} else if (i + 1 >= bufferTimes.length) {
// Last (or only) buffer, keep the current buffer
return current_buffer;
} else {
return this.bufferTimes[i+1];
}
}
public function writeDebug (s: String, bTimestamp: Boolean = false) : Boolean {
return this.sm.writeDebug (s, bTimestamp); // defined in main SM object
}
public function metaDataHandler(infoObject: Object) : void {
/*
var data:String = new String();
for (var prop:* in infoObject) {
data += prop+': '+infoObject[prop]+' ';
}
ExternalInterface.call('soundManager._writeDebug','Metadata: '+data);
*/
if (!this.loaded) {
// writeDebug('not loaded yet: '+this.ns.bytesLoaded+', '+this.ns.bytesTotal+', '+infoObject.duration*1000);
// TODO: investigate loaded/total values
// ExternalInterface.call(baseJSObject + "['" + this.sID + "']._whileloading", this.ns.bytesLoaded, this.ns.bytesTotal, infoObject.duration*1000);
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._whileloading", this.bytesLoaded, this.bytesTotal, (infoObject.duration || this.duration))
}
this.duration = infoObject.duration * 1000;
// null this out for the duration of this object's existence.
// it may be called multiple times.
this.cc.onMetaData = function(infoObject: Object) : void {}
}
public function getWaveformData() : void {
// http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/SoundMixer.html#computeSpectrum()
SoundMixer.computeSpectrum(this.waveformData, false, 0); // sample wave data at 44.1 KHz
this.waveformDataArray = [];
for (var i: int = 0, j: int = this.waveformData.length / 4; i < j; i++) { // get all 512 values (256 per channel)
this.waveformDataArray.push(int(this.waveformData.readFloat() * 1000) / 1000);
}
}
public function getEQData() : void {
// http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/SoundMixer.html#computeSpectrum()
SoundMixer.computeSpectrum(this.eqData, true, 0); // sample EQ data at 44.1 KHz
this.eqDataArray = [];
for (var i: int = 0, j: int = this.eqData.length / 4; i < j; i++) { // get all 512 values (256 per channel)
this.eqDataArray.push(int(this.eqData.readFloat() * 1000) / 1000);
}
}
public function start(nMsecOffset: int, nLoops: int) : void {
this.useEvents = true;
if (this.useNetstream) {
writeDebug("SMSound::start nMsecOffset "+ nMsecOffset+ ' nLoops '+nLoops + ' current bufferTime '+this.ns.bufferTime+' current bufferLength '+this.ns.bufferLength+ ' this.lastValues.position '+this.lastValues.position);
this.cc.onMetaData = this.metaDataHandler;
// Don't seek if we don't have to because it destroys the buffer
var set_position:Boolean = this.lastValues.position != null && this.lastValues.position != nMsecOffset;
if (set_position) {
// Minimize the buffer so playback starts ASAP
this.setBuffer(this.getStartBuffer());
}
if (this.paused) {
writeDebug('start: resuming from paused state');
this.ns.resume(); // get the sound going again
if (!this.didLoad) {
this.didLoad = true;
}
this.paused = false;
} else if (!this.didLoad) {
writeDebug('start: !didLoad - playing '+this.sURL);
this.ns.play(this.sURL);
this.didLoad = true;
this.paused = false;
} else {
// previously loaded, perhaps stopped/finished. play again?
writeDebug('playing again (not paused, didLoad = true)');
this.ns.play(this.sURL);
}
// KJV seek after calling play otherwise some streams get a NetStream.Seek.Failed
// Should only apply to the !didLoad case, but do it for all for simplicity.
// nMsecOffset is in milliseconds for streams but in seconds for progressive
// download.
if (set_position) {
this.ns.seek(this.serverUrl ? nMsecOffset / 1000 : nMsecOffset);
this.lastValues.position = nMsecOffset; // https://gist.github.com/1de8a3113cf33d0cff67
}
// this.ns.addEventListener(Event.SOUND_COMPLETE, _onfinish);
this.applyTransform();
} else {
// writeDebug('start: seeking to '+nMsecOffset+', '+nLoops+(nLoops==1?' loop':' loops'));
this.soundChannel = this.play(nMsecOffset, nLoops);
this.addEventListener(Event.SOUND_COMPLETE, _onfinish);
this.applyTransform();
}
}
private function _onfinish() : void {
this.removeEventListener(Event.SOUND_COMPLETE, _onfinish);
}
public function loadSound(sURL: String, bStream: Boolean) : void {
if (this.useNetstream) {
this.useEvents = true;
if (this.didLoad != true) {
ExternalInterface.call('loadSound(): loading ' + this.sURL);
this.ns.play(this.sURL);
this.didLoad = true;
}
// this.addEventListener(Event.SOUND_COMPLETE, _onfinish);
this.applyTransform();
} else {
try {
this.didLoad = true;
this.urlRequest = new URLRequest(sURL);
this.soundLoaderContext = new SoundLoaderContext(1000, this.checkPolicyFile); // check for policy (crossdomain.xml) file on remote domains - http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/media/SoundLoaderContext.html
this.load(this.urlRequest, this.soundLoaderContext);
} catch(e: Error) {
writeDebug('error during loadSound(): ' + e.toString());
}
}
}
public function setAutoPlay(autoPlay: Boolean) : void {
if (!this.serverUrl) {
// don't apply to non-RTMP, netstream stuff.
this.autoPlay = true;
this.pauseOnBufferFull = false;
} else {
this.autoPlay = autoPlay;
if (this.autoPlay) {
this.pauseOnBufferFull = false;
// writeDebug('ignoring pauseOnBufferFull because autoPlay is on');
} else if (!this.autoPlay) {
this.pauseOnBufferFull = true;
// writeDebug('pausing on buffer full because autoPlay is off');
}
}
}
public function setVolume(nVolume: Number) : void {
this.lastValues.volume = nVolume / 100;
this.applyTransform();
}
public function setPan(nPan: Number) : void {
this.lastValues.pan = nPan / 100;
this.applyTransform();
}
public function applyTransform() : void {
var st: SoundTransform = new SoundTransform(this.lastValues.volume, this.lastValues.pan);
if (this.useNetstream) {
if (this.ns) {
this.ns.soundTransform = st;
} else {
// writeDebug('applyTransform(): Note: No active netStream');
}
} else if (this.soundChannel) {
this.soundChannel.soundTransform = st; // new SoundTransform(this.lastValues.volume, this.lastValues.pan);
}
}
public function recordPlayTime() : void {
this.play_time = Math.round(getTimer() - (this.start_time + this.connect_time));
writeDebug('Play took '+ this.play_time + ' ms');
// We must now have both stats, call the onstats callback
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onstats", {
play_time: this.play_time,
connect_time: this.connect_time
});
// Stop tracking any stats for this object
this.recordStats = false;
}
public function recordConnectTime() : void {
this.connect_time = Math.round(getTimer() - this.start_time);
writeDebug('Connect took '+ this.connect_time + ' ms');
}
// Handle FMS bandwidth check callback.
// @see http://www.adobe.com/devnet/flashmediaserver/articles/dynamic_stream_switching_04.html
// @see http://www.johncblandii.com/index.php/2007/12/fms-a-quick-fix-for-missing-onbwdone-onfcsubscribe-etc.html
public function onBWDone() : void {
// writeDebug('onBWDone: called and ignored');
}
// NetStream client callback. Invoked when the song is complete.
public function onPlayStatus(info:Object):void {
writeDebug('onPlayStatus called with '+info);
switch(info.code) {
case "NetStream.Play.Complete":
writeDebug('Song has finished!');
break;
}
}
public function doIOError(e: IOErrorEvent) : void {
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onload", 0); // call onload, assume it failed.
// there was a connection drop, a loss of internet connection, or something else wrong. 404 error too.
}
public function doAsyncError(e: AsyncErrorEvent) : void {
writeDebug('asyncError: ' + e.text);
}
public function doNetStatus(e: NetStatusEvent) : void {
// Handle failures
if (e.info.code == "NetStream.Failed"
|| e.info.code == "NetStream.Play.FileStructureInvalid"
|| e.info.code == "NetStream.Play.StreamNotFound") {
this.lastNetStatus = e.info.code;
writeDebug('netStatusEvent: ' + e.info.code);
this.failed = true;
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onfailure", '', e.info.level, e.info.code);
return;
}
writeDebug('netStatusEvent: ' + e.info.code); // KJV we like to see all events
// When streaming, Stop is called when buffering stops, not when the stream is actually finished.
// @see http://www.actionscript.org/forums/archive/index.php3/t-159194.html
if (e.info.code == "NetStream.Play.Stop") {
if (!this.useNetstream) {
// finished playing
// this.didFinish = true; // will be reset via JS callback
this.didJustBeforeFinish = false; // reset
writeDebug('calling onfinish for a sound');
// reset the sound? Move back to position 0?
this.sm.checkProgress();
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onfinish");
}
} else if (e.info.code == "NetStream.Play.Start" || e.info.code == "NetStream.Buffer.Empty" || e.info.code == "NetStream.Buffer.Full") {
// First time buffer has filled. Print debugging output.
if (this.recordStats && !this.play_time) {
this.recordPlayTime();
}
// RTMP case..
// We wait for the buffer to fill up before pausing the just-loaded song because only if the
// buffer is full will the song continue to buffer until the user hits play.
if (this.serverUrl && e.info.code == "NetStream.Buffer.Full" && this.pauseOnBufferFull) {
this.ns.pause();
this.paused = true;
this.pauseOnBufferFull = false;
// Call pause in JS. This will call back to us to pause again, but
// that should be harmless.
writeDebug('Pausing song because buffer is full');
ExternalInterface.call(baseJSObject + "['" + this.sID + "'].pause", false);
}
// The buffer is full. Increase its size if possible.
// Double buffering has not been shown to cause false starts, so this is safe.
if (e.info.code == "NetStream.Buffer.Full") {
var next_buffer: int = this.getNextBuffer(this.ns.bufferTime);
if (next_buffer != this.ns.bufferTime) {
this.setBuffer(next_buffer);
}
}
var isNetstreamBuffering: Boolean = (e.info.code == "NetStream.Buffer.Empty" || e.info.code == "NetStream.Play.Start");
// assume buffering when we start playing, eg. initial load.
if (isNetstreamBuffering != this.lastValues.isBuffering) {
this.lastValues.isBuffering = isNetstreamBuffering;
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onbufferchange", this.lastValues.isBuffering ? 1 : 0);
}
// We can detect the end of the stream when Play.Stop is called followed by Buffer.Empty.
// However, if you pause and let the whole song buffer, Buffer.Flush is called followed by
// Buffer.Empty, so handle that case too.
//
// Ignore this event if we are more than 5 seconds from the end of the song.
if (e.info.code == "NetStream.Buffer.Empty" && (this.lastNetStatus == 'NetStream.Play.Stop' || this.lastNetStatus == 'NetStream.Buffer.Flush')) {
if (this.duration && (this.ns.time * 1000) < (this.duration - 5000)) {
writeDebug('Ignoring Buffer.Empty because this is too early to be the end of the stream! (sID: '+this.sID+', time: '+(this.ns.time*1000)+', duration: '+this.duration+')');
} else {
this.didJustBeforeFinish = false; // reset
this.finished = true;
writeDebug('calling onfinish for sound '+this.sID);
this.sm.checkProgress();
ExternalInterface.call(baseJSObject + "['" + this.sID + "']._onfinish");
}
} else if (e.info.code == "NetStream.Buffer.Empty") {
// The buffer is empty. Start from the smallest buffer again.
this.setBuffer(this.getStartBuffer());
}
}
// Remember the last NetStatus event
this.lastNetStatus = e.info.code;
}
// KJV The sound adds some of its own netstatus handlers so we don't need to do it here.
public function addNetstreamEvents() : void {
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, doAsyncError);
ns.addEventListener(NetStatusEvent.NET_STATUS, doNetStatus);
ns.addEventListener(IOErrorEvent.IO_ERROR, doIOError);
}
public function removeNetstreamEvents() : void {
ns.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, doAsyncError);
ns.removeEventListener(NetStatusEvent.NET_STATUS, doNetStatus);
ns.addEventListener(NetStatusEvent.NET_STATUS, dummyNetStatusHandler);
ns.removeEventListener(IOErrorEvent.IO_ERROR, doIOError);
// KJV Stop listening for NetConnection events on the sound
nc.removeEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
}
// Prevents possible 'Unhandled NetStatusEvent' condition if a sound is being
// destroyed and interacted with at the same time.
public function dummyNetStatusHandler(e: NetStatusEvent) : void {
// Don't do anything
}
}
}
|