1

I'm trying to create an app that, when the user doesn't know, says a text that changes every levels. The goal is to say a sentence displayed (yes, it is made for kids):

@IBAction func dontknow(_ sender: Any) {
    let utterance = AVSpeechUtterance(string: textLabel.text)
    utterance.voice = AVSpeechSynthesisVoice(language: "fr-FR")
    utterance.rate = 0.4

    let synthesizer = AVSpeechSynthesizer()
    synthesizer.speak(utterance)

}

The app is constructed like this: if user doesn't know -> he can click the button to say the text else if he is right -> he go to the next level.

The first time he enter the button to say, the app says something, but when the user tries to say the text and for the next level he clicks the button to say, nothing happens. It just throws this error: Failure starting audio queue ≥˚˛ˇ

Full code:

import UIKit
import AVFoundation
import Speech

class ReadViewController: UIViewController, SFSpeechRecognizerDelegate {
    var texts = ["Je mange des pâtes", "Bonjour Jean comment vas-tu", "Qui est-ce", "J'en ai marre", "Je ne te trouve pas gentil", "Pourquoi tu ne veux pas","Tu es si gentil", "Tu es beau", "Dans combien de temps", "Tu as fait de beaux rêves", "Cette application est une révolution"];
    var text = ""
    var transcriptedText = "";
    var effect:UIVisualEffect!




    @IBOutlet weak var dontknowButton: UIButton!
    @IBOutlet weak var listenButton: UIButton!
    @IBOutlet weak var visualEffectView: UIVisualEffectView!
    @IBOutlet var alertView: UIView!
    @IBOutlet weak var regameButton: UIButton!
    @IBOutlet weak var textView: UILabel!
    @IBOutlet weak var textLabel: UILabel!
    @IBOutlet weak var microphoneButton: UIButton!
    @IBOutlet weak var transci: UILabel!


    private let speechRecognizer = SFSpeechRecognizer(locale: Locale.init(identifier: "fr-FR"))  //1
    private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
    private var recognitionTask: SFSpeechRecognitionTask?
    private let audioEngine = AVAudioEngine()
    var recordingSession: AVAudioSession!
    var player: AVAudioPlayer!

    override func viewDidLoad() {
        super.viewDidLoad()
        listenButton.layer.cornerRadius = 10
        dontknowButton.layer.cornerRadius = dontknowButton.frame.width / 2
        self.restart()
        // Do any additional setup after loading the view.




        effect = visualEffectView.effect
        visualEffectView.layer.opacity = 0
        visualEffectView.effect = nil
        regameButton.layer.cornerRadius = 10


        microphoneButton.layer.cornerRadius = 10

        microphoneButton.isEnabled = false  //2

        speechRecognizer?.delegate = self  //3


        SFSpeechRecognizer.requestAuthorization { (authStatus) in  //4

            var isButtonEnabled = false

            switch authStatus {  //5
            case .authorized:
                isButtonEnabled = true

            case .denied:
                isButtonEnabled = false
                self.alert()

            case .restricted:
                isButtonEnabled = false
                self.alert()

            case .notDetermined:
                isButtonEnabled = false
                print("Speech recognition not yet authorized")
            }

            OperationQueue.main.addOperation() {
                self.microphoneButton.isEnabled = isButtonEnabled
            }


            //            self.effect = self.visualEffectView.effect
            //            self.visualEffectView.effect = nil


        }

    }
    func alert () {
        let alertController = UIAlertController (title: "Désolé", message: "Pour le bon fonctionnement de l'application, vous devez activer la reconnaissance vocale dans les réglages.", preferredStyle: .alert)

        let settingsAction = UIAlertAction(title: "Réglages", style: .default) { (_) -> Void in
            guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
                return
            }

            if UIApplication.shared.canOpenURL(settingsUrl) {
                UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
                    print("Settings opened: \(success)") // Prints true
                })
            }
        }
        alertController.addAction(settingsAction)


        present(alertController, animated: true, completion: nil)
    }
    func restart() {

        var randomNumber = random(0..<(texts.count))
        text = texts[randomNumber]

        textLabel.text = "\(text)"

    }



    func startRecording() {

        if recognitionTask != nil {
            recognitionTask?.cancel()
            recognitionTask = nil
        }

        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(AVAudioSessionCategoryRecord)
            try audioSession.setMode(AVAudioSessionModeMeasurement)
            try audioSession.setActive(true, with: .notifyOthersOnDeactivation)
        } catch {
            print("audioSession properties weren't set because of an error.")
        }

        recognitionRequest = SFSpeechAudioBufferRecognitionRequest()

        var inputNode = audioEngine.inputNode

        guard let recognitionRequest = recognitionRequest else {
            fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
        }

        recognitionRequest.shouldReportPartialResults = true

        recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in

            var isFinal = false

            if result != nil {

                self.transcriptedText = (result?.bestTranscription.formattedString)!
                self.transci.text = self.transcriptedText



                isFinal = (result?.isFinal)!


            }

            if error != nil || isFinal {
                self.audioEngine.stop()
                inputNode.removeTap(onBus: 0)

                self.recognitionRequest = nil
                self.recognitionTask = nil
                self.transci.text = ""

                self.microphoneButton.isEnabled = true
            }
        })

        let recordingFormat = inputNode.outputFormat(forBus: 0)
        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
            self.recognitionRequest?.append(buffer)
        }

        audioEngine.prepare()

        do {
            try audioEngine.start()
        } catch {
            print("audioEngine couldn't start because of an error.")
        }


    }


    func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
        if available {
            microphoneButton.isEnabled = true
        } else {
            microphoneButton.isEnabled = false
        }
    }





    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }




    func random(_ range:Range<Int>) -> Int
    {
        return range.lowerBound + Int(arc4random_uniform(UInt32(range.upperBound - range.lowerBound)))
    }


    @IBAction func start(_ sender: Any) {

        if audioEngine.isRunning {
            if self.transcriptedText == self.text {
                // When user won
                self.restart()
            }
            else {
                // When user loses

                animateIn()

            }
            audioEngine.stop()
            recognitionRequest?.endAudio()
            microphoneButton.isEnabled = false
            microphoneButton.setTitle("Commencer", for: .normal)

        } else {
            startRecording()
            microphoneButton.setTitle("Arrêter", for: .normal)
        }

    }
    @IBAction func listen(_ sender: Any) {
        let utterance = AVSpeechUtterance(string: "wesh")
        utterance.voice = AVSpeechSynthesisVoice(language: "fr-FR")!
        utterance.rate = 0.4

        let synthesizer = AVSpeechSynthesizer()
        synthesizer.speak(utterance)
    }
    @IBAction func reGameOn(_ sender: Any) {
        animateOut()
    }

    @IBAction func dontknow(_ sender: Any) {
        var randomNumber = random(0..<(texts.count))
        var tet = texts[randomNumber]
        let utterance = AVSpeechUtterance(string: textLabel.text)
        utterance.voice = AVSpeechSynthesisVoice(language: "fr-FR")!
        utterance.rate = 0.4

        let synthesizer = AVSpeechSynthesizer()
        synthesizer.speak(utterance)
        print(synthesizer.isSpeaking)
        print(synthesizer.isPaused)

    }



    func animateIn() {
        self.view.addSubview(alertView)
        alertView.center = self.view.center

        alertView.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
        alertView.alpha = 0

        UIView.animate(withDuration: 0.4) {
            self.alertView.layer.cornerRadius = 10
            self.visualEffectView.layer.opacity = 1
            self.visualEffectView.effect = self.effect
            self.alertView.alpha = 1
            self.alertView.transform = CGAffineTransform.identity
        }

    }


    func animateOut () {
        UIView.animate(withDuration: 0.3, animations: {
            self.alertView.layer.cornerRadius = 0
            self.alertView.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
            self.alertView.alpha = 0

            self.visualEffectView.effect = nil
            self.visualEffectView.layer.opacity = 0
        }) { (success:Bool) in
            self.alertView.removeFromSuperview()
        }
    }
}
Ashley Mills
  • 50,474
  • 16
  • 129
  • 160
Christophe Prat
  • 188
  • 1
  • 2
  • 18
  • The shown code works fine here. Can you post the code that is run in between "works" and "fails"? – shallowThought Mar 10 '18 at 13:12
  • Simulator or device? Do you have mcrophone permissions? – Sulthan Mar 11 '18 at 23:47
  • I have microphone permission. And device – Christophe Prat Mar 12 '18 at 05:18
  • Possible duplicate of [swift 3 using speech recognition and AVFoundation together](https://stackoverflow.com/questions/40639660/swift-3-using-speech-recognition-and-avfoundation-together) – Jeff May 22 '18 at 14:52
  • Please remove irrelevant code from your question… how you animate a view etc has nothing to do with your problem. Please read [ask], create a [mcve] and update the question. – Ashley Mills Jul 12 '18 at 14:14
  • @ChristophePrat got any solution ...same error getting me "Failure starting audio queue ≥˚˛ˇ" ...is there any suggestion then please tell me – Dhaval Bhadania Jul 27 '18 at 11:25

2 Answers2

5

In @IBAction func dontKnow try adding the following code in the end. This may work.

do{
      let _ = try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback,
                                                               with: .duckOthers)
  }catch{
      print(error)
  }
Abhay Singh
  • 94
  • 1
  • 6
0

Thank you, Abhay Singh! Adding that bit of code to the end of my "speak() function enabled audible speech on my iPhone 14 running iOS 16. Note that I had to update the code as follows as of April 2023:

   do{
      let _ = try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: .duckOthers)
   }catch{
          print(error)
   }

The audio volume is weirdly low. Perhaps the sharing causes this?

Ted Barnett
  • 21
  • 1
  • 1
  • 6