我的 Android 应用程序使用 SoundPool 播放简短的 wav 语音 fragment 。对于某些已连接的蓝牙扬声器,初始播放可能会被截断,其余部分可以听到。通过 native 电话扬声器输出一切正常。
Soundpool 是低延迟的。一些蓝牙扬声器可能会因电源管理引起的 sleep 而滞后。我主要考虑蓝牙 4.x,目前使用的是 Android 7.0,但用户会使用其他版本。
是否有最佳实践来弥补这种情况?我是否应该在语音 fragment 中添加一个无噪音的领导者(例如“X”毫秒)——让蓝牙有时间唤醒,以便之后可以正确听到重要部分?是否首选某些声音文件规范?游戏程序员有什么见解吗?
谢谢!
我的代码用于初始化 soundPool(使用声音 ID 的 HashMap )和播放声音以及释放和停止 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 denied by server; frameCount 70229 03-09 13:09:09.278 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount 78728 03-09 13:09:21.312 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount 79623 03-09 13:09:33.345 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount 73808 03-09 13:09:45.377 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount 43391 03-09 13:09:57.400 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount 46074 03-09 13:10:09.425 2615-2615/com.foobar.foo W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount 46075
最佳答案
你应该先启动Bluetooth SCO,然后播放。这样会及时唤醒Speaker。
关于android - 蓝牙延迟和 Android 音频的提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49184838/