Stop onComplete audio callback

I am daisy chaining audio files in Director so that when one finishes it charges the next with onComplete. This works well with the function below:

local playChain = function ()

        if (_G.autoPlay) == 1 then
            timerStash.timer_ns = timer.performWithDelay( 100, act_sc2, 1 )
        end
   end

audio.play( vars.Eng01, { channel=1, onComplete= playChain } )  

But when this page is disposed and another one opened before the end of the audio track, vars.Eng01 (15secs), the console reports errors getting nil values while attempting to call methods in act_sc2. But act_sc2 shouldn’t be called in the instance you turn the page before the audio track has finished playing (in this case before 15 seconds).

All works well without errors if you remove onComplete from the audio expression.

I guess onComplete needs to be stopped and disposed. The timer is disposed before the new scene opens but that’s not working.

How to dispose or stop onComplete? Or should the formula above be adapted somehow?

Hi @kilopop,

A similar issue was brought up last week by Daniela, another Corona developer using audio and scene management where the audio tracks might “overlap” into new scenes. In this case, because you’re changing scenes while an audio track is potentially still playing, I suggest that you build in some kind of audio management system at the core of your project (outside of Director scenes) which allows you to manage audio in that scope versus in the scene-specific scope. This way, you should be able to change scenes while a track is still playing, and maintain use of the “onComplete” functionality, just at the core level instead of within the scene.

Best of luck!

Brent

Hi Brent, thanks for the reply. Yes I have an audio management system which loads sounds for a scene into the vars table. The table is disposed with the cancelAllAudio function below. cancelAllAudio used to be in the required module mNav, I now moved it to main.lua which still hasn’t solved the problem with cancelling onComplete.

So audio loaded in scenes - page_1, page_2 etc.

Then audio disposed by cancelAllAudio() – calls function in main.lua

I have a half second before the scene changes. Before that cancelAllAudio is called - the audio stops but then act_sc2  starts (which you can see it do within that half second before the scene changes). And then again on the next scene (page_4) it is still running act_sc2 from page_3 as evidenced by the console reports of errors getting nil values while attempting to call methods in act_sc2 from the previous scene (page_3)

So clearly audio is being disposed from the vars table. It seems as soon as audio is disposed that suddenly onComplete charges.

Is there a way to cancel onComplete beyond disposing all audio?

------  Here is the code used in main, pages_ and mNav -----------

– Clear Audio function in main.lua

vars = {}

function cancelAllAudio()
print(“disposing audio”)
    audio.stop()
    audio.rewind()
    local k, v

    for k,v in pairs(vars) do
        audio.dispose(vars[k])
        vars[k]=nil
    end

    vars = nil
    vars = {}
end

– audio load in each scene - page_1, page_2 etc…

vars.Eng01 =  audio.loadSound( audioDir…“02Eng01.mp3”) – ch1
vars.Eng02 =  audio.loadSound( audioDir…“02Eng02.mp3”) – ch2
etc…
 

– mNav is a required module to handle scene changes - it calls cancelAllAudio.

– dispose calls a function to dispose timers and transitions.

function act_nxtPage (event)
    dispose()
    cancelAllAudio()
    local myClosure_switch = function()
        director:changeScene( “page_”…_G.thispge+1,“none”)
    end
    timerStash.newTimer_nf = timer.performWithDelay(500, myClosure_switch, 1)
end

Or you can simply do an audio.stop() on the channel that is currently playing before you call Director to change scenes.

Tried that - doesn’t work.

audio.stop(1)

onComplete still charges on the next page…

but just before you call audio.stop(), set the flag saying stop the chain and in the onComplete function test right away if you’re supposed to stop or not and only continue the chain if you are clear to continue.

Would you recommend setting a variable as a flag? It would need to be global in order to go from the required module mNav from the page_ scene.

So when scenes change there whould be something like _G.stopFlag = 1. Then in the onComplete function: if (_G.stopFlag == 1) then …

Like that?

It just needs to be local to the scene’s main chunk.  You would need one in each scene, but you could use a global.

Thanks Rob. That does work… although it would be better if onComplete didn’t initiate when the audio it is attached to gets disposed… Is there no other way to cancel onComplete callback besides using flags?

Hi @kilopop,

A similar issue was brought up last week by Daniela, another Corona developer using audio and scene management where the audio tracks might “overlap” into new scenes. In this case, because you’re changing scenes while an audio track is potentially still playing, I suggest that you build in some kind of audio management system at the core of your project (outside of Director scenes) which allows you to manage audio in that scope versus in the scene-specific scope. This way, you should be able to change scenes while a track is still playing, and maintain use of the “onComplete” functionality, just at the core level instead of within the scene.

Best of luck!

Brent

Hi Brent, thanks for the reply. Yes I have an audio management system which loads sounds for a scene into the vars table. The table is disposed with the cancelAllAudio function below. cancelAllAudio used to be in the required module mNav, I now moved it to main.lua which still hasn’t solved the problem with cancelling onComplete.

So audio loaded in scenes - page_1, page_2 etc.

Then audio disposed by cancelAllAudio() – calls function in main.lua

I have a half second before the scene changes. Before that cancelAllAudio is called - the audio stops but then act_sc2  starts (which you can see it do within that half second before the scene changes). And then again on the next scene (page_4) it is still running act_sc2 from page_3 as evidenced by the console reports of errors getting nil values while attempting to call methods in act_sc2 from the previous scene (page_3)

So clearly audio is being disposed from the vars table. It seems as soon as audio is disposed that suddenly onComplete charges.

Is there a way to cancel onComplete beyond disposing all audio?

------  Here is the code used in main, pages_ and mNav -----------

– Clear Audio function in main.lua

vars = {}

function cancelAllAudio()
print(“disposing audio”)
    audio.stop()
    audio.rewind()
    local k, v

    for k,v in pairs(vars) do
        audio.dispose(vars[k])
        vars[k]=nil
    end

    vars = nil
    vars = {}
end

– audio load in each scene - page_1, page_2 etc…

vars.Eng01 =  audio.loadSound( audioDir…“02Eng01.mp3”) – ch1
vars.Eng02 =  audio.loadSound( audioDir…“02Eng02.mp3”) – ch2
etc…
 

– mNav is a required module to handle scene changes - it calls cancelAllAudio.

– dispose calls a function to dispose timers and transitions.

function act_nxtPage (event)
    dispose()
    cancelAllAudio()
    local myClosure_switch = function()
        director:changeScene( “page_”…_G.thispge+1,“none”)
    end
    timerStash.newTimer_nf = timer.performWithDelay(500, myClosure_switch, 1)
end

Or you can simply do an audio.stop() on the channel that is currently playing before you call Director to change scenes.

Tried that - doesn’t work.

audio.stop(1)

onComplete still charges on the next page…

but just before you call audio.stop(), set the flag saying stop the chain and in the onComplete function test right away if you’re supposed to stop or not and only continue the chain if you are clear to continue.

Would you recommend setting a variable as a flag? It would need to be global in order to go from the required module mNav from the page_ scene.

So when scenes change there whould be something like _G.stopFlag = 1. Then in the onComplete function: if (_G.stopFlag == 1) then …

Like that?

It just needs to be local to the scene’s main chunk.  You would need one in each scene, but you could use a global.

Thanks Rob. That does work… although it would be better if onComplete didn’t initiate when the audio it is attached to gets disposed… Is there no other way to cancel onComplete callback besides using flags?

Hi Rob, we talked about this issue where onComplete within audio statements engages even when the audio that is set to play has been disposed. Your suggestion (which works) is to create a flag variable to check whether the audio had already been disposed. Obviously doing this flag check is more of a work around but this morning I read this in the 2013.1146 release notes of the Daily Build:

Core - fix various crashes associated with
disposing of audio streams; issue error messages when invalid (usually
previously disposed) streams are passed to various audio. APIs - fixes
casenum 24229 et al

Does this fix our wild onComplete issue?

I’m not sure and I’ve not tested it, but it sounds like that might take care of it.

In onComplete, try using the e.completed?

If the sound is stop by audio.stop() when the sound won’t finish playing the e.completed could return false.

If you don’t need to excecute the code in onComplete try using a code like:

audio.play(“test.mp3”,{channel = 1, onComplete =

function(e)

if e.completed then

–Somethingelse–
 

end

end})

Sorry if I was misunderstand.