Flash SoundChannel limit and memory management - actionscript-3

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.

Related

actionScript3 ENTER_FRAME Event is not working

I am trying to to use the ENTER_FRAME Event on playing audio ,but the code is not executing the handler function.
public function play_mp3(path:String,path1:String):void {
var snd:Sound = new Sound();
snd.load(new URLRequest(path), new SoundLoaderContext());
channel = snd.play();
addEventListener(Event.ENTER_FRAME,myFunction);}
public function myFunction(e:Event){
LogFB.info('test1234'); }
You're issue is likely that the class whose code you've posted, is not on the display tree. (it's not a display object or hasn't been added to the stage).
If it's not on the display tree, then ENTER_FRAME will not dispatch on it.
You can get around this a few ways.
Pass into the class a reference to something that is on the stage (or the stage itself). Then add the ENTER_FRAME listener on that object.
var stage:Stage;
public function MyClass(stage_:Stage){
stage = stage_;
}
....
stage.addEventListener(Event.ENTER_FRAME, myFunction);
Forgo ENTER_FRAME, and just use a Timer
var timer:Timer
public function play_mp3(path:String,path1:String):void {
var snd:Sound = new Sound();
snd.load(new URLRequest(path), new SoundLoaderContext());
channel = snd.play();
timer = new Timer(250); //tick every quarter second
timer.addEventListener(TimerEvent.TIMER, myFunction);
timer.start();
}
public function myFunction(e:Event){
LogFB.info('test1234');
}
Your problem is in LogFB.
Try this and you will see the trace from inside the function...
var channel : SoundChannel = new SoundChannel();
function play_mp3(path:String,path1:String):void {
var snd:Sound = new Sound();
snd.load(new URLRequest(path), new SoundLoaderContext());
channel = snd.play();
addEventListener(Event.ENTER_FRAME,myFunction);
}
function myFunction(e:Event){
//LogFB.info('test1234'); here is the problem
// trace("is working!");
hi();
}
play_mp3('aasa','aaa');
function hi() {
trace("goooooddddd!"); //is working, I am using Flash CC
}
All the best!
there doesnt seem any error try this one
public function play_mp3(path:String,path1:String):void {
addEventListener(Event.ENTER_FRAME,myFunction);
var snd:Sound = new Sound();
snd.load(new URLRequest(path), new SoundLoaderContext());
channel = snd.play();
}
public function myFunction(e:Event){
LogFB.info('test1234'); }
ie put the enterframe event the first thing that hapen in your code to check if at least it initialise it?

AS3 Code - Sound not playing

I'm trying to play sound in as3 code using an external mp3 file.
So here's the code I am using:
private function playSound():void
{
trace("loading sound");
var mySound:Sound = new Sound();
mySound.addEventListener(IOErrorEvent.IO_ERROR, handleIOError);
mySound.load(new URLRequest("Menu.mp3"));
mySound.play();
trace("playing sound");
}
private function handleIOError(evt:IOErrorEvent):void
{
//handle error if needed
}
The music just doesn't play at all.
The traces "loading sound" and "playing sound" appear so the code is being run.
The mp3 file Menu.mp3 is in the same folder as the .fla file used to run the project. Is this the correct directory? I tried moving it around but still couldnt play the sound.
Any help will be appreciated, thanks!
I have a few suggestions that might help:
Declare mySound as a class level property. The garbage collector might be disposing of the variable prematurely since it is local.
mySound.play() returns a SoundChannel object. Try storing this in a class level property.
Add an event listener to the sound for Event.COMPLETE, right before loading the sound. Try playing the sound after this event occurs. As it is, you might be trying to play the sound before it has loaded.
private var mySound:Sound;
private var mySoundChannel:SoundChannel;
private function playSound():void
{
mySound = new Sound();
mySound.addEventListener(IOErrorEvent.IO_ERROR, handleIOError);
mySound.addEventListener(Event.COMPLETE, handleLoadCompletion);
mySound.load(new URLRequest("Menu.mp3"));
}
private function handleLoadCompletion(evt:Event):void
{
mySoundChannel = mySound.play();
}
private function handleIOError(evt:IOErrorEvent):void
{
//handle error if needed
}
Edit:
After reviewing the docs, I think that suggestion 3 isn't necessary.

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...

Weird NetStream problem when using function

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).

Recyclable Sound Object in Actionscript 3?

Using ONE Sound() object in Actionscript3, how can I play a one MP3 and then, when the user chooses a different one, play a second sound, using the SAME Sound() object?
EDIT: See my answer for how I did it.
You cannot use same Sound object to play multiple files.
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.
Ok, I actually did it using the following code. My bug was somewhere else in the FLA file, but this works. I made an uninitialized global variable and created the Sound() object LOCALLY inside of a function. While I'm technically using multiple sound objects, my references are all pointing to ONE object. Additionally, I can call these methods over one another for easier coding. This works for me:
/* -------------
Sound player
functions
------------ */
var snd:Sound; //the sound object
var sndC:SoundChannel; //the soudchannel used as "controller"
var sndT:SoundTransform; //soundTransform used for volume
var vol:Number = 1; //the volume of the song
var pan:Number = 0; //panning of the sound
var pos:Number = 0; //position of the song
var currentSound:String; //currently playing song?
function playSound(s:String){ //this function resets the sound and plays it
stopSound(sndC); //stop the sound from playing
snd = new Sound(); //reset the sound
snd.load(new URLRequest(s)); //load the desired sound
sndC = new SoundChannel(); //(re-)apply the sound channel
applyVolume(vol,pan,sndT,sndC); //apply the volume
sndC = snd.play(pos); //play it
sndC.addEventListener(Event.SOUND_COMPLETE, startSound); //remind it to restart playing when it's done
} //end function
function applyVolume(n:Number, p:Number, st:SoundTransform, sc:SoundChannel){ //takes an argument for the volume, pan, soundTYransform and soundChannel
sndT = new SoundTransform(n,p); //applies the soundTransfrom settings
sndC.soundTransform = sndT; //and attaches it to the soundChannel
} //end function
function stopSound(sndC:SoundChannel){ //this function stops a sound from playing
if(sndC != null){ //if the sound was used before (ie: playing)
if(currentLabel == "video-frame"){ //if we are in the video frame
pos = sndC.position; //store the position of the song to play from at a later time
}else{ //otherwise
pos = 0; //set the position at 0
} //end if
sndC.stop(); //stop it
} //end if
} //end function
function startSound(snd:Sound){ //restarts a sound when it's playing
if(snd != null){ //if the sound exists
sndC = snd.play(pos); //play it
} //end if
} //end function