更换AKPlayer文件时,Audiokit崩溃

时间:2018-04-17 08:34:17

标签: swift audiokit

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

问题

当AKPlayer播放音频文件时,AudioKit会因此错误而崩溃:

2018-04-17 09:32:43.042658+0200 hearfit[3509:2521326] [avae] AVAEInternal.h:103:_AVAE_CheckNoErr: [AVAudioEngineGraph.mm:3632:UpdateGraphAfterReconfig: (AUGraphParser::InitializeActiveNodesInOutputChain(ThisGraph, kOutputChainFullTraversal, *conn.srcNode, isChainActive)): error -10875
2018-04-17 09:32:43.049372+0200 hearfit[3509:2521326] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -10875'
*** First throw call stack:
(0x1847d6d8c 0x1839905ec 0x1847d6bf8 0x18a0ff1a0 0x18a11bf58 0x18a12aab0 0x18a128cdc 0x18a1a1738 0x18a1a160c 0x10519192c 0x10519d2f4 0x10519d64c 0x10503afdc 0x10507c4a0 0x10507c01c 0x104f6d9cc 0x1852233d4 0x18477faa8 0x18477f76c 0x18477f010 0x18477cb60 0x18469cda8 0x18667f020 0x18e67d78c 0x10504dfd4 0x18412dfc0)
libc++abi.dylib: terminating with uncaught exception of type NSException

有时它会在第一次播放时发生,有时第一次播放是正确完成的,但不是第二次播放。

迁移前一切都很顺利。我还尝试保留AKAudioPlayer:声音播放正确,但AKFrequencyTracker不再起作用。

上下文

这是我的设置:

Vue's documentation 快速解释:

  • 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
                })
            }
        }
    }
}

要更改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()
}

谢谢。

1 个答案:

答案 0 :(得分:1)

我不确定您要替换的内容是什么,但是如果文件格式与以前的格式,频道,采样率等不同,则应创建一个新的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.")
}