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

SwiftUI界面在AVSpeech结束时卡顿问题求助

问题解决:语音播放结束后界面卡顿+音频会话停用失败

问题根源

音频会话停用操作阻塞主线程,加上停用失败的状态异常,导致界面滚动卡顿。错误出现在speechSynthesizer(_:didFinish:)方法中,同步执行的停用操作占用了主线程资源,同时会话状态处理不当引发报错。

修复方案

1. 后台线程执行音频会话停用

把停用操作移到后台线程,避免阻塞UI刷新:

func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
    DispatchQueue.global(qos: .background).async {
        do {
            try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
        } catch {
            print("Failed to deactivate audio session: \(error.localizedDescription)")
        }
    }
}

2. 优化音频会话激活逻辑

激活会话前先检查状态,避免重复激活;同时简化线程切换,语音合成无需强制回主线程:

func speak(say: String) {
    DispatchQueue.global(qos: .userInitiated).async {
        let audioSession = AVAudioSession.sharedInstance()
        do {
            if !audioSession.isActive {
                try audioSession.setCategory(.playback, options: [.duckOthers])
                try audioSession.setActive(true)
            }
            
            let utterance = AVSpeechUtterance(string: say)
            utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
            utterance.rate = 0.5
            
            self.synthesizer.speak(utterance)
        } catch {
            print("Audio session error: \(error.localizedDescription)")
        }
    }
}

3. 可选:添加停用容错处理

若停用失败,可延迟重试或忽略(部分场景下会话被占用时停用失败不影响功能):

func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
    DispatchQueue.global(qos: .background).async {
        let audioSession = AVAudioSession.sharedInstance()
        guard audioSession.isActive else { return }
        
        do {
            try audioSession.setActive(false, options: .notifyOthersOnDeactivation)
        } catch {
            print("Failed to deactivate audio session: \(error.localizedDescription)")
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                try? audioSession.setActive(false)
            }
        }
    }
}

关键说明

  • AVAudioSession.setActive()是同步操作,耗时调用会阻塞当前线程,必须放到后台执行。
  • AVSpeechSynthesizer.speak()无需强制在主线程调用,后台线程执行完全正常。
  • 激活前检查isActive状态,可避免重复激活导致的会话状态混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:52:34