Weird NetStream problem when using function - actionscript-3

This code causes my f4v file to stop playing prematurely. Time changes but roughly 8-10 seconds in.
loadSong();
function loadSong()
{
if(!songPlaying)
{
songPlaying = true;
var customClient:Object = new Object();
customClient.onCuePoint = cuePointHandler;
customClient.onMetaData = metaDataHandler;
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
ns.client = customClient;
ns.play("song.f4v");
}
trace("HERE");
}
function cuePointHandler(infoObject:Object):void{
trace(infoObject.name);
}
function metaDataHandler(infoObject:Object):void {
trace("metaData");
}
This code let's the f4v play till the end. WTF!? It seems that when I call it via a function it causes the issue. FYI the code is stored in the first frame of the main timeline, and the F4v is audio only. Any help would be appreciated.
if(!songPlaying)
{
songPlaying = true;
var customClient:Object = new Object();
customClient.onCuePoint = cuePointHandler;
customClient.onMetaData = metaDataHandler;
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
ns.client = customClient;
ns.play("song.f4v");
}

What is happening, when you declare your NetConection and NetStream inside the function, is that the scope for that variable is local to that function. That means that nothing else is referencing the NetConnection you created and thus the garbage collector sweeps it up during its next run (that's why you are seeing the variable time).
When you declare it in just an if statement the variables are in the scope of the movie and that holds a reference to them and thus aren't garbage collected.
I don't know what the architecture is for the rest of your code, but if you want to use functions to hold your code, try putting a declaration for the var nc:NetConnection = new NetConnection(); just before the loadSong(); statement.
Architecturally, you might want to refactor your code out of the frame, but it might really not be worth it, if it is just couple of lines of code. Just depends on your project.
For more information about garbage collection, check out Understanding garbage collection in Flash Player 9 (It's says Flash Player 9, but this is applicable to 10 as well).

Related

Audio stream reconnect in as3

I am using the following code in a swf created with Flash CS6:
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
var customClient:Object = new Object();
ns.client = customClient;
ns.play("http://streamserver3.us:7018/stream?type=.flv");
It plays an Icecast audio streaming.
How could I do to reconnect automatically (if the internet connection drops, etc.)?
Thank you very much for your help!
Sincerely.
See if any of these NetStreamInfo options can help you detect a connection drop:
Try using a timer that fires every two seconds where the responding function checks if there has been a change (ie: amount of incoming data has become zero).
Maybe check with ns.info.dataBytesPerSecond but explore the descriptions of other methods in that linked Info Class. Use an If statement to check input has not become zero or Else (if now zero) run your function that reconnects (does usual ns.stop(); & ns.play( url ); etc..).
Thank you very much for your help. I have found a solution that works and I would like to share:
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
var customClient:Object = new Object();
ns.client = customClient;
ns.play("http://xxxxxxxxx/stream?type=.flv");
ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
function netStatusHandler(event:NetStatusEvent):void
{
switch (event.info.code)
{
case 'NetStream.Play.Stop' :
MovieClip(this.root).gotoAndPlay(1, "Scene 2");
break;
case "NetStream.Play.StreamNotFound" :
MovieClip(this.root).gotoAndPlay(1, "Scene 2");
break;
}
}
I have created a new scene "Scene 2" with the following code:
MovieClip(this.root).gotoAndPlay(1, "Scene 1");
Now if the stream (internet or server connection) is lost, the player will reconnect automatically to the stream.
Working great!
Thank you very much for your ideas!
Regards

Flash SoundChannel limit and memory management

I have a program that I use as a recording platform, and for each sound I play I make a new Sound.
public function playAudioFile():void {
trace("audio file:", currentAudioFile);
sound = new Sound();
sound.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
sound.addEventListener(Event.COMPLETE, soundLoaded);
sound.load(new URLRequest(soundLocation + currentAudioFile));
}
public function soundLoaded(event:Event):void {
sound.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
sound.removeEventListener(Event.COMPLETE, soundLoaded);
var soundChannel:SoundChannel = new SoundChannel();
soundChannel = sound.play();
soundChannel.addEventListener(Event.SOUND_COMPLETE, handleSoundComplete);
trace('soundChannel?', soundChannel);
}
public function handleSoundComplete(event:Event):void {
var soundChannel:SoundChannel = event.target as SoundChannel;
soundChannel.stop();
soundChannel.removeEventListener(Event.SOUND_COMPLETE,handleSoundComplete);
soundChannel = null;
}
After 32 times, I stop getting a SoundChannel object when I call sound.play() (in soundLoaded). However, I don't need to have 32 SoundChannel objects because I play these sounds only serially and not at the same time. How can I get rid of the SoundChannel after I 'used' it to play a file?
You could be explicit about the soundChannel you use :
var soundChannel:SoundChannel = new SoundChannel();
soundChannel = sound.play();
soundChannel.addEventListener(Event.SOUND_COMPLETE,handleSoundComplete);
Then when you are done playing the sound, you can then set the channel to null so it will be marked for garbage collection :
function handleSoundComplete(e:Event):void
{
var soundChannel:SoundChannel = e.target as SoundChannel;
soundChannel.removeEventListener(Event.SOUND_COMPLETE,handleSoundComplete);
soundChannel = null;
}
Keep in mind that you need to remove those event listeners that you show in your code above, when the sound is done loading.
Also keep in mind that when you set something to null, that just sets it as fair game for garbage collection, it doesn't force garbage collection.
Another note is that this code I have posted is just an example, and you might want to think about having several sound channels instances that you keep active, and reuse as needed. Management is required in that case, but then you will not be constantly creating/killing sound channels.

as3 loop loading urls - continue loop on complete

I am trying to load a bunch of files in order. I want the other to start downloading once the previous has downloaded. I thought the best way to do this would be thru a for loop.
TheURL = is a bunch of urls in a ARRAY
for(var i:int=0;i<TheURL.length;i++)
{
var urlString:String = TheURL[i];
var urlReq:URLRequest = new URLRequest(urlString);
var urlStream:URLStream = new URLStream();
var fileData:ByteArray = new ByteArray();
urlStream.addEventListener(Event.COMPLETE, loaded);
urlStream.load(urlReq);
function loaded(event:Event):void
{
/// code to continue loop
}
}
It is important that the others do not start downloading until the previous has completed. Any suggestions on how to do that? Thanks
function downloadFiles():void
{
downloadNextFile();
}
function downloadNextFile():void
{
var urlString:String = TheURL.shift();
var urlReq:URLRequest = new URLRequest(urlString);
var urlStream:URLStream = new URLStream();
var fileData:ByteArray = new ByteArray();
urlStream.addEventListener(Event.COMPLETE, loaded);
urlStream.load(urlReq);
}
function loaded(event:Event):void
{
downloadNextFile();
}
Using a for-loop does not solve what you want to do.
In my opinion the easiest way should be to use the array of URLs as a queue. This can be done by using Array.shift(). But you should make a copy of your array if you need the original set of URLs when finished, because shift() makes an inline modification of the array.
The solution could be the following:
function loadQueue(urlQueue:Array):void
{
var url:String = urlQueue.shift();
var request:URLRequest = new URLRequest(url);
var stream:URLStream = new URLStream();
var data:ByteArray = new ByteArray();
var completeHandler:Function = function(event:Event)
{
// remove listener from stream to be a clean coder ;)
stream.removeEventListener(Event.COMPLETE, completeHandler);
// handle completion in the way you need ...
// continue with the next element
if (urlQueue.length > 0)
loadQueue(urls);
}
urlStream.addEventListener(Event.COMPLETE, loaded);
urlStream.load(urlReq);
}
Loading your queue will then look like:
loadQueue(TheURL.concat()); // concat() will clone your array
You should use a library like greensock LoaderMax http://www.greensock.com/loadermax/.
It's much more difficult than it seems to create your own loading queue. There are plenty of bugs, traps and special cases to deal with. It seems to work fine, and one day a customer call you back because of a bug on this particular flash version on this computer behind this firewall... I've started to do mine library, but finally I used LoadManager.

How i know if a Sound object is playing?

In AS3 i've created a code that load a sound and execute it in streaming.
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
mySound.load(new URLRequest("surrender.mp3"));
myChannel = mySound.play();
Considering that the mp3 file is placed on the server, i need to trace if it's already begun or still receiving initial data from the server. Once it's effectively started i've to call a function that initialize some things.
the problem is, how i can trace if a sound or channel object "is playing" ?
You can check this by listening for the different Events the Sound object dispatches as well as its properties like Sound.isBuffering
Refer to the Sound manpage
you could wait for the mp3 to be loaded completely
var myChannel:SoundChannel;
var soundFactory:Sound = new Sound();
soundFactory.addEventListener(Event.COMPLETE, completeHandler);
soundFactory.load(request);
// ...
private function completeHandler(event:Event):void {
trace("completeHandler: " + event);
myChannel = soundFactory.play();
}
or you can use a Timer and check the myChannel.position periodically - if it doesn't change the sound stopped playing...

Trouble with DataEvent.UPLOAD_COMPLETE_DATA not firing

I am having some trouble with an AS3 script to upload data to the server via PHP and then return some values from the PHP upload script. I am using the FileReference.upload() function, and the files are being successfully uploaded, but the eventListener I attached to the DataEvent.UPLOAD_COMPLETE_DATA event is not triggering. Is there something I can do on the PHP end of things to manually trigger this event when the file is done uploading?
as3:
private function onFileLoaded(event:Event):void {
//var _fileReference:FileReference = event.target as FileReference;
//var data:ByteArray = fileReference["data"];
//var filename:String = fileReference.name;
var urlRequest:URLRequest = new URLRequest("http://www.arttoframes.com/canvasSystems/uploadImage.php");
urlRequest.method = URLRequestMethod.POST;
fileReference.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, onUploadComplete);
fileReference.upload(urlRequest);
}
private function onFileLoadError(event:Event):void {
fileReference.removeEventListener(Event.COMPLETE, onFileLoaded);
fileReference.removeEventListener(IOErrorEvent.IO_ERROR, onFileLoadError);
}
private function onUploadComplete(event:Event):void {
trace("ok");
fileReference.removeEventListener(DataEvent.UPLOAD_COMPLETE_DATA,onUploadComplete);
var thumbReferenceName = fileReference.name.substr(0,fileReference.name.indexOf("."))+"_thumb"+fileReference.name.substr(fileReference.name.indexOf("."),4)+"?nocache=" + new Date().getTime()
var urlRequest:URLRequest = new URLRequest("http://www.arttoframes.com/canvasSystems/uploads/Thumbnails/"+thumbReferenceName);
var urlLoader:Loader = new Loader ();
urlLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onDownloadComplete);
//urlLoader.load(urlRequest);
}
So this is a long standing bug that Adobe claims they've fixed, but at least in Flex 3 lots of people claim they can reproduce it even after Adobe says they've fixed it. And that's including yours truly.
https://bugs.adobe.com/jira/browse/FP-1419
I'd employ a work around monitoring the progress directly and when all of it has uploaded manually dispatch the event or just do your work there. There are several work arounds you can try reading the comments in Jira.