skip to Main Content

The AVSpeechSynthesizer works well if I don’t try to stop it. After stopping and restarting, the next utterance begins where the last ended.
E.g. "Hello World" and "Hello Earth". When I stop the first one after "Hello", the next one will be spoken just as "Earth".
Want I want is the full sentence. So:

Actual:

  • "Hello" – stopped
  • "Earth"

What I want:

  • "Hello" – stopped
  • "Hello Earth"

.

class TextToSpeechService: NSObject, AVSpeechSynthesizerDelegate {
    
    let synthesizer: AVSpeechSynthesizer = AVSpeechSynthesizer()
    var wasStopped: Bool = false
    
    init () {
        super.init()
        self.synthesizer.delegate = self
    }
    
    public func start (text: String, completion: @escaping (Result<Void, TextToSpeechError>) -> Void) {
        self.setAudioPreferences()
        self.wasStopped = false
    
        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")


            self.synthesizer.speak(utterance)
        } else {
            print("LANGUAGE NOT AVAILABLE")
        }
    }
    
    public func stop () {
        self.wasStopped = true
        self.synthesizer.stopSpeaking(at: .immediate)
    }
    
    func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {
        if !wasStopped {
            print("success speaking")
        }
    }
    
    func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
        if !wasStopped {
            print("success speaking")
        }
    }
    
    func setAudioPreferences () {
        do {
            let session = AVAudioSession.sharedInstance()
            try session.setCategory(AVAudioSession.Category.playback, options: [.defaultToSpeaker, .allowBluetooth, .allowBluetoothA2DP])
        } catch let error {
            print("audioSession properties weren't set. Error: (error.localizedDescription)")
        }
    }
}

Calls (shortened)

let textToSpeechService = TextToSpeechService()
textToSpeechService.start(text: "Hello World")
// after word "Hello"
textToSpeechService.stop()
textToSpeechService.start(text: "Hello Earth")

Is it possible to reset the speechSynthesizer?

2

Answers


  1. Chosen as BEST ANSWER

    The text to speech service was just a part of the problem. I also have a speech recognizer and I always set the audio preferences.

    Wrong 🚫

    TTS:

    try session.setCategory(AVAudioSession.Category.playback, options: [.defaultToSpeaker, .allowBluetooth, .allowBluetoothA2DP])
    

    STT:

    try session.setCategory(AVAudioSession.Category.record, options: [.defaultToSpeaker, .allowBluetooth, .allowBluetoothA2DP])
    

    Right ✅

    Now, I do this only once on init and for both:

    try session.setCategory(AVAudioSession.Category.playAndRecord, options: [.defaultToSpeaker, .allowBluetooth, .allowBluetoothA2DP])
    

  2. I had the same issue …
    At the moment you can use a "hack" – changing the stop method as below:

    public func stop () {
            self.wasStopped = true
            self.synthesizer.stopSpeaking(at: .immediate)
            let utterance = AVSpeechUtterance(string: "")
            self.synthesizer.speak(utterance)
            self.synthesizer.stopSpeaking(at: .immediate)
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search