美文网首页
关于Libgdx 在Android平台播放sound无声音的问题

关于Libgdx 在Android平台播放sound无声音的问题

作者: 贼噶人 | 来源:发表于2021-01-15 09:41 被阅读0次

    首先我们看下在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无声音的问题

          本文链接:https://www.haomeiwen.com/subject/zlyiaktx.html