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

AVAudioEngine无法播放音频,三种实现无报错无声音如何排查解决?

AVAudioEngine 播放WAV文件无声音问题排查

问题描述

我正尝试使用AVAudioEngine播放wav格式音频文件,先后尝试了三种不同的实现方式,均无法正常输出声音,调试过程中无任何报错,所有方法均正常执行,请问问题出在哪里?

尝试方案1

private var audioEngine: AVAudioEngine = AVAudioEngine()
private var mixer: AVAudioMixerNode = AVAudioMixerNode()
private var audioFilePlayer: AVAudioPlayerNode = AVAudioPlayerNode()

func Play1() {
    guard let filePath = Bundle.main.url(forResource: "testwav", withExtension: "wav", subdirectory: "res") else {
        print("file not found")
        return
    }
    
    print("\(filePath)")
    
    guard let audioFile = try? AVAudioFile(forReading: filePath) else{ return }
    
    let audioFormat = audioFile.processingFormat
    let audioFrameCount = UInt32(audioFile.length)
    guard let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount)  else{ return }
    do{
        try audioFile.read(into: audioFileBuffer)
    } catch{
        print("over")
    }
    let mainMixer = audioEngine.mainMixerNode
    audioEngine.attach(audioFilePlayer)
    audioEngine.connect(audioFilePlayer, to:mainMixer, format: audioFileBuffer.format)
    audioEngine.connect(mainMixer, to:audioEngine.outputNode, format: audioFileBuffer.format)
    try? audioEngine.start()
    audioFilePlayer.play()
    audioFilePlayer.scheduleBuffer(audioFileBuffer, at: nil, options:AVAudioPlayerNodeBufferOptions.loops)
}

尝试方案2

private var audioEngine: AVAudioEngine = AVAudioEngine()
private var mixer: AVAudioMixerNode = AVAudioMixerNode()
private var audioFilePlayer: AVAudioPlayerNode = AVAudioPlayerNode()

func Play2() {
    DispatchQueue.global(qos: .background).async {
        self.audioEngine.attach(self.mixer)
        self.audioEngine.connect(self.mixer, to: self.audioEngine.outputNode, format: nil)
        // !important - start the engine *before* setting up the player nodes
        try! self.audioEngine.start()

        let audioPlayer = AVAudioPlayerNode()
        self.audioEngine.attach(audioPlayer)
        // Notice the output is the mixer in this case
        self.audioEngine.connect(audioPlayer, to: self.mixer, format: nil)
        
        guard let fileUrl = Bundle.main.url(forResource: "testwav", withExtension: "wav", subdirectory: "res") else {
            print("wav not found")
            return
        }
        
        do {
            let file = try AVAudioFile(forReading: fileUrl)
            
            audioPlayer.scheduleFile(file, at: nil, completionHandler: nil)
            audioPlayer.play(at: nil)
        } catch let error {
            print(error.localizedDescription)
        }
    }
}

尝试方案3

private var audioEngine: AVAudioEngine = AVAudioEngine()
private var mixer: AVAudioMixerNode = AVAudioMixerNode()
private var audioFilePlayer: AVAudioPlayerNode = AVAudioPlayerNode()

func Play3() {
    DispatchQueue.global(qos: .background).async {
        self.audioEngine = AVAudioEngine()
        _ = self.audioEngine.mainMixerNode
        
        self.audioEngine.prepare()
        do {
            try self.audioEngine.start()
        } catch {
            print(error)
        }
        
        guard let url = Bundle.main.url(forResource: "testwav", withExtension: "wav", subdirectory: "res") else {
            print("wav not found")
            return
        }
        
        let player = AVAudioPlayerNode()
        player.volume = 1.0
        
        do {
            let audioFile = try AVAudioFile(forReading: url)
            
            let format = audioFile.processingFormat
            print(format)
            
            self.audioEngine.attach(player)
            self.audioEngine.connect(player, to: self.audioEngine.mainMixerNode, format: format)
            
            player.scheduleFile(audioFile, at: nil, completionHandler: nil)
        } catch let error {
            print(error.localizedDescription)
        }
        
        player.play()
    }
}

修复方案

    1. 配置音频会话
      iOS系统下需要先配置AVAudioSession才能正常输出音频,添加如下代码到播放逻辑前:
do {
    try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
    try AVAudioSession.sharedInstance().setActive(true)
} catch {
    print("音频会话配置失败: \(error.localizedDescription)")
}

该配置会规避设备静音开关导致的静默问题,同时将音频路由到扬声器输出。

    1. 调整播放时序
      必须先调度音频内容,再调用play方法,方案1中先执行play再调度buffer的逻辑会导致播放触发时没有可播放的内容,交换两行代码的顺序即可。
    1. 修正节点生命周期
      方案2、3中在异步闭包内创建局部AVAudioPlayerNode,闭包执行完成后节点会被系统自动回收,导致播放中断,需要将使用的player节点声明为类的全局属性,保证生命周期覆盖整个播放过程。
    1. 删除多余节点连接
      mainMixerNode到outputNode的连接由系统自动管理,不需要手动设置,方案1中audioEngine.connect(mainMixer, to:audioEngine.outputNode, format: audioFileBuffer.format)属于多余代码,手动设置的格式和硬件输出格式不匹配时会导致无声音输出,直接删除即可。
    1. 排查基础设置
      确认设备媒体音量未处于最低值,测试音频文件本身可以正常播放,文件路径读取正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 05:39:02