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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 16:35:56