AVAudioSession.routeChangeNotification两次触发致蓝牙耳机断开回退麦克风问题
问题原因
核心原因是AVAudioSession配置的选项存在优先级冲突:
- 你同时启用了
.allowBluetooth和.defaultToSpeaker两个CategoryOptions,.allowBluetooth会优先将音频路由到已连接的蓝牙HFP设备,触发第一次categoryChange类型的路由变更通知 .defaultToSpeaker的系统优先级高于蓝牙路由规则,系统检测到该配置后,会强制将音频路由切回内置扬声器/麦克风,因此触发第二次categoryChange通知,导致蓝牙路由自动回退
修复方案
- 第一步:移除冲突的
.defaultToSpeaker配置,新增.allowBluetoothA2DP兼容高音质蓝牙输出场景,避免强制覆盖蓝牙路由规则 - 第二步:在路由变更通知中手动判断当前连接的音频设备,如果没有蓝牙设备,再通过
overrideOutputAudioPort方法手动切换到扬声器,满足无蓝牙时默认走扬声器的需求 - 第三步:新蓝牙设备连接时,重新激活AVAudioSession保证路由规则生效
修改后的代码示例
AppDelegate中AVAudioSession配置
let session = AVAudioSession.sharedInstance() do { if #available(iOS 10.0, *) { try session.setCategory(.playAndRecord, mode: .default, options: [.allowBluetooth, .allowBluetoothA2DP]) } else { session.perform(NSSelectorFromString("setCategory:withOptions:error:"), with: AVAudioSession.Category.playAndRecord, with: [ AVAudioSession.CategoryOptions.allowBluetooth, AVAudioSession.CategoryOptions.allowBluetoothA2DP ]) try session.setMode(.default) } try session.setActive(true) } catch { print(error) }
ViewController中通知监听逻辑
@objc private func didRouteChangeNotification(_ notification: Notification) { guard let userInfo = notification.userInfo, let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, let reason = AVAudioSession.RouteChangeReason(rawValue:reasonValue) else { return } let session = AVAudioSession.sharedInstance() var hasBluetoothDevice = false // 校验当前路由是否包含蓝牙设备 for outputPort in session.currentRoute.outputs { switch outputPort.portType { case .bluetoothHFP, .bluetoothA2DP, .bluetoothLE: hasBluetoothDevice = true default: break } } // 无蓝牙设备时手动切换到扬声器 if !hasBluetoothDevice { do { try session.overrideOutputAudioPort(.speaker) } catch { print("切换扬声器失败:\(error)") } } switch reason { case .newDeviceAvailable: debugPrint("newDeviceAvailable") // 新设备连接后重新激活session do { try session.setActive(true) } catch { print("session激活失败:\(error)") } case .oldDeviceUnavailable: debugPrint("oldDeviceUnavailable") case .categoryChange: debugPrint("categoryChange") default: () } }
内容的提问来源于stack exchange,提问作者Mike Simz
相关产品推荐
相关产品推荐

