为啥我的 SoundPool 声音第一次在 Android 上没有播放?

Posted

技术标签:

【中文标题】为啥我的 SoundPool 声音第一次在 Android 上没有播放?【英文标题】:Why does my SoundPool sound not play the first time on Android?为什么我的 SoundPool 声音第一次在 Android 上没有播放? 【发布时间】:2011-12-10 17:37:53 【问题描述】:

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

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

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

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

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

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

为什么会这样?有没有办法防止 AudioHardwareQSD 进入待机状态?有人有任何解决此问题的提示吗?

谢谢!

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

这已经纠正了我的问题......远非最佳,但它有效。

【问题讨论】:

我也有同样的问题!我不明白你的解决方案你能帮我吗? 我使用 Audacity 生成了一个 50 毫秒长的声音文件,它只包含静音。每 1.5 秒,我只是播放这个声音文件。这样就解决了上述问题。 谢谢!也找到了解决方案。检查一下。 ***.com/questions/12261867/… 【参考方案1】:

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);

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

【讨论】:

【参考方案2】:

您可以在后台线程中初始化 SoundPool 并设置 SoundPool.OnLoadCompleteListener 以便在准备好时获得通知。

也可以看看例子:specific sound must play when item is clicked

【讨论】:

【参考方案3】:

自原始帖子发布四年后,我遇到了同样的问题!在我的例子中,它是在使用 Android API 19 的三星 Galaxy S3 上。但我找到了一个不同的解决方案,它不需要按时间间隔播放无声的声音。

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

【讨论】:

【参考方案4】:

问题在 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);
            
        
    

修改了来自here 的 Andreas Linden 的回答。

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

【讨论】:

以上是关于为啥我的 SoundPool 声音第一次在 Android 上没有播放?的主要内容,如果未能解决你的问题,请参考以下文章

SoundPool 仅在第一次播放声音

使用 SoundPool 播放声音

使用 SoundPool 播放声音

SoundPool play() 块渲染

如何停止 SoundPool 中的所有声音?

如何从动作栏上的soundpool中停止声音