I’m not getting onComplete events with media.playEventSound on Android.
Is this a known issue? [import]uid: 4596 topic_id: 9725 reply_id: 309725[/import]
I’m not getting onComplete events with media.playEventSound on Android.
Is this a known issue? [import]uid: 4596 topic_id: 9725 reply_id: 309725[/import]
Also on I Android occasionally I won’t get onComplete events with the Audio API, although it’s better, and only seems to occur if a lot of audio is played in rapid succession. [import]uid: 4596 topic_id: 9725 reply_id: 35449[/import]
enter a bug against it and i will track it internally
could be an injection -
what droid device are you using
c [import]uid: 24 topic_id: 9725 reply_id: 35451[/import]
I think I’m having the same issue on the simulator (version 2011.498 (2011.4.12)) on OSX. I’m not using the “playEventSound” function, but rather the traditional approach of loading an audio file, then calling “audio.play(handle)” function.
I’m developing a fancy audio engine that DEPENDS on “onComplete” callbacks to track what’s being played. As it stands, rapid playback of audio eventually causes some sounds to never call “onComplete” which completely cripples my engine (by flooding the queue with sounds that will never finish, eventually filling it up and not letting anything else through).
In some of my tests, this is even easier to reproduce when “fadein=0” is passed in as one of the play() parameters.
This is reproducible on an iPod Touch 4G and has the exact same behavior. I could potentially share the code to reproduce it (but privately).
I’m currently working on 2 titles and am anxious for some sort of solution to this issue. One of my apps is already on the market and I am wanting to update it as soon as I can. :S Just let me know if there’s anything else I can do to help out.
[import]uid: 23229 topic_id: 9725 reply_id: 37043[/import]
I am using an Iconia A500 tab and Nexus One. My suspicion is that the devices run out of audio channels and forces a used channel to end to play a new sound and does not send a complete event. [import]uid: 4596 topic_id: 9725 reply_id: 37304[/import]
From what I gather from the audio API’s in corona, it won’t play if there aren’t any free channels. It’ll return “0” for either audio.findFreeChannel() or audio.play(...)
, therefor it wouldn’t be forcing a used channel to end. At least this is what the documentation is saying, I really have no clue about the real cause.
In similar news, I’ve re-worked my audio engine so that it doesn’t depend on onComplete callbacks anymore, and is even more efficient because of it. If anyone is interested, this is a simple wrapper for the audio API calls that supports priority, tags (like “voice”, “sfx”, etc) that also allows you to mute all “voices” or all “music”. This is useful if you have 32 background sound effects playing, but you need music or a special sound effect to be heard no matter what. eg:
[blockcode]
– assume engine is setup…
for i=1,32 do
SE.play(‘backgroundthing’…i, {priority=math.random(1,5)})
end
– … some time later
SE.play(‘monstergrowl’, {priority=6})
[/blockcode]
In this example, trying to play “monstergrowl” will search all the currently playing audio samples and select one that is the lowest priority, and stop it. If there are more than one of the lowest priority, then it picks the oldest one and stops it. This frees up a channel for “monstergrowl” to play on.
“Sound objects” that are returned from the engine’s play() function. These sound objects give you easy access to .play(); .pause(); .fadeOut()
etc without having to maintain the audio handle, channel, etc. It behaves as such:
[blockcode]
local SE = SoundEngine.new()
SE.register(“bob”, {tag=‘sfx’, volume=0.6}) – “bob” gets translated to bob.caf or bob.m4a depending on what os you’re on
local bob = SE.play(‘bob’, {volume=0.9}) – temp. overwrite the default volume set above
bob.fadeOut(4000) – fade out over 4 seconds…
bob = nil
– These are also chainable:
SE.register(‘bob’).play(‘bob’).fadeOut(4000)
– Streams are also supported
SE.register(‘bgmusic’, {stream=true, tag=‘music’, volume=0.9, loop=-1})
– by default, streams are: tag=‘music’, loop=0, fadeIn=1000 but those are customizable
[/blockcode]
Anyone interested in using the engine? I’ve never really “given” up code before, but probably should soon considering I’ve used others’ free code. [import]uid: 23229 topic_id: 9725 reply_id: 37499[/import]
As mantic1 says, the audio engine does not force channels to end if you run out of free channels. We can’t know how to prioritize which channels to kill/reclaim in this case, so that is left for you to do. (Every app will have different rules about what sounds are more important.) The APIs return channel 0 telling you no channels are free or your audio could not be played.
The OnComplete callbacks should always fire. It was intended people might do exactly what you are doing to manage state so we understand getting these notifications are important. But you should verify that the audio you started playing actually started playing via the return value. Because no callback will happen for audio that is not played.
[import]uid: 7563 topic_id: 9725 reply_id: 37509[/import]
Thanks Mantic1 & Ewing! =) [import]uid: 4596 topic_id: 9725 reply_id: 37883[/import]
I’m now checking audio.play’s return value, and if it’s zero I don’t set .isPlaying to true. But I’m still encountering an issue where .isPlaying ends up reporting true, although the sound isn’t playing. I’ve attached a sound to each of the three touch event phases. Eventually the touch.ended sound will stop playing and isPlaying will read true. I’ve seen this on my Android device, and it also occurs in the simulator.
[code]
function Audio:Play()
if self.isPlaying ~= true then
self:_Play()
else
print( “isPlaying =”, self.isPlaying )
end
end
function Audio:_Play()
self.channel = audio.play( self.audio, {
onComplete=function(event)
self:_Ended(event)
end})
if( self.channel > 0 ) then
self.isPlaying = true
end
end
function Audio:_Ended( event )
self.isPlaying = false
end
[/code] [import]uid: 4596 topic_id: 9725 reply_id: 38092[/import]
Since self.isPlaying is your variable, I’m going to speculate you have a bug with your code somewhere, possibly related to how you are setting up your Lua “objects”. Make sure your self.isPlaying is a unique instance for every audio.play instance. Otherwise, for every audio onComplete callback, they will fight over sharing that same variable which could explain why you are not seeing the value you expect. Conversely, make sure you aren’t creating separate distinct self objects and referring to the wrong one at the wrong time which could also cause the behavior you see.
[import]uid: 7563 topic_id: 9725 reply_id: 38113[/import]
Yes, the Audio objects are unique instances. That’s the entirety of the Audio “objects” code except for the constructor.
Audio = class( function( self, url )
self.isPlaying = false
self.audio = audio.loadSound( url )
end)
Then the touch handler in main.lua.
local beganAudio = Audio( 'audio1.wav' )
local movedAudio = Audio( 'audio2.wav' )
local endedAudio = Audio( 'audio3.wav' )
display.getCurrentStage():addEventListener( 'touch', function(event)
if( 'began' == event.phase ) then
beganAudio:Play()
elseif( 'moved' == event.phase ) then
movedAudio:Play()
else
endedAudio:Play()
end
end)
Rapidly touching the screen will eventually result in an issue where endedAudio is stuck with self.IsPlaying reporting true, which leads me to believe there’s an issue with the onComplete callback not firing under certain conditions. [import]uid: 4596 topic_id: 9725 reply_id: 38140[/import]
Thanks for filing a formal bug report with reproducible example. We have traced down the problem to our Lua callback system which is one of the few components both our old and new audio system share.
We have just fixed this in the new audio system. ALmixer already has built-in mechanisms for callbacks and deals with multthreading and concurrency so we were able to leverage these things to provide a solution. The fix is in the next daily build (525).
We are still investigating the old audio system. It is less clear to us how we will fix this problem at the moment. (This is one of many reasons we are asking people to move to the new audio system.)
[import]uid: 7563 topic_id: 9725 reply_id: 38336[/import]
By the way, mantic1 and anybody building a management system on top of the new audio system, please note the 525 change log, excerpted here for convenience:
Additional note: It is possible for a channel to be reclaimed by ALmixer to be played on before the user receives the actual callback notification in Lua. This is not necessarily a bug and Corona will work correctly internally, but Lua users might be a little surprised by this. Anybody that builds a partial resource management system on top of our resource system may need to understand this. If they use auto-channel-assignment in play, but use callbacks to record channel availability, their system may get out-of-sync and break. So any user that implements a resource management system should also directly manage channel assignment. [import]uid: 7563 topic_id: 9725 reply_id: 38339[/import]
I probably should add that all the API functions like findFreeChannel and isChannelActive and so forth are internally consistent, so you could also build your management system to rely on those APIs.
[import]uid: 7563 topic_id: 9725 reply_id: 38340[/import]
The Daily Build resolved this issue for me where I am using the new audio API = )
http://developer.anscamobile.com/release/2011/525
The notes sound like I may continue experiencing this issue, but so far I’ve been unable to recreate the lost completion event.
If they use auto-channel-assignment in play, but use callbacks to record channel availability, their system may get out-of-sync and break. [import]uid: 4596 topic_id: 9725 reply_id: 38352[/import]
Great to hear it is working for you.
The issue itself is fixed for the new audio engine. But I was trying to explain a potential corner case that can be caused by a subtle detail that completion callbacks may fire slightly later than you might expect which could lead to bugs in your code (but is not necessarily a Corona bug). Here is an example case:
You call play() with a callback set. The system auto-assigns channel 1 to you.
You manually record in your own data structure that channel 1 is in use. (You plan to use the callback to reset the data structure to reflect that channel 1 is free.)
Corona finishes playing the first sound, but right as it does so, you call play() again on a new sound, and channel 1 gets auto-assigned again. But you have not yet received the callback notification, so your internal data structure says channel 1 is already in use. This is a contradiction in your code and is potentially confusing.
Channel 1 finally gets the callback. If you are not careful, you might mark channel 1 as free even though it is currently playing the new sound.
There are multiple ways to avoid this corner-case if you duplicate all the bookkeeping yourself. One way is to not use the built-in auto-channel assignment and you should manually control channel assignment based on your own free channel lists. Alternatively, you can directly query our APIs to find out if a channel is active/playing/free/etc which should get you the correct answer. [import]uid: 7563 topic_id: 9725 reply_id: 38360[/import]