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

AVCaptureSession添加音频输入延迟及FaceTime冲突问题求助

问题解决:FaceTime通话状态下相机麦克风冲突及录制延迟问题

问题背景

开发的相机应用支持拍照和带声音录像,用户处于FaceTime通话状态时,相机画面冻结并抛出运行时错误:

AVError(_nsError: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (561017449), NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x300723240 {Error Domain=NSOSStatusErrorDomain Code=561017449 "(null)" UserInfo={AVErrorFourCharCode='!pri'}}})

已排查信息

问题根源是AVCaptureSession初始化阶段激活麦克风的代码,原代码如下:

if let audioDevice = AVCaptureDevice.default(for: .audio),
   let audioDeviceInput = try? AVCaptureDeviceInput(device: audioDevice),
   session.canAddInput(audioDeviceInput) {
       session.addInput(audioDeviceInput)
}

当前矛盾:

  • 初始化时执行:无录制延迟,但FaceTime通话时相机直接报错
  • 移到录制前执行:FaceTime下相机可正常工作,但录制触发后有明显延迟和短暂黑屏
  • 尝试过在相机逻辑的DispatchQueue内/外执行、放在session.beginConfiguration()和commitConfiguration()之间,均无改善

解决方案

1. 提前检测音频设备占用状态

初始化时先检查麦克风是否被其他应用(如FaceTime)占用,避免直接添加音频输入触发冲突:

func checkAudioDeviceAvailability() -> Bool {
    guard let audioDevice = AVCaptureDevice.default(for: .audio) else { return false }
    do {
        try audioDevice.lockForConfiguration()
        let isAvailable = !audioDevice.isExclusiveAccessGranted
        audioDevice.unlockForConfiguration()
        return isAvailable
    } catch {
        return false
    }
}

初始化阶段只添加视频输入,若检测到麦克风可用则添加音频输入;若不可用,等到录制前再尝试获取。

2. 预加载音频输入但延迟激活

初始化时创建音频输入对象但不添加到session,录制前快速添加以减少开销:

// 类内存储预创建的音频输入
private var audioInput: AVCaptureDeviceInput?

// 初始化流程
override func viewDidLoad() {
    super.viewDidLoad()
    setupCaptureSession()
    // 预创建音频输入,暂不加入session
    if let audioDevice = AVCaptureDevice.default(for: .audio) {
        do {
            audioInput = try AVCaptureDeviceInput(device: audioDevice)
        } catch {
            print("创建音频输入失败: \(error)")
        }
    }
}

// 录制按钮触发逻辑
func startRecording() {
    if let audioInput = audioInput, session.canAddInput(audioInput) {
        session.beginConfiguration()
        session.addInput(audioInput)
        session.commitConfiguration()
    }
    // 启动录制逻辑
}

预创建音频输入可避免录制时的设备枚举和初始化开销,降低延迟和黑屏概率。

3. 监听session错误并动态调整

添加AVCaptureSession错误监听,检测到音频权限冲突时自动移除音频输入并重启session:

session.addObserver(self, forKeyPath: "running", options: .new, context: nil)

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "running", let isRunning = change?[.newKey] as? Bool, !isRunning {
        guard let error = session.runtimeError as? NSError, error.code == -11800 else { return }
        // 移除音频输入
        session.beginConfiguration()
        session.inputs.forEach {
            if let input = $0 as? AVCaptureDeviceInput, input.device.type == .audio {
                session.removeInput(input)
            }
        }
        session.commitConfiguration()
        // 重启session恢复相机功能
        session.startRunning()
    }
}

关键原理

  • FaceTime通话时会独占麦克风的排他访问权限,初始化阶段直接添加音频输入会触发权限冲突,抛出!pri(权限)相关错误
  • 预创建音频输入对象能减少录制时的初始化开销,避免延迟和黑屏
  • 动态检测设备状态并调整session输入,可在不影响正常录制体验的前提下兼容多应用音频占用场景

内容的提问来源于stack exchange,提问作者Xavi Moll

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 14:02:57