as3 loop loading urls - continue loop on complete - actionscript-3

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.

Related

actionscript 3.0 function calling using button click

im creating a simple flash playlist using buttons, in my stage i have 4 buttons which is button for song1,song2, stop and play. i have a working code for this one, but i decided to revise it because my previous code is like, per song they have each stop and play button,so i created this one to have a dynamic stop and play, i created a function for each song, the function will change the filename of the song to be loaded,
heres the catch, so i first pick a song, (either song1 or song2) then i click stop, then when i select a new song this error appears
Error: Error #2037: Functions called in incorrect sequence, or earlier call was unsuccessful.
at flash.media::Sound/_load()
at flash.media::Sound/load()
at playlist_fla::MainTimeline/songSelect1()
i think its not calling the second function because i cant see the trace i put inside it,anyway heres my code, sorry for the long post,
THANKS IN ADVANCE
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
var myTransform = new SoundTransform();
var lastPosition:Number = 0;
var song;
song1.addEventListener(MouseEvent.CLICK,songSelect1);
function songSelect1(e:MouseEvent):void{
song = "<filenameofthe1stsong>";
mySound.load(new URLRequest(song));
myTransform.volume = 0.5;
myChannel.soundTransform = myTransform;
lastPosition=0;
trace(1);
}
song2.addEventListener(MouseEvent.CLICK,songSelect2);
function songSelect2(e:MouseEvent):void{
song = "<filenameofthe2ndsong>";
mySound.load(new URLRequest(song));
myTransform.volume = 0.5;
myChannel.soundTransform = myTransform;
lastPosition=0;
trace(2);
}
btnStop.addEventListener(MouseEvent.CLICK,onClickStop);
function onClickStop(e:MouseEvent):void{
lastPosition = myChannel.position;
myChannel.stop();
}
btnPlay.addEventListener(MouseEvent.CLICK,onClickPlay);
function onClickPlay(e:MouseEvent):void{
myChannel = mySound.play(lastPosition);
myChannel.soundTransform = myTransform();
}
Correction:
According to Adobe:
Once load() is called on a Sound object, you can't later load a
different sound file into that Sound object. To load a different sound
file, create a new Sound object.
So, creating a new sound object would be the only way to fix it.
- - - Original Post - - -
If you enable debugging in your flash settings, it'd be easier to determine exactly what line is causing issues. That said, your code doesn't look incorrect apart from defining your sound transform twice. Try this:
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
var myTransform = new SoundTransform();
myChannel.soundTransform = myTransform;
var lastPosition:Number = 0;
var song;
song1.addEventListener(MouseEvent.CLICK,songHandler);
song2.addEventListener(MouseEvent.CLICK,songHandler);
btnStop.addEventListener(MouseEvent.CLICK,onClickStop);
btnPlay.addEventListener(MouseEvent.CLICK,onClickPlay);
function songHandler(e:MouseEvent):void {
switch (e.currentTarget.name) {
case "song1":
songSelect("<filenameofthe1stsong>")
break;
case "song2":
songSelect("<filenameofthe2ndsong>")
break;
}
}
function songSelect(songPath:String):void {
mySound.load(new URLRequest(songPath));
myChannel.soundTransform.volume = 0.5;
lastPosition = 0;
trace("Loading " + songPath);
}
function onClickStop(e:MouseEvent):void {
lastPosition = myChannel.position;
myChannel.stop();
}
function onClickPlay(e:MouseEvent):void {
myChannel = mySound.play(lastPosition);
myChannel.soundTransform = myTransform();
}

What is wrong with my JPGEncoder

Here is my code
if (event.target.content is Bitmap)
{
infotext.text = "got something";
var image:Bitmap = Bitmap(event.target.content);
var bitmapData:BitmapData = image.bitmapData;
this.addChild(image);
var j:JPGEncoder = new JPGEncoder(100);
var bytes:ByteArray = new ByteArray();
bytes=j.encode(bitmapData);
}
else
{
throw new Error("What the heck bob?");
}
When I run a debug session everything works fine till it reaches to the line
bytes=j.encode(bitmapData);
after that nothing happens and my program just goes into limbo Please help
I made changes to the code as per your suggestion
var myImage:Bitmap =Bitmap(e.target.content);
var bitmapData:BitmapData = new BitmapData(myImage.width,myImage.height,true,0xffffffff);
bitmapData.draw(myImage);
var encoder:JPGEncoder = new JPGEncoder();
var bytes:ByteArray = encoder.encode(bitmapData);
this.addChild(myImage);
but it gets stuck again after
var bytes:ByteArray = encoder.encode(bitmapData);
What am i doing wrong here?
Pretty sure I ran into this same issue a long time ago so I pulled up my code from then that I got to work.
After reviewing the code the only thing I see different is I construct the bitMapData first and assign the image via the load function.
So I think your issue is with the construction of the bitmapData var.
The following code block was cut down from a function I created that did a lot of other image manipulation.
So basically it is a cut down version and untested but it should work.
var myImage:Image = new Image();
myImage.load( Bitmap(event.target.content) );
var bitmapData:BitmapData = new BitmapData(myImage.width, myImage.height, true, 0xffffffff );
bitmapData.draw(myImage);
var encoder:JPEGEncoder = new JPEGEncoder();
var data:ByteArray = encoder.encode(bitmapData);
this.addChild(myImage);
Just in case anyone runs into this, Make sure you are using the bytearray JPEGEncoder class, it's faster: http://www.bytearray.org/?p=775
the as3core is JPGEncoder not JPEGEncoder. JPG vs JPEG... this got me also.

AS3 - XML Playlist with Single-Track Looping

So this one has me stumped. My plan for my website is to have music tracks pulled from an XML file which act as the background music for the various .swfs loaded by the menu buttons. I.e. hit 'Home', and it takes you back to the home .swf and plays the appropriate music. I want to do this through XML rather than attaching the music directly to the .swf to cut down on load time (syncing isn't a concern), as I can't seem to retain audio quality without bulking up the .swf significantly.
I'm encountering two problems: one is that with the current code, the music only plays once, and doesn't loop. The other is that I want the functionality to play one song as an intro, and then continue to loop another. I.e., hit the home button, intro plays, followed by the looping section, and never returns to the intro unless you hit home again. I can't seem to figure out how to manage either of these things short of creating a unique function for every single button.
Here's the code I'm using:
var my_songs:XMLList;
var my_total:Number;
var my_sound:Sound;
var my_channel:SoundChannel;
var current_song:Number;
var myXMLLoader:URLLoader = new URLLoader();
myXMLLoader.load(new URLRequest("playlist.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void {
var myXML:XML = new XML(e.target.data);
my_songs = myXML.SONG;
my_total = my_songs.length();
//playSong(0);
myXMLLoader.removeEventListener(Event.COMPLETE, processXML);
myXMLLoader = null;
}
function playSong(mySong:Number):void {
var myURL = my_songs[mySong].#URL;
if (my_channel) {
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, playSong);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, playSong);
}
test_btn.addEventListener(MouseEvent.CLICK, onPlay);
function onPlay(e:MouseEvent):void {
playSong(0);
}
Thanks in advance for any help you can give!
YourSongstarting(0,999); // how ever you call to play the song
This above will repeat song forever. I suggest you stream the audio file as this will load the song quicker, then you can keep the songs in memory.you can still use xml or any other external textfile for the audio tracks locations or directly in flash/class files if this site is concrete.
any events you wold like to control simply compare the "Buffer" value out of 100%.Look up streaming audio as3 there are plenty of tutorials with source code if need be let me know i can give you an example.
You were close
var my_songs:XMLList;
var my_total:Number;
var my_sound:Sound;
var my_channel:SoundChannel;
var current_song:Number;
var myXMLLoader:URLLoader = new URLLoader();
myXMLLoader.load(new URLRequest("playlist.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void {
var myXML:XML = new XML(e.target.data);
my_songs = myXML.SONG;
my_total = my_songs.length();
playSong(0);
myXMLLoader.removeEventListener(Event.COMPLETE, processXML);
myXMLLoader = null;
}
function playSong(e:Event):void {
if( current_song > my_total )
current_song = 0;
var myURL = my_songs[current_song++].#URL;
if (my_channel) {
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, playSong);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, playSong);
}
test_btn.addEventListener(MouseEvent.CLICK, onPlay);
function onPlay(e:MouseEvent):void {
playSong(e);
}

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.

How can I use addEventListener and return something that's changed from it in Actionscript?

private function getTitle(src:String):String{
var urlLoader:URLLoader = new URLLoader();
var rssURLRequest:URLRequest = new URLRequest(src);
var rss:XML = new XML;
var t:String = src;
urlLoader.addEventListener(Event.COMPLETE,
function(event:Event):void{
rss = XML(urlLoader.data);
t = rss.channel.title.toString();
});
return t;
}
I'm aware that this code doesn't work because the anonymous function doesn't work until after t is returned. How would I make it so that it works?
You won't be able to return the loaded data from this method. The reason for this is because the loading is asynchronous and doesn't not block the execution of subsequent code. Your best option is to move the vars out of the scope of the function and to write a second function to handle the COMPLETE event.
Something like the following should work:
var rss:XML;
var t:String;
var path:String = "some path";
var urlLoader:URLLoader = new URLLoader();
private function getTitle(src:String):String
{
urlLoader.load( new URLRequest( src ) );
urlLoader.addEventListener(Event.COMPLETE, onComplete );
}
private function onComplete(event:Event):void
{
rss = XML(urlLoader.data);
t = path + rss.channel.title.toString();
}
I realize that this doesn't really answer the question directly, though it is the best practice for handling data loading. If you really want to stop any code from executing before the data is loaded, it may be possible use a while loop after the addEventListener line to halt the player from until the data is loaded. This should probably be considered a not so elegant hack though.
private function getTitle(src:String):String
{
var urlLoader:URLLoader = new URLLoader();
var rssURLRequest:URLRequest = new URLRequest(src);
var rss:XML = new XML;
var t:String = src;
var complete:Boolean;
urlLoader.addEventListener(Event.COMPLETE,
function(event:Event):void
{
rss = XML(urlLoader.data);
t = rss.channel.title.toString();
complete = true;
});
while( !complete ) { /* sleep hack */ }
return t;
}
I haven't tested this, but it seems like it could work. The first example is recommended.