AVCaptureSession录制期间动态切换蓝牙麦克风的适配实现疑问
AVCaptureSession录制期间动态切换蓝牙麦克风的适配实现疑问
我完全懂你的困扰——已经配置好AVAudioSession并监听了路由变化,但不知道怎么把蓝牙设备的连接/断开和AVCaptureSession的音频输入绑定起来,尤其是在录制过程中动态切换对吧?其实核心就是在收到路由通知时,手动替换AVCaptureSession的音频输入设备,同时处理好录制状态的衔接,下面给你一步步拆解解决思路:
首先,我们需要一个辅助方法来快速定位目标音频设备(蓝牙或内置麦克风),避免每次都重复遍历设备列表:
func getTargetAudioDevice(isBluetooth: Bool) -> AVCaptureDevice? { let audioDevices = AVCaptureDevice.devices(for: .audio) for device in audioDevices { if isBluetooth { // 匹配蓝牙HFP和LE类型的设备,覆盖大多数蓝牙麦克风 if device.transportType == .bluetoothHFP || device.transportType == .bluetoothLE { return device } } else { if device.transportType == .builtInMic { return device } } } return nil }
接下来就是修改你的handleRouteChange方法,核心逻辑是:记录当前录制状态→修改AVCaptureSession输入→恢复录制(如果之前在录)。注意所有对AVCaptureSession的配置修改都必须放在beginConfiguration()和commitConfiguration()之间,这是Session的线程安全要求:
@objc func handleRouteChange(notification: Notification) { guard let userInfo = notification.userInfo, let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else { return } // 先保存当前的录制状态,后面要用来恢复 let wasRecording = captureSession.isRunning switch reason { case .newDeviceAvailable: // 找到刚连接的蓝牙设备 guard let bluetoothMic = getTargetAudioDevice(isBluetooth: true) else { print("未检测到可用蓝牙麦克风") return } captureSession.beginConfiguration() // 移除旧的音频输入(不管是内置还是之前的蓝牙) if let oldAudioInput = captureSession.inputs.first(where: { $0.device.type == .audio }) { captureSession.removeInput(oldAudioInput) } // 添加新的蓝牙麦克风输入 do { let newAudioInput = try AVCaptureDeviceInput(device: bluetoothMic) if captureSession.canAddInput(newAudioInput) { captureSession.addInput(newAudioInput) } } catch { print("创建蓝牙音频输入失败:\(error.localizedDescription)") } captureSession.commitConfiguration() // 如果之前在录制,重新启动会话 if wasRecording { captureSession.startRunning() } case .oldDeviceUnavailable: // 蓝牙断开,切换回内置麦克风 guard let builtInMic = getTargetAudioDevice(isBluetooth: false) else { print("未检测到内置麦克风") return } captureSession.beginConfiguration() // 移除旧的蓝牙音频输入 if let oldAudioInput = captureSession.inputs.first(where: { $0.device.type == .audio }) { captureSession.removeInput(oldAudioInput) } // 添加内置麦克风输入 do { let newAudioInput = try AVCaptureDeviceInput(device: builtInMic) if captureSession.canAddInput(newAudioInput) { captureSession.addInput(newAudioInput) } } catch { print("创建内置麦克风输入失败:\(error.localizedDescription)") } captureSession.commitConfiguration() // 恢复录制状态 if wasRecording { captureSession.startRunning() } default: // 其他路由变化场景(比如切换有线耳机),可以按需扩展 break } }
最后给你几个关键注意点,避免踩坑:
- 权限检查:确保已经申请并获取了麦克风权限,否则无法访问任何音频设备;
- 线程安全:AVCaptureSession的配置操作建议在主线程执行,或者用专门的串行队列处理,避免出现线程冲突;
- 录制中断:目前AVCaptureSession不支持无中断切换音频输入,所以切换过程中会有短暂的录制中断,你可以在UI上给用户加个提示(比如“正在切换音频设备...”)提升体验;
- 设备兼容性:有些蓝牙设备可能需要配对后才能被识别,测试时记得先完成配对流程。
内容来源于stack exchange
相关产品推荐
相关产品推荐

