swiftxcodeswiftuiavspeechsynthesizeravspeechutterance

Swift How to stop current running Voice Output of AVSpeechSynthesizer


In my app I have a behavior where it can happen that 2 AVSpeech synthesizers are playing at the same time and would therefore overlap. In this case, is there a way to cancel all voice output currently being played as soon as a new voice output is started? Thanks very much! This is my code:

    func makeVoiceOutput(_ text: String) {
    let spech = AVSpeechUtterance(string: text)
    spech.voice = AVSpeechSynthesisVoice(language: Locale.current.languageCode)
    
    let synth = AVSpeechSynthesizer()
    synth.speak(spech)
}

Solution

  • The AVSpeechSynthesizer documentation https://developer.apple.com/documentation/avfaudio/avspeechsynthesizer/ says:

    If the synthesizer is speaking, the synthesizer adds utterances to a queue and speaks them in the order it receives them.

    So you should add your speech texts to an instance of AVSpeechSynthesizer that you create once, and not create a new one every time in your func. That should lead to queueing the spoken texts one after another.

    Alternatively using isSpeaking and stopSpeaking you can also stop the current speech output.

    struct ContentView: View {
        
        let synth = AVSpeechSynthesizer() // create once
    
        @State private var input = ""
        
        var body: some View {
            Form {
                TextField("Text", text: $input)
                Button("Speak") {
                    makeVoiceOutput(input)
                }
                Button("Stop") {
                    stopVoiceOutput()
                }
            }
        }
        
        func makeVoiceOutput(_ text: String) {
            let spech = AVSpeechUtterance(string: text)
            spech.voice = AVSpeechSynthesisVoice(language: Locale.current.languageCode)
    //        let synth = AVSpeechSynthesizer()
            synth.speak(spech)
        }
        
        func stopVoiceOutput() {
            synth.stopSpeaking(at: .immediate)
        }
    }