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

本文探讨了在Android平台上使用Libgdx的SoundPool进行音效播放时可能出现的问题,即由于SoundPool异步加载可能导致音效无声。为了解决这个问题,作者采用了CountDownLatch来确保音效加载完成后再进行播放。同时,注意到Libgdx在重复播放同一音效后可能会影响其他音效的播放,原因是系统AudioTrack资源限制。为避免这个问题,作者调整了内存管理,减少了AudioTrack的占用。此外,还提供了一个AndroidSound类实现,用于更有效地管理和播放声音。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先我们看下在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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值