Mac端Swift用AVCaptureSession录音,AVCaptureAudioDataOutput代理回调未触发求助
我之前在Mac上开发音频录制工具时也踩过完全一样的坑,AVCaptureSession看似配置正常,但就是收不到音频数据回调。结合我的排查经验,给你列几个最可能的问题点:
必须正确设置代理队列
AVCaptureAudioDataOutput要求你指定一个专门的串行队列来处理回调,不能直接依赖主队列(技术上允许但容易出问题),而且队列必须是你显式初始化的。如果没设置队列或者队列初始化有问题,系统根本不会触发回调。比如:let outputQueue = DispatchQueue(label: "com.your.app.audioCapture", qos: .userInitiated) audioDataOutput.setSampleBufferDelegate(self, queue: outputQueue)严格遵循Session配置顺序
一定要按「创建Session → 添加Input → 添加Output → 设置Output代理 → 启动Session」的顺序来操作。如果先加Output再加Input,或者没把Output添加到Session里,回调肯定不会触发。记得检查有没有调用captureSession.addOutput(audioDataOutput)。确认麦克风权限的完整流程
光在Info.plist里加NSMicrophoneUsageDescription还不够,你必须主动请求权限,并且确保用户允许了。如果跳过权限请求直接初始化Session,Session会静默启动失败,不会有任何报错,但也不会产生回调。可以用这段代码检查权限:AVCaptureDevice.requestAccess(for: .audio) { granted in if granted { // 在这里初始化Session和相关组件 } else { print("用户拒绝了麦克风权限") } }检查代理对象的生命周期
如果你的代理是局部变量(比如在某个方法里临时创建的),方法执行完后代理对象会被销毁,自然收不到回调。一定要把代理对象(比如你的Recorder类实例)作为强引用的属性保存起来,比如放在ViewController的属性里,或者用单例。排查Session的运行状态
启动Session后,打印captureSession.isRunning看看是不是true。如果是false,说明Session启动失败了,可能是设备被占用(比如其他应用在使用麦克风),或者输入设备不可用。可以监听AVCaptureSessionRuntimeErrorNotification来获取具体错误信息:NotificationCenter.default.addObserver(self, selector: #selector(handleSessionError(_:)), name: .AVCaptureSessionRuntimeError, object: captureSession)
一个可运行的简化示例
这里给你一个经过验证的Swift代码片段,你可以对照着检查自己的实现:
import AVFoundation class AudioCaptureManager: NSObject, AVCaptureAudioDataOutputSampleBufferDelegate { private var captureSession: AVCaptureSession! private let outputQueue = DispatchQueue(label: "com.example.audioCaptureQueue", qos: .userInitiated) func startCapture() { captureSession = AVCaptureSession() captureSession.sessionPreset = .high AVCaptureDevice.requestAccess(for: .audio) { [weak self] granted in guard granted, let self = self else { return } DispatchQueue.main.async { // 获取麦克风设备 guard let audioDevice = AVCaptureDevice.default(for: .audio) else { print("找不到可用的麦克风设备") return } // 添加音频输入 do { let audioInput = try AVCaptureDeviceInput(device: audioDevice) if self.captureSession.canAddInput(audioInput) { self.captureSession.addInput(audioInput) } } catch { print("创建音频输入失败: \(error)") return } // 添加音频输出并设置代理 let audioOutput = AVCaptureAudioDataOutput() if self.captureSession.canAddOutput(audioOutput) { self.captureSession.addOutput(audioOutput) audioOutput.setSampleBufferDelegate(self, queue: self.outputQueue) } // 启动会话 self.captureSession.startRunning() print("会话运行状态: \(self.captureSession.isRunning)") } } } // 代理回调方法 func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { print("成功收到音频数据!") // 在这里处理原始音频缓冲区 } @objc private func handleSessionError(_ notification: Notification) { if let error = notification.userInfo?[AVCaptureSessionErrorKey] as? Error { print("Session运行错误: \(error.localizedDescription)") } } }
先从这几个方向排查,大概率能找到问题所在。
内容的提问来源于stack exchange,提问作者David Bauer

