iOS耳机连接状态检测异常:已连耳机却返回speaker端口类型
解决Swift检测耳机连接时portType识别错误的问题
问题描述
我编写了如下Swift代码用于检测耳机是否连接:
func areHeadphonesConnected() -> Bool { let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setActive(true) let currentRoute = audioSession.currentRoute SDKLog(info: "currentRouteis\(currentRoute)") for output in currentRoute.outputs { SDKLog(info: "portType is\(output.portType)") SDKLog(info: "UID is\(output.uid)") if output.portType == AVAudioSession.Port.headphones { try audioSession.setActive(false) return true } } try audioSession.setActive(false) } catch { print("Error checking headphone status: \(error.localizedDescription)") } return false }
但实际运行时,即使已连接耳机,代码返回的portType仍为speaker,预期连接耳机时返回headphones,未连接时返回speaker,请问该如何解决?
解决方案
1. 移除不必要的音频会话激活操作
手动激活再立刻停用音频会话的操作会干扰系统对当前音频路由的判断,实际上不需要激活会话就能获取准确的路由信息。修改后的基础检测代码如下:
func areHeadphonesConnected() -> Bool { let audioSession = AVAudioSession.sharedInstance() let currentRoute = audioSession.currentRoute for output in currentRoute.outputs { SDKLog(info: "portType is\(output.portType)") if output.portType == .headphones { return true } } return false }
2. 覆盖全类型耳机检测
只判断.headphones会遗漏蓝牙耳机的情况,建议加入常见的蓝牙耳机端口类型:
func areHeadphonesConnected() -> Bool { let audioSession = AVAudioSession.sharedInstance() let currentRoute = audioSession.currentRoute let headphonePortTypes: [AVAudioSession.Port] = [.headphones, .bluetoothA2DP, .bluetoothHFP] for output in currentRoute.outputs { if headphonePortTypes.contains(output.portType) { return true } } return false }
.bluetoothA2DP:适用于立体声蓝牙音频设备.bluetoothHFP:适用于支持通话的蓝牙设备(如蓝牙耳机、车载蓝牙)
3. 实时监听耳机插拔状态
如果需要实时响应耳机的连接/断开事件,注册AVAudioSession.routeChangeNotification通知是更可靠的方式:
// 在初始化阶段注册通知 func setupAudioRouteObserver() { NotificationCenter.default.addObserver( self, selector: #selector(handleAudioRouteChange(_:)), name: AVAudioSession.routeChangeNotification, object: nil ) } // 路由变化回调处理 @objc private func handleAudioRouteChange(_ notification: Notification) { guard let userInfo = notification.userInfo, let reasonRawValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, let reason = AVAudioSession.RouteChangeReason(rawValue: reasonRawValue) else { return } switch reason { case .newDeviceAvailable: // 检测到新设备接入,判断是否为耳机 let isHeadphoneConnected = areHeadphonesConnected() print(isHeadphoneConnected ? "耳机已连接" : "其他音频设备接入") case .oldDeviceUnavailable: // 设备断开,可根据之前的状态判断是否为耳机拔出 print("音频设备已断开") default: break } }
4. 确认音频会话类别设置
不合适的音频会话类别可能导致路由检测异常,根据App功能设置对应的类别,比如需要播放+录音的场景:
func setupAudioSession() { do { try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default) } catch { print("设置音频会话类别失败: \(error.localizedDescription)") } }
建议在App启动时完成会话类别配置,确保路由检测的准确性。
内容的提问来源于stack exchange,提问作者Sushant Memane
相关产品推荐
相关产品推荐

