关于Libgdx 在Android平台播放sound无声音的问题,修改AndroidAudio、AndroidSound源码来解决该问题。

首先我们看下在Android平台下Libgdx的sound的音效是通过SoundPool来实现播放的,下面是Android下的Audio的实现,我们可以看到SoundPool。从下面的代码可以看出,我们在使用sound时SoundPool会进行加载,但是其实异步的方式加载的,可能在使用时sound还未加载完成,导致立即使用可能会无声,所以我做了个优化用CountDownLatch来等待加载完成,所以我们如果使用AssetsManager来加载音效时,如碰到第一次加载无声,可能就是这个原因造成的,我们可以进同步等待,也可以将其放入到加载队列的头部让他优先加载。

public AndroidAudio(Context context, AndroidApplicationConfiguration config) {
        if (!config.disableAudio) {
            soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
            if (context instanceof GameActivity) {
                commonSoundPool = new SoundPool(3
                        , AudioManager.STREAM_MUSIC, 0);
            }
            manager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
            if (context instanceof Activity) {
                ((Activity) context).setVolumeControlStream(AudioManager.STREAM_MUSIC);
            }
        } else {
            soundPool = null;
            commonSoundPool = null;
            manager = null;
        }
    }

 /**
     * {@inheritDoc}
     */
    @Override
    public synchronized Sound newSound(FileHandle file) {
        if (soundPool == null) {
            throw new GdxRuntimeException("Android audio is not enabled by the application config.");
        }
        AndroidFileHandle aHandle = (AndroidFileHandle) file;
        if (aHandle.type() == FileType.Internal) {
            try {
                final AssetFileDescriptor descriptor = aHandle.getAssetFileDescriptor();
                final AndroidSound sound = new AndroidSound(soundPool, manager
                        , soundPool.load(descriptor, 1));
                descriptor.close();
                return sound;
            } catch (IOException ex) {
                throw new GdxRuntimeException("Error loading audio file: " + file
                        + "\nNote: Internal audio files must be placed in the assets directory.", ex);
            }
        } else {
            try {
                if (aHandle.file().getAbsolutePath().contains(File.separator + "common" + File.separator)) {
                    return new AndroidSound(null != commonSoundPool ? commonSoundPool : soundPool, manager
                            , (null != commonSoundPool ? commonSoundPool : soundPool).load(aHandle.file().getAbsolutePath()
                            , 1));
                } else {
                    if (Thread.currentThread().getName().equals("AsynchExecutor-Thread") && !( //判断是不是使用AssetsManager加载,如果是启动同步等待模式。
                            aHandle.file().getAbsolutePath().contains(File.separator + "p1" + File.separator)
                                    || aHandle.file().getAbsolutePath().contains(File.separator + "p2" + File.separator)
                                    || aHandle.file().getAbsolutePath().contains(File.separator + "p3" + File.separator)
                                    || aHandle.file().getAbsolutePath().contains(File.separator + "p4" + File.separator)
                                    || aHandle.file().getAbsolutePath().contains(File.separator + "p5" + File.separator)
                                    || aHandle.file().getAbsolutePath().contains(File.separator + "p6" + File.separator)
                                    || aHandle.file().getAbsolutePath().contains(File.separator + "p7" + File.separator))) {
                        final CountDownLatch latch = new CountDownLatch(1); 
                        soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
                            @Override
                            public void onLoadComplete(final SoundPool soundPool, final int sampleId, final int status) {
                                if (sampleId == AndroidAudio.this.sampleId) {
                                    latch.countDown(); 
                                }
                            }
                        });
                        sampleId = soundPool.load(aHandle.file().getAbsolutePath(), 1);
                        if (aHandle.file().getAbsolutePath().contains("g195")) {
                            latch.await(300, TimeUnit.MILLISECONDS);
                        } else {
                            latch.await(1500, TimeUnit.MILLISECONDS);
                        }
                        return new AndroidSound(soundPool, manager, sampleId);
                    } else {
                        sampleId = soundPool.load(aHandle.file().getAbsolutePath(), 1);
                        return new AndroidSound(soundPool, manager, sampleId);
                    }
                }
            } catch (Exception ex) {
                try {
                    if (!aHandle.file().exists()) {
                        final Intent intent = new Intent("com.mytian.game.exception");
                        MGardenApplication.instance.sendBroadcast(intent);
                    }
                } catch (Exception e) {

                }
                throw new GdxRuntimeException("Error loading audio file: " + file, ex);
            }
        }
    }

Libgdx在多次重复播放一个sound后会导致其他的sound播放失败,无声,看异常Log发现是AudioTrack创建失败导致播放失败,其实原因是系统能够创建的AudioTrack是有限的,而Libgdx播放完sound没有及时的释放其导致后面的sound无法创建。(IOS同理)

final class AndroidSound implements Sound {
    final SoundPool soundPool;
    final AudioManager manager;
    final int soundId;
    final IntArray streamIds = new IntArray(2); // 未修改前是8,导致同一个sound占用多个AudioTrack,你可以根据你的游戏业务控制这个参数的大小,做到播放完成后及时释放。

    AndroidSound(SoundPool pool, AudioManager manager, int soundId) {
        this.soundPool = pool;
        this.manager = manager;
        this.soundId = soundId;
    }

   @Override
    public long play(float volume) {
        if (streamIds.size == 2) { // 以前是==8时才会从里面释放sound,所以会导致一个sound有8个缓存的Audiotrack
            try {
                soundPool.stop(streamIds.pop());
            } catch (Exception e) {

            }
        }
        final int streamId = soundPool.play(soundId, volume, volume
                , 1, 0, 1);
        if (streamId == 0) return -1;
        streamIds.insert(0, streamId);
        return streamId;
    }

你可能感兴趣的:(关于Libgdx 在Android平台播放sound无声音的问题,修改AndroidAudio、AndroidSound源码来解决该问题。)