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

通话中断结束后AudioKit引擎无法立即启动的问题求助

AudioKit MIDISampler 音频中断后立即重启无声音问题解决

问题背景

使用AudioKit的MIDISampler加载.exs音色库,配合AppleSequencer运行,节点结构如下:

output = mixer {
  MIDISampler
}

常规运行状态正常,但处理音频中断时出现异常:中断开始时暂停AudioKit引擎,中断结束后立即调用.start()重启引擎,无异常抛出,但控制台输出样本资源被释放的日志,之后音频无法播放或仅输出正弦波;延迟1秒重启引擎则一切正常,且相同代码处理应用前后台切换的暂停/恢复操作无问题。

控制台关键日志片段

SamplerBase.cpp:272   SamplerBase::Cleanup
      SamplerBase.cpp:307   SamplerBase::Reset(0, 0)
  InstrumentState.cpp:248   InstrumentState::Cleanup(0x129fbf7f0)
InstrumentManager.cpp:269   InstrumentManager::ReleaseSamples(0x280c205e0)
    SampleManager.cpp:545   SampleManager::ReleaseSample: Holder count for sample ID 2975638501413859767: 1
    SampleManager.cpp:548   SampleManager::ReleaseSample: Holder count now zero -- unref'ing and removing sample 0x12b50b940
       RefCounted.cpp:28    RefCounted::Unref(this = 0x12b50b940) count going to 0
    // 其余样本释放日志省略
    AudioStreamer.cpp:375   AudioStreamerImpl::Destroy: done -- now cleaning up

临时延迟恢复代码

else if type == .ended {
    print("Interruption ended")
    guard let optionsValue =
            info[AVAudioSessionInterruptionOptionKey] as? UInt else {
        return
    }

    let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
    if options.contains(.shouldResume) {
        print("Session should resume")

        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.resumeEngine()
        }
    }
}

问题分析

从日志可以看出,音频中断触发了SamplerBase的清理和重置逻辑,InstrumentManager直接释放了所有加载的样本资源——样本引用计数归0后被彻底卸载(包括文件缓存、音频流线程)。立即重启引擎时,MIDISampler的样本未完成重新加载,导致无有效音频输出;延迟1秒后样本完成自动加载,因此恢复正常。而前后台切换时AudioKit的资源清理逻辑不同,未触发样本释放,因此无此问题。

解决方案

1. 手动重新加载音色库样本

中断开始时保存MIDISampler的音色库路径,中断结束后重启引擎前手动重新加载样本,确保资源恢复:

// 类内保存音色库路径
private var samplerSoundBankURL: URL?

// 中断开始处理逻辑
case .began:
    AudioKit.engine.pause()
    sequencer.stop()
    // 记录当前加载的音色库路径
    samplerSoundBankURL = sampler.soundBankURL

// 中断结束处理逻辑
case .ended:
    guard let optionsValue = info[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
    let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
    
    if options.contains(.shouldResume) {
        // 优先重新加载音色库
        if let url = samplerSoundBankURL {
            do {
                try sampler.loadSoundBank(url: url)
            } catch {
                print("重新加载音色库失败: \(error)")
            }
        }
        // 重启引擎与 sequencer
        try? AudioKit.engine.start()
        sequencer.play()
    }

2. 确保音频会话正确激活

中断结束后先重新激活AVAudioSession,确认会话状态正常后再启动引擎:

do {
    try AVAudioSession.sharedInstance().setActive(true)
    try AudioKit.engine.start()
} catch {
    print("激活音频会话或启动引擎失败: \(error)")
}

3. 升级AudioKit版本

部分旧版本AudioKit存在中断时资源清理逻辑缺陷,升级到最新稳定版可能直接解决该问题。

4. 避免过度依赖.shouldResume选项

该选项并非在所有中断场景下都可靠,可改为主动检查音频会话状态,再执行恢复操作:

case .ended:
    DispatchQueue.main.async {
        do {
            try AVAudioSession.sharedInstance().setActive(true)
            // 重新加载样本+启动引擎逻辑
        } catch {
            print("恢复音频会话失败: \(error)")
        }
    }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:54:52