Dan.code
Dan.code

Reputation: 441

AVSpeechSynthesizer not working when new strings are added to be spoken [xcode - swift 4]

Im using the code below to read random sentences at a random time. However I run into the problem when a random sentence is called to be read while the previous sentence is still being spoken by the AVSpeechSynthesizer, making the second sentence not spoken. What I am asking is, how can I get the second sentence to be spoken after the first sentence is finished being spoken??

Any import would be appreciated. Cheers

Heres my code:

import UIKit
import AVFoundation


class ViewController: UIViewController {

var myTimer = Timer()
   let string = ["what kind of car do you have?", "do you like the beach?","did you bring a towel?","There are big waves today"]
var randomTimer = Int()


@objc func speakToMe(){

    let random = Int.random(in: 0...3)
    randomTimer = Int.random(in: 0...2)
    print(randomTimer)
    print(string[random])


let utterance = AVSpeechUtterance(string: string[random])
utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
utterance.rate = 0.1
let synthesizer = AVSpeechSynthesizer()
synthesizer.speak(utterance)

}

override func viewDidLoad() {
    super.viewDidLoad()
    speakToMe()
    myTimer = Timer.scheduledTimer(timeInterval: TimeInterval(randomTimer), target: self, selector: #selector(ViewController.speakToMe), userInfo: nil, repeats: true)
}


}   

Upvotes: 1

Views: 1621

Answers (1)

Dharmesh Kheni
Dharmesh Kheni

Reputation: 71854

You can simply use AVSpeechSynthesizerDelegate for that and you can remove timer from your code.

And to use AVSpeechSynthesizerDelegate first you need to confirm your view controller with AVSpeechSynthesizerDelegate like shown below:

class ViewController: UIViewController, AVSpeechSynthesizerDelegate {

next thing is you need to add

synthesizer.delegate = self

in your viewDidLoad method. and you need to declare

let synthesizer = AVSpeechSynthesizer()

outside the methods and inside the class.

And you can use randomElement property to find random element from string array.

And your final code will look like:

import UIKit
import AVFoundation

class ViewController: UIViewController, AVSpeechSynthesizerDelegate {

    let string = ["what kind of car do you have?", "do you like the beach?","did you bring a towel?","There are big waves today"]
    let synthesizer = AVSpeechSynthesizer()

    override func viewDidLoad() {
        super.viewDidLoad()
        synthesizer.delegate = self
        speakToMe()
    }

    @objc func speakToMe(){

        let utterance = AVSpeechUtterance(string: string.randomElement()!)
        utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
        utterance.rate = 0.1
        synthesizer.speak(utterance)

    }

    func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
        speakToMe()
    }
}

EDIT:

Since you are using only 4 elements in your array there will be possibilities to repeat same sentence many time when you take random string for it so you can add one more logic here which will prevent it.

Update your speakToMe function like below:

@objc func speakToMe(){

    var randomStr = string.randomElement()!
    while previousStr == randomStr {
        randomStr = string.randomElement()!
    }
    previousStr = randomStr
    let utterance = AVSpeechUtterance(string: randomStr)
    utterance.voice = AVSpeechSynthesisVoice(language: "en-GB")
    utterance.rate = 0.1
    synthesizer.speak(utterance)
}

And declare var previousStr = "" outside the function.

Upvotes: 2

Related Questions