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() } }
修复方案
- 配置音频会话
iOS系统下需要先配置AVAudioSession才能正常输出音频,添加如下代码到播放逻辑前:
- 配置音频会话
do { try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default) try AVAudioSession.sharedInstance().setActive(true) } catch { print("音频会话配置失败: \(error.localizedDescription)") }
该配置会规避设备静音开关导致的静默问题,同时将音频路由到扬声器输出。
- 调整播放时序
必须先调度音频内容,再调用play方法,方案1中先执行play再调度buffer的逻辑会导致播放触发时没有可播放的内容,交换两行代码的顺序即可。
- 调整播放时序
- 修正节点生命周期
方案2、3中在异步闭包内创建局部AVAudioPlayerNode,闭包执行完成后节点会被系统自动回收,导致播放中断,需要将使用的player节点声明为类的全局属性,保证生命周期覆盖整个播放过程。
- 修正节点生命周期
- 删除多余节点连接
mainMixerNode到outputNode的连接由系统自动管理,不需要手动设置,方案1中audioEngine.connect(mainMixer, to:audioEngine.outputNode, format: audioFileBuffer.format)属于多余代码,手动设置的格式和硬件输出格式不匹配时会导致无声音输出,直接删除即可。
- 删除多余节点连接
- 排查基础设置
确认设备媒体音量未处于最低值,测试音频文件本身可以正常播放,文件路径读取正确。
- 排查基础设置
内容的提问来源于stack exchange,提问作者Sirop4ik
相关产品推荐
相关产品推荐

