蓝牙延迟和 Android 音频提示
Posted
技术标签:
【中文标题】蓝牙延迟和 Android 音频提示【英文标题】:Tips for Bluetooth lag and Android audio 【发布时间】:2018-03-09 00:37:34 【问题描述】:我的 android 应用使用 SoundPool 播放简短的 wav 语音片段。对于连接的某些蓝牙扬声器,初始播放可能会被截断,其余部分可以听到。通过本机电话扬声器输出一切正常。
Soundpool 具有低延迟。某些蓝牙扬声器可能会因电源管理引起的睡眠而滞后。我主要考虑蓝牙 4.x,目前使用的是 Android 7.0,尽管用户将使用其他版本。
是否有弥补这种情况的最佳做法?我是否应该在语音片段中添加一个无噪音的领导者(例如“X”毫秒)——让蓝牙有时间唤醒,以便之后可以正确听到重要部分?是否首选某些声音文件规格?游戏程序员有什么见解吗?
谢谢!
我的初始化 soundPool(使用声音 id 的哈希图)和播放声音以及释放和停止 soundPool 的代码如下。在我的主程序中调用 playSound 的示例是 SoundPoolManager.getInstance().playSound(R.raw._whistle);
public void InitializeSoundPool(Activity activity, final ISoundPoolLoaded callback) throws Exception
if (sounds == null || sounds.size() == 0)
throw new Exception("Sounds not set");
int maxStreams = 1;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
soundPool = new SoundPool.Builder()
.setMaxStreams(maxStreams)
.build();
else
soundPool = new SoundPool(maxStreams, AudioManager.STREAM_MUSIC, 0);
soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener()
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId,
int status)
SoundSampleEntity entity = getEntity(sampleId);
if (entity != null)
entity.setLoaded(status == 0);
if (sampleId == maxSampleId())
callback.onSuccess();
);
int length = sounds.size();
hashMap = new HashMap<Integer, SoundSampleEntity>();
int index;
for (index = 0; index < length; index++)
hashMap.put(sounds.get(index), new SoundSampleEntity(0, false));
index = 0;
for (Map.Entry<Integer, SoundSampleEntity> entry : hashMap.entrySet())
index++;
entry.getValue().setSampleId(soundPool.load(activity, entry.getKey(), index));
public void playSound(int resourceId)
if (isPlaySound())
SoundSampleEntity entity = hashMap.get(resourceId);
if (entity.getSampleId() > 0 && entity.isLoaded())
soundPool.play(entity.getSampleId(), .99f, .99f, 1, 0, 1f);
public void release()
if (soundPool != null)
soundPool.release();
public void stop()
if (soundPool != null)
for (Map.Entry<Integer, SoundSampleEntity> entry : hashMap.entrySet())
SoundSampleEntity entity = entry.getValue();
soundPool.stop(entity.getSampleId());
我添加了一个 SCO 广播接收器:
public class SCOBroadcastReceiver extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent)
if (intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1) ==
AudioManager.SCO_AUDIO_STATE_CONNECTED)
// SCO now connected
SoundPoolManager.isPlaySound = true;
Log.e("SCOBroadcastReceiver", "SCO_AUDIO_STATE_CONNECTED");
else if (intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1) ==
AudioManager.SCO_AUDIO_STATE_DISCONNECTED)
// SCO now disconnected
SoundPoolManager.isPlaySound = false;
Log.e("SCOBroadcastReceiver", "SCO_AUDIO_STATE_DISCONNECTED");
之后我的应用程序运行的日志输出是:
03-09 13:08:34.160 2615-2615/com.foobar.foo E/SCOBroadcastReceiver:SCO_AUDIO_STATE_CONNECTED 03-09 13:08:39.404 2615-2615/com.foobar.foo W/AudioTrack:AUDIO_OUTPUT_FLAG_FAST 被服务器拒绝;帧数 70229 03-09 13:09:09.278 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST 被服务器拒绝;帧数 78728 03-09 13:09:21.312 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST 被服务器拒绝;帧数 79623 03-09 13:09:33.345 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST 被服务器拒绝;帧数 73808 03-09 13:09:45.377 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST 被服务器拒绝;帧数 43391 03-09 13:09:57.400 2615-2615/com.foobar.foo W/AudioTrack:AUDIO_OUTPUT_FLAG_FAST 被服务器拒绝;帧数 46074 03-09 13:10:09.425 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST 被服务器拒绝;帧数 46075
【问题讨论】:
有人能帮忙吗?问题未解决。 你明白了吗? 【参考方案1】:你应该先启动蓝牙SCO,然后播放。这将及时唤醒扬声器。
【讨论】:
嗨 Neo,蓝牙 SCO 看起来很有帮助,我在原始帖子中提供了代码,以便您可以显示插入位置。我已经在清单中添加了 MODIFY_AUDIO_SETTINGS 权限。 我不在PC附近。我认为这是一个异步调用。所以可以先调用它然后获取回调结果。之后开始播放 正在努力工作,非常感谢您的帮助...我添加了一个 SCOBroadcastReceiver 并在播放声音之前在我的日志中看到 SCO_AUDIO_STATE_CONNECTED 存在持续截断问题。 SCO_AUDIO_STATE_DISCONNECTED 没有出现。还有其他想法吗?服务器拒绝 AUDIO_OUTPUT_FLAG_FAST 是否需要修复?以上是关于蓝牙延迟和 Android 音频提示的主要内容,如果未能解决你的问题,请参考以下文章