AudioManager MODE_IN_COMMUNICATION致蓝牙音频爆音音质下降问题
问题描述
当应用通过蓝牙耳机连接时,调用audioManager.startBluetoothSco()接口,相关实现代码如下。蓝牙连接功能运行正常,但MediaPlayer播放的音频存在噼啪爆音问题:每次播放动作提示音(例如R.raw.record_start、R.raw.success_action、R.raw.failure_action)时,都会出现音质劣化或爆音现象。
测试所用设备
- 蓝牙耳机:AfterShokx OpenComm、Jabra Evolve 65
- 测试手机:三星A52、三星A50、Pixel 3、一加6 Pro
已尝试的排查方案
- 尝试将
audioManager.mode = AudioManager.MODE_IN_COMMUNICATION修改为AudioManager.MODE_IN_CALL或AudioManager.MODE_NORMAL。- 修改为
MODE_IN_CALL时audioManager.mode未发生变化,值始终为0(即MODE_NORMAL)。
- 修改为
- 修改为
MODE_NORMAL仅在三星A52上生效,无爆音问题、运行完全符合预期,是目标实现效果。- 但其余所有测试手机都会切换到其他音频流,导致无法听到任何媒体声音。
- 例如在Pixel 3上连接Jabra Evolve 65并设置为
MODE_NORMAL时,无法听到任何媒体声音,包括Youtube、Spotify等第三方应用音频以及系统音;但切换为MODE_IN_COMMUNICATION时可以听到声音,仅存在爆音问题。
- 尝试修改MediaPlayer的AudioAttributes配置,音质问题仍然存在。
val actionSound = if (triggerErrorEarcon) R.raw.failure_action else if (longRecordingBreak) R.raw.success_action else R.raw.record_start val md = MediaPlayer.create(context, actionSound) val streamType = if (audioDeviceManager.headsetConnected) AudioManager.STREAM_VOICE_CALL else AudioManager.STREAM_MUSIC md.setAudioAttributes( AudioAttributes.Builder() .setLegacyStreamType(streamType) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build()) md.play()
待验证的解决方向
- 调整
audioManager.mode或audioManager的其他相关属性修复问题(暂未找到具体调整方式)。 - 继续使用
MODE_IN_COMMUNICATION模式,调整MediaPlayer相关属性解决蓝牙设备上的音质劣化问题。 - 目前暂未找到其他可行排查方向,希望能获得相关问题的解决方案,在此先行致谢。
AudioDeviceManager.kt 代码
class AudioDeviceManager(val context: Context) { internal val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager internal val headsetConnectedSubject = BehaviorSubject.createDefault(false) internal val headsetConnected: Boolean get() = headsetConnectedSubject.value ?: false private val intentFilter = IntentFilter().apply { addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED) } private val audioDeviceCallback = object: AudioDeviceCallback() { override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) { super.onAudioDevicesAdded(addedDevices) updateBluetoothHeadsetState() } override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>?) { super.onAudioDevicesRemoved(removedDevices) updateBluetoothHeadsetState() } } private val scoReceiver = object: BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent?.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1) == AudioManager.SCO_AUDIO_STATE_CONNECTED) { // SCO 连接完成 audioManager.mode = AudioManager.MODE_IN_COMMUNICATION audioManager.isSpeakerphoneOn = false audioManager.isBluetoothScoOn = true } } } fun start() { if (headsetConnected.not()) audioManager.registerAudioDeviceCallback(audioDeviceCallback, null) } fun stop(unregisterAudioDeviceCallback: Boolean = false) { if (unregisterAudioDeviceCallback) unregisterDeviceCallback() audioManager.mode = AudioManager.MODE_NORMAL audioManager.isSpeakerphoneOn = true audioManager.isBluetoothScoOn = false audioManager.stopBluetoothSco() } private fun unregisterDeviceCallback() = audioManager.unregisterAudioDeviceCallback(audioDeviceCallback) fun updateBluetoothHeadsetState() { val headset = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)?.firstOrNull { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO } val headsetConnected = headset != null headsetConnectedSubject.onNext(headsetConnected) if (headsetConnected) { audioManager.startBluetoothSco() context.registerReceiver(scoReceiver, intentFilter) } else { audioManager.mode = AudioManager.MODE_NORMAL audioManager.isSpeakerphoneOn = true audioManager.isBluetoothScoOn = false audioManager.stopBluetoothSco() } } }
应用内播放动作提示音代码
MediaPlayer.create(context, R.raw.record_start) .play() .subscribe() .addTo(disposable)
MediaPlayer扩展函数代码
fun MediaPlayer.play(): Completable { return Completable.create { emitter -> var isCancelled = false emitter.setCancellable { isCancelled = true } setOnCompletionListener { GlobalScope.launch { // 延迟释放资源,避免CompletionListener触发过快导致异常 delay(3000) it.release() } if (isCancelled) { return@setOnCompletionListener } emitter.onComplete() } start() } }
内容的提问来源于stack exchange,提问作者Orcun Sevsay
相关产品推荐
相关产品推荐

