通话中断结束后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
相关产品推荐
相关产品推荐

