Android - sounds are buggy, stop playing midway, play only on random occasions when invoked

Interesting, this works fine for both the desktop and Android?

Do you know why that fixes audio issue? Doesn’t that have to do with GC?

Current OpenAL garbage collection might be problematic in some cases because

  1. If you don’t store ALSource to a variable, it may get deleted even if it’s still in use. You can avoid this issue by storing it to somewhere, but that may defeat the purpose as it prevents GC. This might be still useful for deleting sources that finished playing, though.
  2. ALBuffer may get deleted first, but this will fail if there is a ALSource that still reference it, and cause memory leaks.
  3. Storing GC value to a global variable is not compatible with hxcpp’s moving garbage collector. This is not enabled by default though.

I think you might be right as, after about 20mins of game-play the sounds start lagging behind.

singmajesty: Yes works for both (but with the above issue, of course)

so how should I change the code above to have proper GC. To be honest I don’t know much about memory leaks or openAl

Do you think it is garbage collection related?

This is simple to test – keep a reference for the SoundChannel after you play it

private var soundChannels = new Array<SoundChannel> ();

...

soundChannels.push (sound.play ());

You can see that we use something similar to your AudioSource snippet inside sound.play

https://github.com/openfl/openfl/blob/develop/openfl/media/Sound.hx#L139-L150

Is the issue that on complete fires too soon?

https://github.com/openfl/openfl/blob/develop/openfl/media/SoundChannel.hx#L160-L167

When I do this:

public static var soundChannels:Array<SoundChannel>; ...


public static function play(name:String) {
	
	soundChannels.push(Assets.getSound(name+EXTENSION).play());
}

The sound still only plays sometimes, not all times when it shoud - on android.

Looks like there is a limit on number of OpenAL sources you can create. With default configuration you can create 256 sources on openal-soft. (alGenSources() returns error after creating 256 sources)
Adding OpenAL source to array will help in solving premature collection issue, but you will end up maxing out number of sources if you don’t delete them at all.

There is also a limit on number of sources you can play simultaneously. (32 on Android?)


Perhaps we need to “fake play” sounds at some point – I think in Flash Player (I could be wrong?) the sound behaves like it’s audible, but it isn’t, if too many sounds are playing. I forget if active sounds become audible as older ones finish, or if the newer sound just remains inaudible

I think we should delete stopped sources immediately with alDeleteSources() because we don’t know when GC occurs, and users may keep reference to AudioSource. Even in such case audio should still work at some degree.

I’m not sure if it’s still meaningful to have dispose method on AudioSource if we do that.

Also, it would be helpful for debugging if Lime/OpenFL could print out OpenAL errors with flags. Currently it just ignores OpenAL errors.

I’ve also tried setting ALSOFT_LOGLEVEL to 3, but this didn’t print errors with alGenSourcesor alSourcePlay.

Complete events are invoked with timers, but I’m not sure if it’s very accurate because it does not take latency into account.

Maybe issue is not in garbage collection? You could accidentally delete sources if you use lime AudioSource directly, but that probably doesn’t happen if it’s used via OpenFL implementation. SoundChannel adds itself to list when it’s created, and disposes containing AudioSource when it has finished playing.

Memory leak issue I described above only occurs with OpenAL buffers. That doesn’t cause severe issues unless you allocate lots of buffers and let GC delete them.

Or onComplete event is triggered too soon for some reason? In that case I think you could insert some code that checks if audio is still playing. (AL.getSourcei(source, AL.SOURCE_STATE))

So I also re-included a long background music (added using openfl.Assets.getMusic ) that now should loop infinitely using SOUND_COMPLETE event. It works fine on flash, but on android it plays for 3 second then stops. SOUND_COMPLETE event is not fired at this point though.
Furthermore, however, after the approximate length of the music (although it is not really playing) SOUND_COMPLETE is fired, then the music restarts, and after 3 seconds nothing, and so on …

I just made a change to limit the number of active sound channels to 32, we can visit this later if we want to consider more on different platforms, but I found that Flash Player returns null on sound.play if 32 are already playing

Perhaps buffering the whole background sound is too large, and only by streaming smaller buffer sizes can it work… at least on Android. I’m not sure. We should get streaming sound in place either way

Is your game getting too slow to play? If so, could you share profiling result?

http://hxscout.com

I’m not sure if sound length has to do with this problem either. Does that really cause slowdown? It should work on windows at least.

Do we have problems in wav/ogg loader? Maybe unrelated, since it hasn’t changed a lot since openfl 4.1.

When I try to test my game with this command:
haxelib run lime test android -Dtelemetry

I get the following error:
./src/hxtelemetry/CppHxTelemetry.cpp:233: error: return-statement with no value, in function returning ‘Void’

I think HxScout is only compatible with HXCPP 3.2.x, not 3.3.x

No, I got it to run eventually: hxtelemetry issue

Here is a profiling result, near the end it the animations start to stutter.
profilling

I saw that many objects are created in the process of event dispatching and animation with actuate library, but does that cause audio issues?
Do you get the same result with older OpenFL?

Garbage collection may take longer because of many small garbage. But does mixer thread pause because of that?

for long music, the result was worse with the older openfl versions. The music doesn’t really pause, it’s just as if it’s mute, until you tell it to play again.

Also, from the profiling, do you have any advice to optimize my code for performance?