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

AVAudioPlayer循环播放FLAC音频出现点击噪音问题求助

问题

使用AVAudioPlayer循环播放FLAC格式音频时,每次循环启动都会产生点击噪音。该音频在Audacity中播放流畅,但在设备或模拟器中循环时,每次噪音强度不同。选择FLAC格式是因为它不会像MP3或M4A那样在文件首尾添加静音,且体积不如WAV庞大。

音频会话配置代码

// Audio
let audioSession = AVAudioSession.sharedInstance()
do {
    try audioSession.setCategory(.playback, mode: .default, options: [.mixWithOthers])
    try audioSession.setActive(true)
} catch {
    print("Setting category session for AVAudioSession Failed")
}

播放音频方法代码

// PlaySound
func playSound(soundId: Int) {
    let sound = ModelData.shared.sounds[soundId]
    
    if let bundle = Bundle.main.path(forResource: sound.filename, ofType: "flac") {
        let backgroundMusic = NSURL(fileURLWithPath: bundle)
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: backgroundMusic as URL)
            audioPlayer?.prepareToPlay()
            audioPlayer?.numberOfLoops = -1 // 无限循环
            audioPlayer?.play()
            isPlayingSounds = true
        } catch {
            print(error)
        }
    }
}

已尝试的方案:

  • 使用AVQueuePlayer重复播放时噪音消失,但无法实现无限循环且内存占用过高;
  • 使用AVLooper则循环间隔出现静音。

求可行的解决思路。


解决思路

1. 修复音频文件的衔接平滑度

点击噪音本质是音频首尾电平突变导致的,哪怕Audacity中听着流畅,AVAudioPlayer的循环衔接逻辑可能没做平滑处理。可以直接在Audacity中给音频首尾添加10ms以内的线性淡入淡出,或者手动将首尾采样点拉至0电平,从源头上消除电平突变的可能。

2. 改用AVAudioEngine实现精准无缝循环

AVAudioEngine是更底层的音频播放框架,能精准控制音频缓冲的循环播放,避免AVAudioPlayer的衔接缺陷。实现代码如下:

var audioEngine: AVAudioEngine?
var playerNode: AVAudioPlayerNode?
var audioBuffer: AVAudioPCMBuffer?

func setupLoopedSound(soundId: Int) {
    let sound = ModelData.shared.sounds[soundId]
    guard let audioUrl = Bundle.main.url(forResource: sound.filename, withExtension: "flac") else { return }
    
    audioEngine = AVAudioEngine()
    playerNode = AVAudioPlayerNode()
    guard let engine = audioEngine, let node = playerNode else { return }
    
    engine.attach(node)
    
    do {
        let audioFile = try AVAudioFile(forReading: audioUrl)
        audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat, frameCapacity: AVAudioFrameCount(audioFile.length))
        try audioFile.read(into: audioBuffer!)
        
        // 连接播放器节点到主混音器
        let mainMixer = engine.mainMixerNode
        engine.connect(node, to: mainMixer, format: audioBuffer?.format)
        
        // 循环播放缓冲
        node.scheduleBuffer(audioBuffer!, at: nil, options: .loops, completionHandler: nil)
        
        try engine.start()
        node.play()
        isPlayingSounds = true
    } catch {
        print("Audio engine setup failed: \(error)")
    }
}

这种方式只会加载一次音频缓冲到内存,既实现无限循环,又能精准控制衔接点,消除点击噪音。

3. 调整AVAudioPlayer的循环衔接逻辑

如果不想换框架,可以监听AVAudioPlayerDelegate的audioPlayerDidFinishPlaying(_:successfully:)方法,用双播放器无缝切换的方式避免原生循环的缺陷:

// 声明两个播放器实例
var audioPlayer1: AVAudioPlayer?
var audioPlayer2: AVAudioPlayer?
var currentPlayerIndex = 0

func setupDualPlayers(soundId: Int) {
    let sound = ModelData.shared.sounds[soundId]
    guard let url = Bundle.main.url(forResource: sound.filename, withExtension: "flac") else { return }
    
    do {
        audioPlayer1 = try AVAudioPlayer(contentsOf: url)
        audioPlayer2 = try AVAudioPlayer(contentsOf: url)
        audioPlayer1?.delegate = self
        audioPlayer2?.delegate = self
        audioPlayer1?.prepareToPlay()
        audioPlayer2?.prepareToPlay()
        audioPlayer1?.play()
        isPlayingSounds = true
    } catch {
        print(error)
    }
}

// 实现代理方法切换播放器
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
    if flag {
        if currentPlayerIndex == 0 {
            audioPlayer2?.play()
            currentPlayerIndex = 1
        } else {
            audioPlayer1?.play()
            currentPlayerIndex = 0
        }
    }
}

这种方式需要维护两个播放器实例,内存占用略高,但能避免原生循环的点击噪音。

4. 优化音频会话配置

尝试移除.mixWithOthers选项,或者将模式改为.moviePlayback,部分场景下音频会话的配置会影响播放的精度:

try audioSession.setCategory(.playback, mode: .moviePlayback, options: [])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 21:36:36