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

使用AudioKit v5-main时麦克风Pitch Tap触发崩溃,求解决方法

解决AudioKit v5中同时使用PitchTap和NodeRecorder导致的崩溃问题

崩溃原因分析

你遇到的这个错误:

[avae] AVAEInternal.h:76 required condition is false: [AVAEGraphNode.mm:817:CreateRecordingTap: (nullptr == Tap())]

核心原因是Core Audio的AVAudioEngine不允许在同一个音频节点实例上同时添加多个录制/监听Tap。AudioKit的PitchTap(用于音频分析)和NodeRecorder(用于录音)底层都会给绑定的节点添加Tap,当你把它们都挂在同一个boostMic节点上时,就触发了这个冲突,直接导致崩溃。

解决方案:拆分音频信号分支

我们需要把麦克风的信号拆分成两个独立的分支,让PitchTap和NodeRecorder分别处理不同的分支节点,这样就不会产生Tap冲突了。这里提供两种简洁的实现方式:

方法1:使用Splitter拆分信号

AudioKit的Splitter可以将单个输入信号拆分为多个独立的输出分支,每个分支都是独立的音频节点,完美解决Tap冲突问题:

class ViewController: UIViewController {
    let engine = AudioEngine()
    var silence: Fader!
    var boostMic: Fader!
    var tracker: PitchTap!
    var recorder: NodeRecorder!
    var player = AudioPlayer()
    var mixer = Mixer()
    // 新增Splitter用于拆分麦克风信号
    var micSplitter: Splitter!

    override func viewDidLoad() {
        super.viewDidLoad()
        guard let mic = engine.input else {
            debugPrint("无法获取麦克风输入")
            return
        }
        boostMic = Fader(mic, gain: 5)
        
        // 将boostMic的信号拆分为两个独立分支
        micSplitter = Splitter(boostMic)
        
        // PitchTap监听第一个分支
        tracker = PitchTap(micSplitter[0], handler: { (pitch, amp) in
            DispatchQueue.main.async {
                debugPrint("amp: \(amp.first!.description)")
            }
        })
        
        // NodeRecorder录制第二个分支
        do {
            recorder = try NodeRecorder(node: micSplitter[1])
        } catch {
            debugPrint(error.localizedDescription)
        }
        
        // 将其中一个分支接入静音Fader(不影响录音和分析)
        silence = Fader(micSplitter[0], gain: 0)
        mixer.addInput(silence)
        mixer.addInput(player)
        engine.output = mixer
        Settings.audioInputEnabled = true
        
        do {
            try engine.start()
            tracker.start()
            NodeRecorder.removeTempFiles()
            try recorder.record()
        } catch {
            debugPrint(error.localizedDescription)
        }
    }
}

方法2:使用两个独立Mixer复制信号

如果你不想用Splitter,也可以创建两个独立的Mixer,分别接收原始麦克风信号,让PitchTap和NodeRecorder绑定到不同的Mixer上:

class ViewController: UIViewController {
    let engine = AudioEngine()
    var silence: Fader!
    var boostMic: Fader!
    var tracker: PitchTap!
    var recorder: NodeRecorder!
    var player = AudioPlayer()
    var mixer = Mixer()
    // 新增两个Mixer分别处理分析和录音分支
    var tapMixer: Mixer!
    var recorderMixer: Mixer!

    override func viewDidLoad() {
        super.viewDidLoad()
        guard let mic = engine.input else {
            debugPrint("无法获取麦克风输入")
            return
        }
        boostMic = Fader(mic, gain: 5)
        
        // 创建两个独立的Mixer,都接入boostMic的信号
        tapMixer = Mixer(boostMic)
        recorderMixer = Mixer(boostMic)
        
        // PitchTap绑定到tapMixer
        tracker = PitchTap(tapMixer, handler: { (pitch, amp) in
            DispatchQueue.main.async {
                debugPrint("amp: \(amp.first!.description)")
            }
        })
        
        // NodeRecorder绑定到recorderMixer
        do {
            recorder = try NodeRecorder(node: recorderMixer)
        } catch {
            debugPrint(error.localizedDescription)
        }
        
        // 将tapMixer接入静音Fader
        silence = Fader(tapMixer, gain: 0)
        mixer.addInput(silence)
        mixer.addInput(player)
        engine.output = mixer
        Settings.audioInputEnabled = true
        
        do {
            try engine.start()
            tracker.start()
            NodeRecorder.removeTempFiles()
            try recorder.record()
        } catch {
            debugPrint(error.localizedDescription)
        }
    }
}

为什么这样能解决问题?

两种方法的核心逻辑都是让PitchTap和NodeRecorder绑定到不同的音频节点实例,这样它们各自添加的Tap就不会冲突,完全符合Core Audio的限制要求,同时还能保证两者都能获取到完整的麦克风信号。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:50:12