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

获取AVAudioEngine输入节点导致外部音频中断问题咨询

关于AVAudioSession与AVAudioEngine导致外部音频中断的问题解答

这是iOS音频会话机制的预期行为,并非Bug。

原因分析

当你调用inputNode = audioEngine.inputNode时,AVAudioEngine会自动触发音频会话的激活逻辑——即便你已经手动调用过setActive(true),获取输入节点的操作会强制抢占音频输入资源。而你设置的playAndRecord会话类别,默认会中断其他应用的音频播放,因为录音操作需要独占系统音频输入通道,这是iOS系统为保证录音质量和音频资源合理分配的设计规则。

解决方案:延迟初始化录音输入节点+动态切换会话类别

要实现「APP启动不中断外部音频、录音时暂停、停止后恢复」的需求,核心思路是把录音相关的资源初始化和会话类别切换推迟到用户触发录音操作时执行,而非APP启动阶段。具体实现如下:

1. APP启动时仅初始化播放相关资源(不碰录音输入)

private var audioEngine: AVAudioEngine?
private var inputNode: AVAudioInputNode?
private var audioPlayerNode: AVAudioPlayerNode!

func setupAudioOnAppLaunch() {
    // 仅初始化播放链路,不获取录音输入节点
    audioEngine = AVAudioEngine()
    audioPlayerNode = AVAudioPlayerNode()
    audioEngine?.attach(audioPlayerNode)
    
    let format = AVAudioFormat(standardFormatWithSampleRate: AUDIO_SESSION_SAMPLE_RATE, channels: 1)
    audioEngine?.connect(audioPlayerNode, to: audioEngine!.mainMixerNode, format: format)
    
    // 设置播放类别的会话,允许与其他APP音频混音
    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(.playback, mode: .default, options: [.mixWithOthers, .defaultToSpeaker, .allowBluetooth])
        try audioSession.setActive(true)
        setupInterruptionObserver()
    } catch {
        audioErrorMessage = "Failed to set up audio session: \(error)"
    }
}

2. 用户触发录音时,切换会话类别并初始化录音资源

func startRecording() {
    guard let audioEngine = audioEngine else { return }
    
    // 切换到录音+播放类别,此时系统会自动暂停外部音频
    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth])
        try audioSession.setPreferredSampleRate(AUDIO_SESSION_SAMPLE_RATE)
        try audioSession.setPreferredIOBufferDuration(0.005)
        try audioSession.setActive(true)
        
        // 此时才获取输入节点并设置录音回调
        inputNode = audioEngine.inputNode
        let recordingFormat = inputNode!.inputFormat(forBus: 0)
        inputNode!.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, time in
            // 在这里处理录音数据
        }
        
        try audioEngine.start()
    } catch {
        audioErrorMessage = "Failed to start recording: \(error)"
    }
}

3. 停止录音后,切回播放类别恢复外部音频

func stopRecording() {
    guard let audioEngine = audioEngine, let inputNode = inputNode else { return }
    
    // 停止录音并清理资源
    audioEngine.stop()
    inputNode.removeTap(onBus: 0)
    self.inputNode = nil
    
    // 切换回播放类别,允许外部音频恢复播放
    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(.playback, mode: .default, options: [.mixWithOthers, .defaultToSpeaker, .allowBluetooth])
        try audioSession.setActive(true)
    } catch {
        audioErrorMessage = "Failed to stop recording: \(error)"
    }
}

补充说明

  • 启动阶段使用playback类别+mixWithOthers选项,能让你的APP与其他音频APP共存,不会中断外部播放。
  • 录音时切换到playAndRecord类别是必要的,因为iOS系统不允许多个APP同时占用音频输入通道,此时外部音频会自动暂停,属于系统规则。
  • 停止录音后切回playback类别,系统会自动恢复之前被暂停的外部音频播放(如果用户之前有在播放的话)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 10:35:13