Audio disposal and errors

I found a related topic here http://forums.coronalabs.com/topic/40965-getting-an-audio-error-in-terminal-regarding-channel-0/, however it didn’t really answer my question so I figured I’d bring it up again.

I have 2 questions. My app has a main menu with background music. Then you can start a new game and I stop the background music and start game music. I have the menu music set to channel 10 and the in-game music set to channel 1. I also have a few other sounds (button clicks, error sounds, and victory music) that play.

So the first question I have is about disposing sounds. I obviously don’t want to use up a ton of memory, but I wasn’t sure if i needed to dispose of the sounds if they’re consistently being used. For instance, if I’m using button clicks on the main menu, then go into a new game where there are also buttons that make sounds, and an in-game menu that also has buttons, when should I dispose of these sounds? After every time they’re called, or just in between scenes?

What about the music? Both musics use LoadStream, and they’re set on loops for the appropriate pages they play on. When I exit the game, I do an audio.stop(1), but should I also nil it out and dispose it? Should I do the same for the main menu music?

The second part is related to the streaming music. I’ve been messing around with it and no matter how I set things, the same error occurs. When I load the game for the first time, the main menu music stops, the in-game music starts. Then if I leave the game, the music flips back over again like it should. When I re-enter the game again, the music does not start back up, but instead throws an error that the “Requested channel 0 is in use”. Is that because I did not dispose of things properly the first time?

I can post code sections if it helps. But I think my main issue is I wasn’t sure how/when to dispose of music and sounds if they’re being called up a lot.

So I’ve tried several different things to fix my issues and nothing has seemed to work. Some new issues that I figured I’d ask.

  1. I set my sounds/music variables to global in main so that transitioning from one scene to another would know what was going on. I tried disposing the music when I turn it off, but then I get “data is NULL” error turning it back on because it’s now undefined. Still not sure if I’m supposed to dispose of anything or when I’m supposed to do it. Also not sure now if I’m allowed to set these as global variables.

  2. Now that they’re global, doing audio.stop() doesn’t seem to actually stop the music, but instead puts it in the background. I’m getting errors about channel <0> being in use and “can’t stream shared sample because it’s already in use” when I toggle sounds off and on.

So I know something is wrong here, but not sure where to start looking. I feel that it is related to when I stop the music and it doesn’t stop, so it’s still technically playing. Thoughts? Again, I can post code sections, but I’d be helpful to know what is needed (variable declarations, toggle on/off for sounds, when I switch sounds, etc) Let me know what you need to help me, and I’ll post it.

So no one knows when to dispose of audio? Or if using global variables for sounds/music is okay?

I’ve done a few more things swapping things around and testing using channel numbers, audio handle, or nothing at all. Seems things work until I try to toggle sounds on/off. Doing it one way gives me the error about channel 0 being in use. Another way says data is null (I believe because it doesn’t know what that channel is anymore?). Another way works fine, mostly.

My only remaining problem I am running into now is I have a main menu sound options screen and an in-game sound options screen. If I pause the music on one options screen and then try to unpause it on the second screen, it plays the wrong music. Sometimes it doesn’t start back up at all. Sometimes it gives me the “can’t stream shared sample because it’s already in use”.  I’ve tried using audio.stops, I’ve tried using audio.pause/audio.resume. I’ve tried just about everything and nothing works.

So I’m hoping someone comes up with something on here or has an example of how to do sound toggle for apps (particularly when you have 2 screens that can toggle, and particularly when you have different songs that can play, like per level). At this point, anything would be useful.

Disposing audio is like any other memory management topic.  Audio takes up memory.  But it also takes time to read the file in and decode it.  There is a tradeoff and only you can decide what works best for you.  But from my personal experience, I would keep small sounds that get reused all the time (button clicks, beeps, bells, etc) in memory all the time.  Their memory footprint is small compared to the performance hit of constantly loading, decoding, playing and disposing. 

Now larger sounds that are maybe only used in specific scenes, like voice overs, you probably should load when you need them and dump them when you are done. 

Now on to your second issue…  The loading of a sound and retaining it in memory should have nothing to do with the error you’re getting about “requested channel 0 not available.”.  I think the first channel is channel 1.  Are you using a variable to hold the channel number?  Could it be getting set to 0?  Or a spelling error passing in a nil as the channel number?

I’m defining my main menu music as channel 10 and my game music as channel 4. I’ve used the examples from the corona docs so I shouldn’t have any misspellings. Because neither stopping, pausing, or any combination therein seemed to help, I decided to go the “volume” route.

So now I have both songs set to start upon launch. I immediately set the volume on channel 4 and 10 to 0 to make sure they don’t play. Then when I toggle sounds, I simply change the volume from 0 to 1.0 and that seems to work okay.

However, I still get back into the same problem of silencing the music on one menu page, then turning it back on through the second in-game menu page. It still for whatever reason turns the volume on for the wrong channel (10 instead of 4). Here is the relevant code:

I define them in main.lua:

\_G.backgroundMusic = audio.loadStream("AngryRobot.mp3") \_G.gameMusic = audio.loadStream("DST-Collidescope.mp3") \_G.musicOptions = { channel=4, loops=-1, } \_G.menuMusic = { channel=10, loops=-1, } audio.play(backgroundMusic, menuMusic) audio.play(gameMusic, musicOptions) audio.setVolume( 0.0, { channel=10 } ) audio.setVolume( 0.0, { channel=4 } )

And this is where my toggle fails to unsilence the right channel, in my gameOptions.lua file:

onMusicOnOffSwitchPress = function(event) local switch = event.target if (switch.isOn == false) then print("musicoff") profile.musicStatus = false audio.setVolume( 0.0, { channel=4 } ) audio.setVolume( 0.0, { channel=10 } ) elseif switch.isOn then print("musicon") profile.musicStatus = true audio.setVolume( 0.0, { channel=10 } ) audio.setVolume( 1.0, { channel=4 } ) end end

I went ahead and set the volume to 0 for channel 10 both times as a failsafe to make sure it doesn’t turn back on, but yet it continues to turn on instead of my channel 4.

So if you see a misspelling, or some syntax error that prevents this from working, let me know. Every line looks exactly the same in terms of syntax (I wasn’t sure about spaces and the like, so I referred to the corona docs for examples and followed them), so I’m not sure why it doesn’t work. Whether I’m doing play/pauses/resumes or volume, it trips up every time when it’s silenced from one menu and unsilenced in the other.

Hi @tjed110,

You may want to try reserving your channels, audio.reserveChannels( channels).

I had “Requested channel 0 is in use” error and reserving few channels help since the channels you want to use will not be “overwrite”.

But remember to release when no longer required.

Read the API doc for more info on how to use properly.

Good Luck!

burhan

Thanks Burhan, I tried that but it did not work either. I’ve managed to get rid of the various warnings with my current setup. The only real problem I have now is that when I toggle the sound off on one screen and turn it back on in the other, the wrong song starts up. The code from my in-game menu is above, and it clearly shows that whether the sound is on or off, the volume for the main menu music (channel 10) should be 0. Only the channel 4 sound should change. And yet, it continues to turn up the wrong one.

I am manually setting all my music channels so there should not be any automatic settings causing problems. I don’t believe loadSounds use channels so they shouldn’t be affecting this either, but I went ahead and left in the reserve channel code just in case someone else comes up with a fix.

I’m just wondering in your onMusicOnOffSwitchPress function,  how do you change the flag switch.isOn either true or false?

You may have change it somewhere in your code but i believe you have to set in the function itself?

onMusicOnOffSwitchPress = function(event) local switch = event.target if (switch.isOn == false) then print("musicoff") profile.musicStatus = false audio.setVolume( 0.0, { channel=4 } ) audio.setVolume( 0.0, { channel=10 } ) switch.isOn = true -- here elseif switch.isOn then print("musicon") profile.musicStatus = true audio.setVolume( 0.0, { channel=10 } ) audio.setVolume( 1.0, { channel=4 } ) switch.isOn = false -- and here end end

You may also want to save switch.isOn status to  external file and load them when start so the user do not have to switch on/off again.

Good Luck!

burhan

We have a profile file that takes care of that. In the code I posted above, we have profile.musicStatus that is set to either true or false to maintain that setting throughout the game. We also have a function profile.updateProfileSettings() that writes the profile status out to save it between playing the game.

I didn’t post all of that because it was working correctly and not necessarily relevant to the problem. The section you commented on (switch.isOn) simply shows the user a switch widget and either has it checked or unchecked, depending on whether it’s true or false.

Hi @tjed10,

I strongly suggest that you avoid global variables for this. They are ripe for creating problems and it may be why you’re having these issues.

Here are two tutorials on how to avoid them… the second one even focuses specifically on audio implementation:

http://coronalabs.com/blog/2013/05/28/tutorial-goodbye-globals/

http://coronalabs.com/blog/2013/06/04/tutorial-handling-cross-scene-audio/

Take care,

Brent

Well without using global variables, I found that when I toggled sound off, I got errors trying to turn it back on because it was not yet defined in that scene. So then I would define it but it would run into race conditions and cause other errors (like already streaming errors). However, as global variables, I found that I still don’t know when to dispose of them because they become undefined. Doing local variables allowed me to dispose of them between scenes but redefine them in the next.

And while the tutorials are handy (wish I found it before I reworked my variables to global and before I put in about 80 “if sound on, play sound”), they don’t specifically address streaming sounds. It mentions disposing of sounds, but not streams, so it still doesn’t really answer my question of when to dispose of streams (if ever…or simply when you close out of the app or no longer need the song again, like if you beat level 1 and no longer need level 1’s song).

I will say that global variables have simplified my code and caused my errors/warnings to go away. With locally defined variables I got 1 of 4 errors when I began turning sounds on or off or switched scenes. Now the only problem is toggling sound sometimes plays the wrong song.

The “Goodbye Globals” should show you a technique for creating a globally available table of values that don’t occupy global space.  They allow you to have a local access to them.  In fact some people call that table globals (which is fine), as long as you’re not using _G or having variables that are not part of a table or local to the chunk you’re working in.

Rob

So I’ve tried several different things to fix my issues and nothing has seemed to work. Some new issues that I figured I’d ask.

  1. I set my sounds/music variables to global in main so that transitioning from one scene to another would know what was going on. I tried disposing the music when I turn it off, but then I get “data is NULL” error turning it back on because it’s now undefined. Still not sure if I’m supposed to dispose of anything or when I’m supposed to do it. Also not sure now if I’m allowed to set these as global variables.

  2. Now that they’re global, doing audio.stop() doesn’t seem to actually stop the music, but instead puts it in the background. I’m getting errors about channel <0> being in use and “can’t stream shared sample because it’s already in use” when I toggle sounds off and on.

So I know something is wrong here, but not sure where to start looking. I feel that it is related to when I stop the music and it doesn’t stop, so it’s still technically playing. Thoughts? Again, I can post code sections, but I’d be helpful to know what is needed (variable declarations, toggle on/off for sounds, when I switch sounds, etc) Let me know what you need to help me, and I’ll post it.

So no one knows when to dispose of audio? Or if using global variables for sounds/music is okay?

I’ve done a few more things swapping things around and testing using channel numbers, audio handle, or nothing at all. Seems things work until I try to toggle sounds on/off. Doing it one way gives me the error about channel 0 being in use. Another way says data is null (I believe because it doesn’t know what that channel is anymore?). Another way works fine, mostly.

My only remaining problem I am running into now is I have a main menu sound options screen and an in-game sound options screen. If I pause the music on one options screen and then try to unpause it on the second screen, it plays the wrong music. Sometimes it doesn’t start back up at all. Sometimes it gives me the “can’t stream shared sample because it’s already in use”.  I’ve tried using audio.stops, I’ve tried using audio.pause/audio.resume. I’ve tried just about everything and nothing works.

So I’m hoping someone comes up with something on here or has an example of how to do sound toggle for apps (particularly when you have 2 screens that can toggle, and particularly when you have different songs that can play, like per level). At this point, anything would be useful.

Disposing audio is like any other memory management topic.  Audio takes up memory.  But it also takes time to read the file in and decode it.  There is a tradeoff and only you can decide what works best for you.  But from my personal experience, I would keep small sounds that get reused all the time (button clicks, beeps, bells, etc) in memory all the time.  Their memory footprint is small compared to the performance hit of constantly loading, decoding, playing and disposing. 

Now larger sounds that are maybe only used in specific scenes, like voice overs, you probably should load when you need them and dump them when you are done. 

Now on to your second issue…  The loading of a sound and retaining it in memory should have nothing to do with the error you’re getting about “requested channel 0 not available.”.  I think the first channel is channel 1.  Are you using a variable to hold the channel number?  Could it be getting set to 0?  Or a spelling error passing in a nil as the channel number?

I’m defining my main menu music as channel 10 and my game music as channel 4. I’ve used the examples from the corona docs so I shouldn’t have any misspellings. Because neither stopping, pausing, or any combination therein seemed to help, I decided to go the “volume” route.

So now I have both songs set to start upon launch. I immediately set the volume on channel 4 and 10 to 0 to make sure they don’t play. Then when I toggle sounds, I simply change the volume from 0 to 1.0 and that seems to work okay.

However, I still get back into the same problem of silencing the music on one menu page, then turning it back on through the second in-game menu page. It still for whatever reason turns the volume on for the wrong channel (10 instead of 4). Here is the relevant code:

I define them in main.lua:

\_G.backgroundMusic = audio.loadStream("AngryRobot.mp3") \_G.gameMusic = audio.loadStream("DST-Collidescope.mp3") \_G.musicOptions = { channel=4, loops=-1, } \_G.menuMusic = { channel=10, loops=-1, } audio.play(backgroundMusic, menuMusic) audio.play(gameMusic, musicOptions) audio.setVolume( 0.0, { channel=10 } ) audio.setVolume( 0.0, { channel=4 } )

And this is where my toggle fails to unsilence the right channel, in my gameOptions.lua file:

onMusicOnOffSwitchPress = function(event) local switch = event.target if (switch.isOn == false) then print("musicoff") profile.musicStatus = false audio.setVolume( 0.0, { channel=4 } ) audio.setVolume( 0.0, { channel=10 } ) elseif switch.isOn then print("musicon") profile.musicStatus = true audio.setVolume( 0.0, { channel=10 } ) audio.setVolume( 1.0, { channel=4 } ) end end

I went ahead and set the volume to 0 for channel 10 both times as a failsafe to make sure it doesn’t turn back on, but yet it continues to turn on instead of my channel 4.

So if you see a misspelling, or some syntax error that prevents this from working, let me know. Every line looks exactly the same in terms of syntax (I wasn’t sure about spaces and the like, so I referred to the corona docs for examples and followed them), so I’m not sure why it doesn’t work. Whether I’m doing play/pauses/resumes or volume, it trips up every time when it’s silenced from one menu and unsilenced in the other.

Hi @tjed110,

You may want to try reserving your channels, audio.reserveChannels( channels).

I had “Requested channel 0 is in use” error and reserving few channels help since the channels you want to use will not be “overwrite”.

But remember to release when no longer required.

Read the API doc for more info on how to use properly.

Good Luck!

burhan

Thanks Burhan, I tried that but it did not work either. I’ve managed to get rid of the various warnings with my current setup. The only real problem I have now is that when I toggle the sound off on one screen and turn it back on in the other, the wrong song starts up. The code from my in-game menu is above, and it clearly shows that whether the sound is on or off, the volume for the main menu music (channel 10) should be 0. Only the channel 4 sound should change. And yet, it continues to turn up the wrong one.

I am manually setting all my music channels so there should not be any automatic settings causing problems. I don’t believe loadSounds use channels so they shouldn’t be affecting this either, but I went ahead and left in the reserve channel code just in case someone else comes up with a fix.

I’m just wondering in your onMusicOnOffSwitchPress function,  how do you change the flag switch.isOn either true or false?

You may have change it somewhere in your code but i believe you have to set in the function itself?

onMusicOnOffSwitchPress = function(event) local switch = event.target if (switch.isOn == false) then print("musicoff") profile.musicStatus = false audio.setVolume( 0.0, { channel=4 } ) audio.setVolume( 0.0, { channel=10 } ) switch.isOn = true -- here elseif switch.isOn then print("musicon") profile.musicStatus = true audio.setVolume( 0.0, { channel=10 } ) audio.setVolume( 1.0, { channel=4 } ) switch.isOn = false -- and here end end

You may also want to save switch.isOn status to  external file and load them when start so the user do not have to switch on/off again.

Good Luck!

burhan

We have a profile file that takes care of that. In the code I posted above, we have profile.musicStatus that is set to either true or false to maintain that setting throughout the game. We also have a function profile.updateProfileSettings() that writes the profile status out to save it between playing the game.

I didn’t post all of that because it was working correctly and not necessarily relevant to the problem. The section you commented on (switch.isOn) simply shows the user a switch widget and either has it checked or unchecked, depending on whether it’s true or false.