【问题标题】:How to play sounds at accurate periods of time across different devices in Android如何在 Android 的不同设备上以准确的时间段播放声音
【发布时间】:2013-10-01 08:49:01
【问题描述】:

我正在使用 Android 开发游戏,但遇到了一个非常烦人且难以发现的错误。问题是当您使用SoundPool 播放声音时,您实际上可以循环播放您正在播放的任何声音。在这种情况下,问题是“运行步骤”的声音;当主角运行时,这个声音会非常快速且持续地执行(大约每个400ms)。

现在在常规(不是那么强大)设备上播放声音时,例如三星 SII,每隔500ms 播放一次声音 - 但是,如果我在另一台设备(比如三星 SIV、三星 SIII)上运行相同的代码,声音播放速度会快两倍甚至三倍。

似乎设备硬件规格越强大,播放速度就越快。在某些设备上,它的播放速度非常快,您几乎可以听到一种连续的声音。我一直在寻找在声音播放之间设置特定比例的技术,但它不能正常工作并且问题仍然存在。有谁知道如何修复它,或者使用SoundPoolMediaPlayer 或 Android 上的任何其他声音控制 API?

【问题讨论】:

  • 您找到解决方案了吗?如果是,请分享!
  • 还没找呢,如果你+1这个问题也许更多人会关注它...
  • 我不能多次投票
  • 你可以在一个runnable里面放一个非循环的声音,并设置runnable在一个特定的时间间隔运行。这篇文章解释一下:blog.nelsondev.net/?p=207
  • 一种肮脏的方法是让你的声音变长(添加填充)然后循环播放

标签: android soundpool


【解决方案1】:

我在开发使用声音之类的应用程序时遇到了很多问题。我不建议您使用 SoundPool,因为它会受到 bug 的影响,并且还要注意,使用 SoundPool 循环声音在 4.3 及更高版本的设备上不起作用,请参阅this open issue, at AOSP - Issue tracker。 我认为解决方案是原生并使用 OpenSL ES o 类似的库。

【讨论】:

    【解决方案2】:

    如果问题是您想控制离散声音之间的间隔,最简单的方法是使用处理程序。

    基本上,您开始播放声音,这是一个异步过程。然后,您使用处理程序安排消息在未来某个时间播放下一个声音。需要一些试验和错误才能使其正确,但可以保证声音会在每台设备上的前一​​个声音之后的相同间隔开始。

    这里有一些代码来说明我在说什么。

    这是您可以使用的处理程序实现:

        handler = new Handler() {
    
            /* (non-Javadoc)
             * @see android.os.Handler#handleMessage(android.os.Message)
             */
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == NEXT_ITEM_MSG) {
                    playNextSound();
                }
                else if (msg.what == SEQUENCE_COMPLETE_MSG) {
                    // notify a listener
                    listener.onSoundComplete()
                }
            }
        };
    

    那么你可以这样写 playNextSound:

    private void playNextSound() {
        if (mRunning) {
            // Get the first item
            SoundSequenceItem item = currentSequence.getNextSequenceItem();
            if (item == null) {
                Message msg = handler.obtainMessage(SEQUENCE_COMPLETE_MSG);
                handler.sendMessage(msg);
                return;
            }
            // Play the sound
            int iSoundResId = item.getSoundResId();
            if (iSoundResId != -1) {
                player.playSoundNow(soundResId);
            }
    
            // schedule a message to advance to next item after duration
            Message msg = handler.obtainMessage(NEXT_ITEM_MSG);
            handler.sendMessageDelayed(msg, item.getDuration());
        }
    }
    

    您的 SoundSequenceItem 可能只是一个简单的类,它具有声音文件资源 ID 和持续时间。如果您想在角色移动时继续播放声音,您可以执行以下操作:

    public void onSoundComplete() {
        if (character.isRunning()) {
            currentSequence.addSequenceItem(new SoundSequenceItem(R.id.footsteps,500);
            playNextSound();
        }
    }
    

    或者您可以修改 playNextSound 以连续播放相同的声音。我是这样写的,以便能够按顺序播放不同的声音。

    【讨论】:

    • 我已经考虑过几种手动执行的方法,例如 ThreadPools/Scheduler/Monitor 甚至处理程序,但是我正在寻找一个本地调用作为答案,手动执行不会是问题我只是在寻找 API 中存在的东西
    【解决方案3】:

    我似乎无法在 Galaxy Nexus 和 Nexus S 上复制该问题,这是否意味着我已解决?或者,也许您可​​以展示您正在做的与此不同的事情:

    SoundPool soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100);
    Integer sound1 = soundPool.load(this, R.raw.file1, 1);
    Integer sound2 = soundPool.load(this, R.raw.file2, 1);
    playSound(sound1);
    
    public void playSound(int sound) {
      AudioManager mgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
      float volume = mgr.getStreamVolume(AudioManager.STREAM_MUSIC)
                   / mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);  
      soundPool.play(sound, volume, volume, 1, -1, 1.0f);
    }
    

    【讨论】:

    • 没什么,我就是这么做的,用旧设备测试,你会发现一个声音和另一个声音之间的差距很大,彼此之间会有更大的延迟,这与我的代码完全相同...
    【解决方案4】:

    仅循环播放或使用固定间隔播放诸如脚步声之类的内容的问题在于,您可能会将声音和视觉效果解耦。如果您的声音延迟或加速,或者您的视觉效果延迟或加速,您将不得不动态地自动调整该延迟。你已经有这个问题了

    更好的解决方案是在应该触发声音的确切事件上放置一个触发器(在这种情况下,脚被放下),然后播放声音。这也意味着,如果您有多个声音来源(例如多个脚步声),您不必手动以正确的间隔开始声音。

    【讨论】:

    • 这种方法有很大的差距,因为每次我想要一个声音“例如自动枪”时,并非所有情况都可以计算一个事件,是一个触发事件,并且声音必须循环在特定的时间间隔直到手指从枪中释放出来......
    • 如果你有自动枪的声音,那么循环会更好,是的,但除非你做自动跑步游戏或神秘风格的冒险游戏,否则循环声音是个坏主意。最好将它与脚步声联系起来,因为这样声音总是与脚步声耦合。我没说要一直循环播放。
    【解决方案5】:

    您可以使用AudioTrack 播放连续的 PCM 数据流,因为您会传递一个流,您可以确定声音之间的间隔。缺点可能是第一次启动声音时会有一点延迟,但这取决于最小缓冲区大小,我认为这取决于 android 版本和设备。在我的 Galaxy s2 android 4.1 上大约是 20 毫秒。
    如果您认为这可能是一个选项,我可以发布一些代码

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多