audiolibgdxsoundpoolaudiotrackaudioflinger

LibGDX: AudioFlinger could not create track, status -12


I've recently added sounds into my LibGDX game. It's set up so that all the sounds I need are loaded into an AssetManager, and I retrieve them when I need to play them from a getSound(String name) method.

It works fine for a little bit when you play, but eventually it stops playing some, and sometimes most of them. I'd be fine with prioritizing the ones that are most recently played, and stopping the ones that are older if need be, but LibGDX doesn't seem to give you that much control over them.

The log error I get when this happens E/AudioTrack: AudioFlinger could not create track, status: -12 E/SoundPool: Error creating AudioTrack.

It's usually playing quite a few at one time, probably around 10-20 small sounds at one time, depending on the situation, so I'm pretty sure that's the problem. I've read here about releasing a sound once it's played using a SoundPool, but I'm not entirely sure how to do that with LibGDX, or if it's possible, because I didn't see a class like that when I looked.

Also, I'm using ogg files for all of the sounds and none of them are very big. Thanks!


Solution

  • Solved! By creating my own (kind of pseudo) Sound class, and a loader for it to be used with an AssetManager using assetManager.setLoader(). In the custom Sound class, I set every sound to keep track of their soundIds in an Array<Long>, then every time it plays I check the size of the array against a limit variable, stopping the oldest sound in the array. 0 meaning only able to be played one at a time, up to as far as I decide is necessary. This might not be a perfect solution, but it seems to work fairly well.

    Criticism is welcome.

    My created "Sound" class:

    public class MySound {
    
        private Sound sound;
        private Array<Long> ids;
        private int limit;
    
        public MySound(Sound sound) {
            this.sound = sound;
            ids = new Array<Long>();
            limit = 0;
        }
    
        public long play() {
            limitSounds();
            long id = sound.play();
            ids.add(id);
    
            return id;
        }
    
        public long play(float volume) {
            limitSounds();
            long id = sound.play(volume);
            ids.add(id);
    
            return id;
        }
    
        public long play(float volume, float pitch, float pan) {
            limitSounds();
            long id = sound.play(volume, pitch, pan);
            ids.add(id);
    
            return id;
        }
    
        public long loop() {
            limitSounds();
            long id = sound.loop();
            ids.add(id);
    
            return id;
        }
    
        public long loop(float volume) {
            limitSounds();
            long id = sound.loop(volume);
            ids.add(id);
    
            return id;
        }
    
        public long loop(float volume, float pitch, float pan) {
            limitSounds();
            long id = sound.loop(volume, pitch, pan);
            ids.add(id);
    
            return id;
        }
    
        public void stop() {
            ids.clear();
            sound.stop();
        }
    
        public void pause() {
            sound.pause();
        }
    
        public void resume() {
            sound.resume();
        }
    
        public void dispose() {
            sound.dispose();
        }
    
        public void stop(long soundId) {
            if (ids.contains(soundId, true)) {
                ids.removeValue(soundId, true);
            }
            sound.stop(soundId);
        }
    
        public void pause(long soundId) {
            sound.pause(soundId);
        }
    
        public void resume(long soundId) {
            sound.resume(soundId);
        }
    
        public void setLooping(long soundId, boolean looping) {
            sound.setLooping(soundId, looping);
        }
    
        public void setPitch(long soundId, float pitch) {
            sound.setPitch(soundId, pitch);
        }
    
        public void setVolume(long soundId, float volume) {
            sound.setVolume(soundId, volume);
        }
    
        public void setPan(long soundId, float pan, float volume) {
            sound.setPan(soundId, pan, volume);
        }
    
        private void limitSounds () {
            if (ids.size > limit) {
                sound.stop(ids.get(0));
                ids.removeIndex(0);
            }
        }
    
        public void setLimit (int limit) {
            this.limit = limit;
        }
    }
    

    MySoundLoader class, for AssetManager:

    public class MySoundLoader extends AsynchronousAssetLoader<MySound, MySoundLoader.SoundParameter> {
    
        private MySound sound;
    
        public MySoundLoader(FileHandleResolver resolver) {
            super(resolver);
        }
    
        @Override
        public Array<AssetDescriptor> getDependencies(String fileName, FileHandle file, SoundParameter parameter) {
            return null;
        }
    
        @Override
        public void loadAsync(AssetManager manager, String fileName, FileHandle file, SoundParameter parameter) {
            sound = new MySound(Gdx.audio.newSound(file));
        }
    
        @Override
        public MySound loadSync(AssetManager manager, String fileName, FileHandle file, SoundParameter parameter) {
            MySound sound = this.sound;
            this.sound = null;
            return sound;
        }
    
        static public class SoundParameter extends AssetLoaderParameters<MySound> {
        }
    }