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

AVSpeechSynthesizer停止后新播报从断点续播如何重置

问题原因

这个是AVSpeechSynthesizer的系统级缓存问题:调用stopSpeaking(at: .immediate)立即中断播报后,系统不会立刻清空当前播放队列的进度缓存,如果在缓存清空完成前就对同一个合成器实例调用speak传入新文本,系统会错误地把新文本套用上一条内容的中断进度,导致新内容从截断位置开始播放,出现前半段丢失的情况。

可行解决方案

以下两个方案都可以彻底解决该问题,可根据业务场景选择:

方案1:重建合成器实例(最稳定,无时序依赖)

直接在每次启动新播报前重建AVSpeechSynthesizer实例,从根源上清空所有历史状态缓存,不需要等待停止回调,适配全系统版本。
修改后的核心代码如下:

class TextToSpeechService: NSObject, AVSpeechSynthesizerDelegate {
    // 改成可变变量,支持每次重建
    var synthesizer: AVSpeechSynthesizer!
    var wasStopped: Bool = false
    
    init () {
        super.init()
        // 初始化首次使用的合成器
        self.synthesizer = AVSpeechSynthesizer()
        self.synthesizer.delegate = self
    }
    
    public func start (text: String, completion: @escaping (Result<Void, TextToSpeechError>) -> Void) {
        self.setAudioPreferences()
        self.wasStopped = false
        
        // 停止旧实例、重建全新合成器,清空所有历史缓存
        self.synthesizer.stopSpeaking(at: .immediate)
        self.synthesizer = AVSpeechSynthesizer()
        self.synthesizer.delegate = self
    
        let hasLanguage = AVSpeechSynthesisVoice.speechVoices().first(where: { $0.language == "de-DE" }) != nil

        if (hasLanguage) {
            let utterance = AVSpeechUtterance(string: text)
            utterance.voice = AVSpeechSynthesisVoice(identifier: "com.apple.ttsbundle.siri_Helena_de-DE_compact")
            // 放到主队列异步执行,避开同runloop的状态冲突
            DispatchQueue.main.async {
                self.synthesizer.speak(utterance)
            }
        } else {
            print("LANGUAGE NOT AVAILABLE")
        }
    }
    
    public func stop () {
        self.wasStopped = true
        self.synthesizer.stopSpeaking(at: .immediate)
    }
    
    // 其余代理方法、音频设置方法保持原有逻辑即可
}

方案2:等待停止完成后再启动新播报(无需频繁创建实例)

如果不想频繁创建合成器实例,可以加状态标记,等didCancel代理回调触发、确认上一条内容完全取消后,再发起新的播报,避免缓存冲突。
核心修改点:

  • 新增isStopping状态位,标记当前是否正在执行停止操作
  • 调用stop时置位isStopping = true
  • 收到didCancel回调时重置isStopping = false,如果此时有待播报的排队内容,再调用speak
  • start方法检测到isStopping == true时,不要立刻调用speak,先把待播报文本暂存,等停止完成后再执行
验证效果

修改后调用逻辑的运行表现会符合预期:

  • "Hello" - 已停止
  • "Hello Earth"(完整播报)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 00:31:16