Swift 6中AVAudioEngine麦克风输入Tap无法接收缓冲区数据
Swift 6下AVAudioEngine麦克风Tap无缓冲区数据问题解决
问题描述
在Swift 6中调用startMicrophoneSession方法后,控制台正常输出Audio engine started, microphone is active.,但麦克风输入节点的Tap回调从未触发(print("buffer")无输出),而Swift 6之前版本可通过该Tap正常获取音量数据。
原实现代码:
@MainActor func startMicrophoneSession() async { if audioEngine.isRunning { audioEngine.stop() } inputNode.removeTap(onBus: 0) // Explicitly remove the tap do { try audioSession.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth, .mixWithOthers]) try audioSession.setActive(true) } catch { print("Failed to set up AVAudioSession: \(error)") return } let inputFormat = inputNode.inputFormat(forBus: 0) inputNode.installTap(onBus: 0, bufferSize: 1024, format: inputFormat) { [weak self] buffer, _ in guard let self = self else { return } // Use guard let to unwrap self if buffer.frameLength > 0 { print("buffer") } else { print("Received empty buffer.") } } print("Tap installed on input node.") do { try audioEngine.start() print("Audio engine started, microphone is active.") } catch { print("Failed to set up audio session or start engine: \(error.localizedDescription)") } }
原音量获取代码:
self.micLevel = self.calculateAveragePower(buffer: buffer)
调用方式:
Task { @MainActor in await startMicrophoneSession() }
解决方案
1. 补全麦克风权限配置
iOS要求必须在Info.plist中声明麦克风使用权限,Swift 6对权限校验更严格,缺失配置会导致麦克风静默无数据:
在Info.plist中添加键NSMicrophoneUsageDescription,值为麦克风用途说明(例如:"需要访问麦克风以采集音频")。
2. 调整音频会话激活时机
将音频会话激活操作移至引擎启动之后,避免会话状态与引擎初始化冲突:
// 替换原引擎启动与会话激活的代码块 do { try audioEngine.start() try audioSession.setActive(true) print("Audio engine started, microphone is active.") } catch { print("Failed to start engine or activate session: \(error.localizedDescription)") }
3. 更换Tap安装的格式参数
尝试使用输入节点的输出格式而非输入格式安装Tap,部分场景下输入格式存在兼容性问题:
// 替换原inputFormat的获取代码 let inputFormat = inputNode.outputFormat(forBus: 0)
4. 显式连接音频节点
手动连接输入节点到主混音节点,避免隐式连接失效:
在安装Tap后、引擎启动前添加以下代码:
audioEngine.connect(inputNode, to: audioEngine.mainMixerNode, format: inputFormat)
5. 移除不必要的主线程约束
音频引擎操作无需强制在主线程执行,@MainActor可能导致回调调度异常。移除该属性,仅在更新UI时切换到主线程:
// 移除@MainActor修饰符 func startMicrophoneSession() async { // ... 原有代码 ... inputNode.installTap(onBus: 0, bufferSize: 1024, format: inputFormat) { [weak self] buffer, _ in guard let self = self else { return } if buffer.frameLength > 0 { // 更新UI时切换到主线程 Task { @MainActor in self.micLevel = self.calculateAveragePower(buffer: buffer) } print("buffer") } else { print("Received empty buffer.") } } // ... 原有代码 ... }
6. 验证节点运行状态
在引擎启动后检查输入节点的运行状态,确认节点是否正常激活:
try audioEngine.start() print("Audio engine started, microphone is active. Input node playing: \(inputNode.isPlaying)")
内容的提问来源于stack exchange,提问作者Hope
相关产品推荐
相关产品推荐

