You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 10:44:31