更改 AKPlayer 文件时 Audiokit 崩溃

syf*_*seq 5 swift audiokit

我最近完成了从 AudioKit 3.7 到 4.2 的迁移(使用 Cocoapods),这是 XCode 9.3 所需的。我按照迁移指南将 AKAudioPlayer 更改为 AKPlayer。

问题

当 AKPlayer 播放音频文件时,AudioKit 崩溃并出现以下错误:

2018-04-17 09:32:43.042658+0200hearfit[3509:2521326][avae]AVAEInternal.h:103:_AVAE_CheckNoErr:[AVAudioEngineGraph.mm:3632:UpdateGraphAfterReconfig:(AUGraphParser::InitializeActiveNodesInOutputChain(ThisGraph, kOutputChainFull)遍历,*conn .srcNode,isChainActive)):错误-10875
2018-04-17 09:32:43.049372+0200hearfit[3509:2521326]*** 由于未捕获的异常“com.apple.coreaudio.avfaudio”而终止应用程序,原因:“错误-10875”
*** 首先抛出调用堆栈:
(0x1847d6d8c 0x1839905ec 0x1847d6bf8 0x18a0ff1a0 0x18a11bf58 0x18a12aab0 0x18a128cdc 0x18a1a1738 0x18a1a160c 0x10519192c 0x10519 d2f4 0x10519d64c 0x10503afdc 0x10507c4a0 0x10507c01c 0x104f6d9cc 0x1852233d4 0x18477faa8 0x18477f76c 0x18477f010 0x18477cb60 0x18 469cda8 0x18667f020 0x18e67d78c 0x10504dfd4 0x18412dfc0)
libc++abi.dylib:以 NSException 类型的未捕获异常终止

有时它发生在第一次播放时,有时第一次播放正确,但第二次播放则不然。

迁移之前一切都运行良好。我还尝试保留 AKAudioPlayer: 声音正常播放,但 AKFrequencyTracker 不再工作。

语境

这是我的设置:

设置 快速解释:

  • AKPlayer 1播放短音频文件(1 到 5 秒之间)
  • AKFrequencyTracker用于显示绘图
  • AKPlayer 2播放背景声音(音量必须可配置)
  • AKWhiteNoise允许进行一些手动体积测量(使用AKMixer 2体积属性)

用例示例

用户开始锻炼。使用 连续播放声音(循环),AKPlayer 2并且用户听一个单词(使用 播放AKPlayer 1),显示绘图。接下来,屏幕上会显示几个单词,用户必须选择正确的单词。然后听到一个新单词......等等。

所以我必须动态改变AKPlayer 1的播放文件。所有代码都写在一个专用的类中,一个单例。所有节点均在init()函数中设置。

// singleton
static let main = AudioPlayer()
private init() {

    let silenceUrl = Bundle.main.url(forResource: "silence", withExtension: "m4a", subdirectory: "audio")
    self.silenceFile = silenceUrl!

    self.mainPlayer = AKPlayer(url: self.silenceFile)!
    self.mainPlayer.volume = 1.0

    self.freqTracker = AKFrequencyTracker(self.mainPlayer, hopSize: 256, peakCount: 10)

    let noiseUrl = Bundle.main.url(forResource: "cocktail-party", withExtension: "m4a", subdirectory: "audio")
    self.noiseFile = noiseUrl!

    self.noisePlayer = AKPlayer(url: self.noiseFile)!

    self.noisePlayer.volume = 1.0
    self.noisePlayer.isLooping = true

    let mixer = AKMixer(self.freqTracker, self.noisePlayer)

    self.whiteNoise = AKWhiteNoise(amplitude: 1.0)
    self.whiteNoiseMixer = AKMixer(self.whiteNoise)
    self.whiteNoiseMixer.volume = 0
    self.mixer = AKMixer(mixer, self.whiteNoiseMixer)

    AudioKit.output = self.mixer
    do {
        try AudioKit.start()
    } catch (let error) {
        print(error)
    }

    // stop directly the white noise mixer
    self.whiteNoise.stop()
    self.whiteNoiseMixer.volume = self.whiteNoiseVolume

    self.mainPlayer.completionHandler = {
        DispatchQueue.main.async {
            if let timer = self.timer {
                timer.invalidate()
                self.timer = nil
            }

            if let completion = self.completionHandler {
                Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: { (_) in
                    completion()
                    self.completionHandler = nil
                })
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

要更改AKPlayer 1音频文件,我在同一类上使用此函数:

func play(fileUrl: URL, tracker: @escaping TrackerCallback, completion: (() -> Void)?) throws {

    self.completionHandler = completion
    let file = try AKAudioFile(forReading: fileUrl)

    self.mainPlayer.load(audioFile: file)
    self.mainPlayer.preroll()

    self.timer = Timer.scheduledTimer(withTimeInterval: self.trackerRefreshRate, repeats: true) { (timer) in
        tracker(self.freqTracker.frequency, self.freqTracker.amplitude)
    }

    self.mainPlayer.play()
}
Run Code Online (Sandbox Code Playgroud)

谢谢。

Rya*_*oni 3

我不确定您要替换到播放器中的内容,但如果文件的格式与以前的格式、通道、采样率等不同 - 您应该创建一个新的 AKPlayer 实例,而不是加载到同一个实例中。如果您的文件都是相同的格式,那么它应该可以正常工作。

也就是说,我还没有看到你展示的崩溃。

代码中另一件危险的事情是强制解开这些选项 - 你应该防止事情为零。AKPlayer实际上使用AVAudioFile,不需要AKAudioFile。

guard let akfile = try? AVAudioFile(forReading: url) else { return }

if akfile.channelCount != player?.audioFile?.processingFormat.channelCount ||
    akfile.sampleRate != player?.audioFile?.processingFormat.sampleRate {

    AKLog("Need to create new player as formats have changed.")
}
Run Code Online (Sandbox Code Playgroud)