当收集苹果时,使用sound.play()会导致libgdx出现延迟。

5

我正在开发一个简单的libgdx游戏。当我使用sound.play()时,出现了卡顿(游戏停顿0.5秒)。 编辑:这个bug只出现在Android 4.0上,在2.3上一切正常。

我是用以下代码播放音乐的:

if(CollisionDetector.detect(touchArea, hoodie.getTouchArea())){
        GameScreen.totalScore++;
        setPosition();
        System.out.println("played");

        Assets.eatSound.play();

}

我使用以下方法来加载音频:

 static long waitForLoadCompleted(Sound sound,float volume) {
        long id;
        while ((id = sound.play(volume)) == -1) {
            long t = TimeUtils.nanoTime();
            while (TimeUtils.nanoTime() - t < 100000000);
        }
        return id;
 }

我做错了什么?或者我该怎么解决这个延迟问题?

编辑:

我刚刚尝试使用sound.play()线程,但也没有用:

    new Thread(new Runnable() {
           @Override
           public void run() {
              // do something important here, asynchronously to the rendering thread

              // post a Runnable to the rendering thread that processes the result
              Gdx.app.postRunnable(new Runnable() {
                 @Override
                 public void run() {
                    // process the result, e.g. add it to an Array<Result> field of the ApplicationListener.
                eatSound2.play();
                 }
              });
           }
        }).start();

我的音频资源类看起来像这样,但是我仍然有声音延迟的问题。 package com.redHoodie;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.utils.Disposable;

public class SoundEffect implements Disposable {
   private static final int WaitLimit = 1000;
   private static final int ThrottleMs = 100;
    Sound eatSound;
    Sound endSound;

    public SoundEffect(){
        eatSound = Gdx.audio.newSound(Gdx.files.internal("eatSound.ogg"));
        endSound = Gdx.audio.newSound(Gdx.files.internal("sadend.wav"));

        checkedPlay(eatSound);
    }

   protected long checkedPlay (Sound sound) {
      return checkedPlay(sound, 1);
   }

   protected long checkedLoop (Sound sound) {
      return checkedLoop(sound, 1);
   }

   protected long checkedPlay (Sound sound, float volume) {
      int waitCounter = 0;
      long soundId = 0;

      boolean ready = false;
      while (!ready && waitCounter < WaitLimit) {
         soundId = sound.play(volume);
         ready = (soundId != 0);
         waitCounter++;
         try {
            Thread.sleep(ThrottleMs);
         } catch (InterruptedException e) {
         }
      }

      return soundId;
   }

   protected long checkedLoop (Sound sound, float volume) {
      int waitCounter = 0;
      long soundId = 0;

      boolean ready = false;
      while (!ready && waitCounter < WaitLimit) {
         soundId = sound.loop(volume);
         ready = (soundId != 0);
         waitCounter++;
         try {
            Thread.sleep(ThrottleMs);
         } catch (InterruptedException e) {
         }
      }

      return soundId;
   }

@Override
public void dispose() {
    // TODO Auto-generated method stub

}
}

我的声音变量是静态的,这可能导致我的程序出现延迟吗? - peterSweter
你的资产类是什么样子的?你是否每次想播放声音时都重新加载它?我不理解你的waitForLoadCompleted方法——你是否在进行某种异步加载? - Tenfour04
我在我的GameScreen的构造函数中只加载一次声音。我在互联网上发现,使用0音量播放声音可能有助于加载此声音,这就是为什么我使用waitForLoadCompleted的原因。 - peterSweter
在 logCat 中,我得到了“示例5未准备好”的信息。 - peterSweter
但是你在什么时候调用waitForLoadCompleted函数呢?是在加载音频后的唯一时间吗? - Tenfour04
我在创建SoundEffect类并拥有我的声音后,调用此函数一次。 - peterSweter
4个回答

7

我曾经遇到过同样的问题。原因是我的.mp3文件太短了,只有0.167秒。我使用Audacity添加了1.2秒的静音,问题得以解决。


1
我的游戏加入了更多的声音后,卡顿问题变得更加严重。尝试给每个声音样本添加1秒的静默时间,但没有起到作用。:( 在电脑上运行很流畅,但在手机上(SD 855,6GB RAM,Android 10)会出现卡顿。LibGDX 明显存在一些声音问题。:( - MilanG
最初我使用了22Khz的wav pcm样本来节省内存。但是后来尝试了44100、48000Hz,还尝试在结尾添加了两秒的静音。但都没有起到作用。我认为只有LibGDX(或甚至是Android)的声音系统不够好,无法像PC一样同时处理几乎相同数量的样本。唯一的解决方案就是不幸地减少播放的声音数量。 - MilanG
我也尝试了各种方法,比如更改比特率,使用不同的文件扩展名(如wav、mp3、flac等),但不幸的是这些都没有帮助。经过数月的搜寻,你的解决方案帮助我解决了这个问题。我认为重要的部分是在文件中将音量降低,因此你可能还需要延长采样时间(我使用了Ableton Live)。我唯一能够测试的实际手机是摩托罗拉G5 Plus。这可能是因为该手机保持了音频流或线程或其他一些开放状态。非常感谢,应该为其他人更容易找到而进行点赞。 - Timothy

0

如果有人像我一样仍然遇到这个问题,那么有一种替代解决方案,但有一个限制:无法使用声音ID选项。

您可以更改默认的LibGDX行为,并通过在您的AndroidLauncher类中覆盖此方法来使用AsynchronousAndroidAudio

@Override
public AndroidAudio createAudio(Context context, AndroidApplicationConfiguration config) {
    return new AsynchronousAndroidAudio(context, config);
}

查看官方文档以获取更多信息,同时也可以查看拉取请求

此外,如果您需要声音ID,您可以将此实现作为示例,并找到解决方案适用于您的项目。

从LibGDX 1.9.12开始提供修复。


0
当我尝试制作一个节奏游戏并想要播放一些特效音效时,我遇到了同样的问题。因此,我尝试使用AsynchronousAndroidAudio来解决它。然而,AsynchronousAndroidAudio似乎引起了更多的问题,比如声音延迟。最后,我使用了OpenSL ES,它在改善性能方面表现良好(在我那款2016年生产的老设备上)。但是,我只写了一些简单的功能,更糟糕的是,所有的声音文件都需要转换为PCM格式,除非导入一个解码器。尽管如此,它满足了我的需求(这些声音很小,所以我直接将它们加载到内存中,而且这些声音不需要ID,甚至可以暂停)。 (我的英语不太好)

0
最近我遇到了相同的问题(除了我使用的是wav而不是mp3文件)。当我同时播放许多(如10或20)个声音时(相同的渲染方法),我的应用程序会出现延迟。通过一次只播放一个声音来“解决”这个问题。通常很难在同时听到许多声音。在桌面上它可以正常工作,但在Android(9或8)上出现问题。

有点晚了,但是试着扩展你的样本,并在样本结束前降低音量。我有Ableton Live,但你也可以使用免费的Audacity。 - Timothy
也尝试过了。我认为这个问题可能无法解决:https://stackoverflow.com/questions/59022221/sound-makes-app-lags-on-android-any-solution - MilanG
我制作了一个更智能的声音管理系统,为声音设置了一些优先级,并且同时只播放2或3个声音。 - MilanG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接