为什么我的 SoundPool 声音第一次在 Android 上无法播放?

发布于 2024-12-20 11:03:39 字数 1212 浏览 2 评论 0原文

我在 Android 上播放 Ogg Vorbis 声音时遇到了一个奇怪的问题,我很难纠正该问题。我正在使用 SoundPool 类来播放声音。除了我在暂停后播放的第一个声音之外,它的效果很好。

这是我遇到的问题:我有一个菜单,上面有几个按钮。如果我按下按钮,我会发出滴答声。然而,我第一次尝试演奏时,它没有发出声音。然后,如果我再次点击相同的菜单按钮,它就会起作用。如果我将下一次按键延迟几秒钟,问题就会再次出现。具体来说,我看到以下行为:

  • 等待几秒钟
  • 触摸 UI 按钮,该按钮应该发出声音...它不会
  • 记录 cat 报告“AudioFlinger:写入阻塞 165 毫秒,66 次延迟写入,线程 0xec40”(当我触摸 UI 按钮)
  • 等待几秒钟
  • log cat 报告“AudioHardwareQSD:AudioHardware pcm 播放将进入待机状态”
  • 触摸应该发出声音的 UI 按钮...但没有。
  • logcat 报告“AudioFlinger:写入被阻止 166 毫秒,67 个延迟写入,线程 0xec40”(当我触摸 UI 按钮时立即发生)
  • 再次触摸 UI 按钮,但在出现 AudioHardwareQSD 待机消息之前...声音作品!

我在几种不同的设备上看到过这种行为:HTC Incredible、root Nook Color 和 HTC Thunderbolt,所以我不认为这是特定于设备的。

我猜这是 AudioHardwareQSD 进入待机状态的一个功能。一旦进入待机状态,滑槽发出的第一个声音就会被忽略,而后续的声音会一直工作,直到再次进入待机状态。我的 HTC Incredible 上的“写入被阻止”消息和 AudioHardwareQSD 消息之间大约有 3 秒的延迟。

StackOverflow 上有一个答案,讨论使用 WakeLock 来防止这种情况发生。我尝试了该解决方案,但它没有解决我的问题。

为什么会发生这种情况?有没有办法阻止 AudioHardwareQSD 进入待机状态?有人对解决此问题有任何建议吗?

谢谢!

更新:我已经能够实现一个相当粗略的解决方法来纠正这个问题。在我的应用程序(游戏)中,我有一个更健全的渲染类。我添加了一个新方法present(),该方法由游戏逻辑定期执行。该方法使用1.5s超时定时器。当计时器到达最低点时,声音渲染器会播放包含 50 毫秒静音的音频文件,然后重置计时器。

这解决了我的问题......远非最佳,但它有效。

I've got a got a curious problem with playing Ogg Vorbis sounds on Android that I'm having difficulty correcting. I'm using the SoundPool class to play sounds. It works great with the exception of the first sound that I play after a pause.

Here's the issue I'm encountering: I have a menu with several buttons on it. If I hit a button, I play a tick sound. However, the very first time that I attempt to play one, it does not emit a sound. Then, if I hit the same menu button again, it works. If I then delay the next press for several seconds, the issue re-appears. Specifically, I see the following behavior:

  • wait several seconds
  • touch UI button which should emit a sound ... it doesn't
  • log cat reports "AudioFlinger: write blocked for 165 msecs, 66 delayed writes, thread 0xec40" (happens immediately when I touch the UI button)
  • wait several seconds
  • log cat reports "AudioHardwareQSD: AudioHardware pcm playback is going to standby"
  • touch UI button which should emit a sound... it doesn't.
  • logcat reports "AudioFlinger: write blocked for 166 msecs, 67 delayed writes, thread 0xec40" (happens immediately when I touch the UI button)
  • touch UI button again, but before AudioHardwareQSD standby message appears... SOUND WORKS!

I've seen this behavior on a few different devices: HTC Incredible, rooted Nook Color, and HTC Thunderbolt, so I don't believe it is device specific.

I'm GUESSING this is a function of the AudioHardwareQSD going to standby. Once it is in standby, the first sound out of the chute gets ignored, while subsequent sounds work until it hits standby once again. There is roughly a 3 second delay between the 'write blocked' message and the AudioHardwareQSD message on my HTC Incredible.

There's an answer on StackOverflow here that discusses using WakeLock to prevent this from happening. I tried that solution and it did not fix my problem.

Why is this happening? Is there a way to prevent AudioHardwareQSD from going into standby? Does anybody have any tips on troubleshooting this?

Thanks!

UPDATE: I've been able to implement a rather crude workaround that corrects this problem. In my application (a game), I have a sounder rendering class. I added a new method present() that is executed by the game logic on a periodic basis. The method uses a 1.5s timeout timer. When the timer bottoms out, the sound renderer plays an audio file that consists of 50ms of silence and then resets the timer.

This has corrected my issue... Far from optimal, but it works.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

别闹i 2024-12-27 11:03:39

Android SoundPool 确实很糟糕。我必须这样做

  int streamid = soundPool.play(sid, soundVolume, soundVolume, 0, loopVal, 1.0f);
  if (streamid == 0) {
    try {
     Thread.sleep(50);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
  }
} while(streamid == 0 && retry++<3);

,但这并不理想,它确实降低了帧速率。

Android SoundPool really sucks. I have to

  int streamid = soundPool.play(sid, soundVolume, soundVolume, 0, loopVal, 1.0f);
  if (streamid == 0) {
    try {
     Thread.sleep(50);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
  }
} while(streamid == 0 && retry++<3);

But this isn't ideal, it really slows down the framerate.

年少掌心 2024-12-27 11:03:39

距离最初的帖子已经过去四年了,我也遇到了同样的问题!就我而言,它在使用 Android API 19 的三星 Galaxy S3 上。但我找到了一种不同的解决方案,不需要按时间间隔播放无声声音。

相反,我发现只有音频文件的第一部分(50-100 毫秒)没有第一次播放。因此编辑我的声音文件,使生成的 mp3 在开始时有大约 100 毫秒的静音,然后它可以正确播放。单击按钮时几乎感觉不到 100 毫秒的延迟。

Four years since the original post and I'm having this same issue! In my case, it's on a Samsung Galaxy S3 using Android API 19. But I found a different solution that doesn't require playing a silent sound at a timed interval.

Instead, I found that it's only the first portion (50-100ms) of the audio file that isn't being played the first time. So editing my sound file so the resulting mp3 has about 100ms of silence at the beginning, it then plays correctly. The 100ms delay is barely perceptible for a button click.

记忆里有你的影子 2024-12-27 11:03:39

您可以在后台线程中初始化 SoundPool 并设置 SoundPool.OnLoadCompleteListener 以在准备就绪时收到通知。

另请查看示例:必须播放特定声音单击项目时

You can initialize the SoundPool in a background thread and set a SoundPool.OnLoadCompleteListener to get informed when ready.

Also take a look to the example: specific sound must play when item is clicked

花心好男孩 2024-12-27 11:03:39

到 2021 年,问题仍然存在。

真正消除初始延迟的唯一解决方案是使用一个线程,每 5 秒左右连续播放音量为 0 的声音。

Kotlin 代码:

class SoundThread(soundPool: SoundPool) : Thread() {

    private var soundPool: SoundPool = soundPool;
    var sounds: BlockingQueue<SoundEntity> = LinkedBlockingQueue<SoundEntity>();

    override fun run() {
        var sound: SoundEntity;
        var prevTime = System.currentTimeMillis();

        while(true){
            var now = System.currentTimeMillis();
            if(now - prevTime > 5000){
                this.soundPool.play(1, 0.0f, 0.0f, 1, 0, 1.0f);
                prevTime = now;
            }

            if(!sounds.isEmpty()) {
                sound = sounds.take();
                this.soundPool.play(sound.soundId, sound.volume, sound.volume, 1, 0, 1.0f);
            }
        }
    }
}

修改了 Andreas Linden 在此处的答案。

(我为那些像我一样忽视问题中的解决方法部分的人写了这个答案。)

Issue still exists in 2021.

The only solution, that really gets rid of that initial delay, is to use a thread that continuously plays a sound with volume 0 every 5 seconds or so.

Kotlin code:

class SoundThread(soundPool: SoundPool) : Thread() {

    private var soundPool: SoundPool = soundPool;
    var sounds: BlockingQueue<SoundEntity> = LinkedBlockingQueue<SoundEntity>();

    override fun run() {
        var sound: SoundEntity;
        var prevTime = System.currentTimeMillis();

        while(true){
            var now = System.currentTimeMillis();
            if(now - prevTime > 5000){
                this.soundPool.play(1, 0.0f, 0.0f, 1, 0, 1.0f);
                prevTime = now;
            }

            if(!sounds.isEmpty()) {
                sound = sounds.take();
                this.soundPool.play(sound.soundId, sound.volume, sound.volume, 1, 0, 1.0f);
            }
        }
    }
}

Modified Andreas Linden's answer from here.

(I write this answer for the ones who overlook that workaround part in the question, like I did.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文