You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android 15及以上版本下经典蓝牙耳机同时录音与音乐播放的实现问题及解决方案问询

Android 15及以上版本下经典蓝牙耳机同时录音与音乐播放的实现问题及解决方案问询

嘿,我太懂你这糟心的处境了——Android 15之前用经典蓝牙耳机(非BLE)一边录音频一边跑YouTube、Spotify这类流媒体完全没问题,结果升级后这功能直接“罢工”,明明音质差点儿也无所谓,就想要个能同时干活的办法!我仔细看了你贴的代码,它确实能通过SCO通道用蓝牙耳麦录音,但一启动录音就把音乐播放给掐断了,咱们来聊聊可能的解决思路和可行的workaround。

先聊聊问题根源

Android 15对音频路由和SCO通道的管理做了挺严格的变更:传统SCO通道本来是为语音通话设计的,之前系统允许它和媒体播放同时占用,但Android 15收紧了资源独占性——当你用VOICE_COMMUNICATION作为音频源启动AudioRecord时,系统会自动抢占音频焦点,直接切断媒体播放的路由,这就是为啥录音时音乐停了的原因。

试试这些可行的workaround

1. 调整音频焦点策略,请求临时共享焦点

别让录音直接把焦点抢光,试试请求可压低音量的临时焦点,这样媒体播放不会完全停止,只是音量降低(你也说了音质不是问题,这个应该能接受)。具体操作是用AudioManagerrequestAudioFocus方法,配置AudioFocusRequestfocusGainAUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK

// 先定义音频焦点相关变量
private var audioFocusRequest: AudioFocusRequest? = null

private fun requestAudioFocus() {
    val audioAttributes = AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
        .build()

    audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
        .setAudioAttributes(audioAttributes)
        .setOnAudioFocusChangeListener { focusChange ->
            when (focusChange) {
                AudioManager.AUDIOFOCUS_LOSS -> {
                    logUi("失去音频焦点,可考虑暂停录音")
                }
                AudioManager.AUDIOFOCUS_GAIN -> {
                    logUi("获取到音频焦点,可启动录音")
                }
            }
        }
        .build()

    val result = audioManager.requestAudioFocus(audioFocusRequest!!)
    if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        logUi("音频焦点申请成功")
    } else {
        logUi("音频焦点申请失败")
    }
}

// 录音结束后记得释放焦点
private fun releaseAudioFocus() {
    audioFocusRequest?.let {
        audioManager.abandonAudioFocusRequest(it)
        audioFocusRequest = null
    }
}

你可以在startRecordingFlow方法开头调用requestAudioFocus,在stopRecordingFlow里调用releaseAudioFocus,看看能不能保留音乐播放。

2. 强制固定音频输出路由到SCO设备

试试在启动录音后,把媒体播放的输出也强制绑定到蓝牙SCO设备,用audioManager.setPreferredDevice()方法,指定输出设备为你找到的SCO设备:

// 在buildAndStart方法里,启动AudioRecord后添加
audioManager.setPreferredDevice(preferred)
// 这里的preferred就是你获取到的Bluetooth SCO输入设备,它同时也是输出设备

不过Android 15可能限制了这个操作的权限,你需要确保已经拿到BLUETOOTH_CONNECT权限,而且测试时要确认耳机确实支持SCO双向传输。

3. 尝试改用MediaRecorder替代AudioRecord

虽然你用的是AudioRecord,但可以试试换成MediaRecorder,配置音频源为VOICE_COMMUNICATION,同时指定音频路由到SCO,看看系统会不会允许它和媒体播放共存:

val mediaRecorder = MediaRecorder().apply {
    setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
    setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
    setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
    setOutputFile(outFile.path)
    // 尝试指定音频路由
    audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION)
    audioManager.startBluetoothSco()
    prepare()
    start()
}

这个方法不一定百分百有效,但可以作为备选方案试试。

额外注意事项

  • 确保所有权限都正确申请:RECORD_AUDIOBLUETOOTH_CONNECT(Android 12+)一个都不能少,而且要在运行时动态申请。
  • 确认你的蓝牙耳机是经典蓝牙(非BLE),BLE设备不支持SCO通道,自然没法实现这个场景。
  • 如果以上方法都不行,可能需要向Android官方提交bug反馈,或者看看有没有第三方音频处理库能绕过系统的限制,但目前来说上面的几个方向是最值得尝试的。

内容来源于stack exchange

火山引擎 最新活动