Why might audio.play not play and return 0?

Hi, I currently have a program with a little radio. If I tap on the radio when it’s off (or turning off), static sfx occurs and at the end of the static audio music plays. If I tap the radio when it’s on (or turning on), then the music stops and static sfx occurs.

I’m currently having an issue when I turn the radio off then back on quickly. Sometimes the music doesn’t play. After looking further into this I noticed that in those circumstances where the radio wasn’t playing… audio.play returned 0. 

Why might audio.play not play a sound and instead return 0?  I’m usually never using more than like 4 or so channels.

In case it might help pinpoint the problem… my code:

local function stopChannel(key) print("Trying to stop channel: " .. key .. ": " .. tostring(channelTable[key])) if channelTable[key] and channelTable[key] \> -1 then audio.stop(channelTable[key]) print("Stopped channel: " .. key .. ": " .. tostring(channelTable[key])) end channelTable[key] = -1 end local function activate() if not radioObj then return; end if radioObj.state == "turnOff" or radioObj.state == "off" then print("Radio: Turn On") -- Audio audio.pause(channelTable["background"]); radioObj.state = "turnOn" stopChannel("radio") channelTable["radio"] = audio.play(soundTable["radioStatic"], { onComplete = function(e) if e.completed then print("Radio: On") -- 1. State radioObj.state = "on"; petObj.hasDanced = false; -- 2. Audio stopChannel("radio") channelTable["radio"] = audio.play(soundTable["radioMusic"], {loops = -1}) -- THIS IS RETURNING ZERO SOMETIMES print("Playing Radio Music on channel: " .. channelTable["radio"]) end end }) print("Playing Radio Static on channel: " .. channelTable["radio"]) radioObj:bounce({minXScale = 0.98}) elseif radioObj.state == "turnOn" or radioObj.state == "on" then print("Radio: Turn Off") -- 1. State radioObj.state = "turnOff"; -- 2. Animate radioObj:stopAfterBounce(); -- 3. Audio stopChannel("radio") channelTable["radio"] = audio.play(soundTable["radioStatic"], { onComplete = function(e) if e.completed then print("Radio: Off") stopChannel("radio") audio.resume(channelTable["background"]); radioObj.state = "off" end end }) end end

Thank you very much!

0 is returned if the sound could not be played, else it returns the channel #.  It’s possible that you’re stopping and trying to play so fast that things are not having time to clear out.  You might want to try and put the play inside of a timer.pefrormWithDelay(50, function() audio.play(…); end) call to give the stop time to finish.

Rob

0 is returned if the sound could not be played, else it returns the channel #.  It’s possible that you’re stopping and trying to play so fast that things are not having time to clear out.  You might want to try and put the play inside of a timer.pefrormWithDelay(50, function() audio.play(…); end) call to give the stop time to finish.

Rob

For the record, submitted a bug report for this ( Case 43279:  Audio Bug: audio.play, audio.stop and audio.isChannelActive not working properly).

I’ve attached the code and an image of the report here in case anyone is interested in taking a look at it.

Hi @jhow,

I haven’t tested or deeply inspected your code, but at a glance, my impression is that you’re trying to “over-engineer” your audio code and you’re trying to do “too much” in terms of explicitly controlling, pausing, stopping, playing, and using onComplete listeners in a way that is mucking up the audio engine. In most cases, you should just let the audio engine handle some internals by itself, and let channels end/clear or get selected by the OpenAL engine, instead of trying to forcibly micro-manage every channel and its state.

Brent

Hi Brent,

Did you look at the code in Audio Bug.zip? It’s extremely different from the code in the first posting, which is old. And I would highly disagree with you in that the code in the Audio Bug.zip is over engineered. 

It’s in fact very simple. When I want to reset a sound, I stop it on it’s channel and I play it, which isn’t anything to complex.

The extra code is in there to help highlight the problem.

Hi @jhow,

Apologies, I was looking at the old code. So in regards to the code in “Audio Bug.zip”:

  1. In testing in both the Simulator and on my iPhone 6S, I could only get the issue to occur occasionally, like once in 50-100 extremely rapid taps on the button. So you’re correct that it occurs, but not consistently.

  2. Wrapping the “play” portion (say, lines 115-130 in your code) within a function and then triggering it with a very short timer of about 10 milliseconds seems to prevent the problem entirely. That seems to prevent the audio engine from getting mucked up with dozens of consecutive, rapid, “stop then immediately play on the same channel” calls. Can you try this and see if you can manage to reproduce the issue?

Best regards,

Brent

Hi again Brent,

Thank you for suggesting an idea on how to address this. I put the code (located in the began phase of the touchHandler) within a function. Then I set a timer to 10ms to call the function. Unfortunately, the issue still occurs. 

Regarding your suggestion that this issue occurs “occasionally, but not consistently”, I hope such a statement is not an indicator that you believe this to be a non-issue. I can replicate it pretty easily and the issue comes up often in our app… Sometimes sounds just don’t play when they’re supposed to, which reduces the overall quality of our app. I hope you agree that occasionally or not, this just flat out should not happen (and probably should not require use of a timer). I can assure you that this issue occurs quite regularly in normal audio practices (not just when mashing buttons). The button to mash was just the best easy demonstration I could provide.

From my understanding, this would appear to be an issue with something going on under Corona’s hood. Do you happen to have an idea on when you guys will take a look at the bug report to address the issue?

Hi @jhow,

Well I acknowledge it’s an issue, but I’m not sure it’s something we can even control. For example, the physics engine (internally) does not allow certain properties or functions to be applied in the same frame/timestep as a collision, and that is simply something we cannot control, even within the core. The audio engine is equally complex (if not more) under the hood, with buffering and channel management and all kinds of other things.

In my suggestion of using a timer (just like you would need to with the physics engine call-after-collision-frame APIs), did you try to wrap just the “play” portion in a function? I didn’t mean to simply surround the entire contents of the touch handler function in another child function… that is merely doing the same entire process after a delay. Instead, try to separate the part where it stops and plays by a short delay.

If you can reproduce it even in that case, let me know. Before I added a “timer wrap”, I was only able to reproduce your issue by mashing the button in fast sequence. After I added the timer, I wasn’t able to reproduce the issue even with rapidly mashing the button ~100 times. In any case, test it out and report the results.

Best regards,

Brent

For the record, submitted a bug report for this ( Case 43279:  Audio Bug: audio.play, audio.stop and audio.isChannelActive not working properly).

I’ve attached the code and an image of the report here in case anyone is interested in taking a look at it.

Hi @jhow,

I haven’t tested or deeply inspected your code, but at a glance, my impression is that you’re trying to “over-engineer” your audio code and you’re trying to do “too much” in terms of explicitly controlling, pausing, stopping, playing, and using onComplete listeners in a way that is mucking up the audio engine. In most cases, you should just let the audio engine handle some internals by itself, and let channels end/clear or get selected by the OpenAL engine, instead of trying to forcibly micro-manage every channel and its state.

Brent

Hi Brent,

Did you look at the code in Audio Bug.zip? It’s extremely different from the code in the first posting, which is old. And I would highly disagree with you in that the code in the Audio Bug.zip is over engineered. 

It’s in fact very simple. When I want to reset a sound, I stop it on it’s channel and I play it, which isn’t anything to complex.

The extra code is in there to help highlight the problem.

Hi @jhow,

Apologies, I was looking at the old code. So in regards to the code in “Audio Bug.zip”:

  1. In testing in both the Simulator and on my iPhone 6S, I could only get the issue to occur occasionally, like once in 50-100 extremely rapid taps on the button. So you’re correct that it occurs, but not consistently.

  2. Wrapping the “play” portion (say, lines 115-130 in your code) within a function and then triggering it with a very short timer of about 10 milliseconds seems to prevent the problem entirely. That seems to prevent the audio engine from getting mucked up with dozens of consecutive, rapid, “stop then immediately play on the same channel” calls. Can you try this and see if you can manage to reproduce the issue?

Best regards,

Brent

Hi again Brent,

Thank you for suggesting an idea on how to address this. I put the code (located in the began phase of the touchHandler) within a function. Then I set a timer to 10ms to call the function. Unfortunately, the issue still occurs. 

Regarding your suggestion that this issue occurs “occasionally, but not consistently”, I hope such a statement is not an indicator that you believe this to be a non-issue. I can replicate it pretty easily and the issue comes up often in our app… Sometimes sounds just don’t play when they’re supposed to, which reduces the overall quality of our app. I hope you agree that occasionally or not, this just flat out should not happen (and probably should not require use of a timer). I can assure you that this issue occurs quite regularly in normal audio practices (not just when mashing buttons). The button to mash was just the best easy demonstration I could provide.

From my understanding, this would appear to be an issue with something going on under Corona’s hood. Do you happen to have an idea on when you guys will take a look at the bug report to address the issue?

Hi @jhow,

Well I acknowledge it’s an issue, but I’m not sure it’s something we can even control. For example, the physics engine (internally) does not allow certain properties or functions to be applied in the same frame/timestep as a collision, and that is simply something we cannot control, even within the core. The audio engine is equally complex (if not more) under the hood, with buffering and channel management and all kinds of other things.

In my suggestion of using a timer (just like you would need to with the physics engine call-after-collision-frame APIs), did you try to wrap just the “play” portion in a function? I didn’t mean to simply surround the entire contents of the touch handler function in another child function… that is merely doing the same entire process after a delay. Instead, try to separate the part where it stops and plays by a short delay.

If you can reproduce it even in that case, let me know. Before I added a “timer wrap”, I was only able to reproduce your issue by mashing the button in fast sequence. After I added the timer, I wasn’t able to reproduce the issue even with rapidly mashing the button ~100 times. In any case, test it out and report the results.

Best regards,

Brent