android - 蓝牙延迟和 Android 音频的提示

标签 android audio bluetooth

我的 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/

相关文章:

java - 单击按钮播放声音

python安装零食包

iPhone如何知道蓝牙耳机是否已连接

android - 多个电话/设备之间的通信

java - 在android中识别android蓝牙设备

android - 应用程序关闭时保持用户登录 - Android Studio - MySQL

android - 从 android 运行 ffmpeg 命令 ffmpeg 语法错误在 logcat 中

android - 如何检查ImageView是否附加了android中的图像

java - 如何在android recyclerview中获取点击项目的文本

java - NullPointer异常GainControl