sl11
sl11

Reputation: 61

How to fix AV Speech Synthesizer error "Unable to list voice folder" even after moving synthesizer outside class?

I'm trying to use AV Speech Synthesizer on an ARKit app (I've never used it before), but I keep getting the same error message "Unable to list voice folder."

I saw the same question being asked before, and all the answers mentioned iOS 16 being the difference, so they suggested moving the synthesizer declaration line outside the function or moving it directly under where I import AVFoundation.

let synthesizer = AVSpeechSynthesizer()

However, I still get the same error message no matter where I put this line. I'm pretty new to Swift and app development, so I suspect there's another problem, but the relevant code roughly looks like this:

import AVFoundation
let synthesizer = AVSpeechSynthesizer()

//within the view controller class:
func testSpeak() {
    
    let utterance = AVSpeechUtterance(string: "screen has been tapped")
    utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
    synthesizer.speak(utterance)

}

Are there any alternatives to using AVSpeechSynthesizer if I can't get it to work? I just need something that can read a few strings aloud to users.

Upvotes: 6

Views: 5281

Answers (4)

peetadelic
peetadelic

Reputation: 184

Using SwiftUI

When I combined both of the answers above, so from @Vinoth Vino and @devdchaudhary I made it work.

  1. take AVSpeechSynthesizer outside of the local scope and made it @State variable
  2. handled audio session

here is the full code, btw I am working with Czech language, therefore you will see cs text in the code

import SwiftUI
import AVFoundation
struct ContentView: View {
    
    @State private var speechSynthesizer: AVSpeechSynthesizer? // 1) taking outside of the local scope of function `speak()`
    
    var body: some View {
        Button {
            speak()
        } label: {
            Text("Dotkni se mě.")
        }
        .buttonStyle(.borderedProminent)
        
        
    }
    
    func speak() {
        
        let audioSession = AVAudioSession() // 2) handle audio session first, before trying to read the text
        do {
            try audioSession.setCategory(.playback, mode: .default, options: .duckOthers)
            try audioSession.setActive(false)
        } catch let error {
            print("❓", error.localizedDescription)
        }
        
        speechSynthesizer = AVSpeechSynthesizer()
        
        let speechUtterance = AVSpeechUtterance(string: "Vepřík")
        speechUtterance.voice = AVSpeechSynthesisVoice(language: "cs")
        
        speechSynthesizer?.speak(speechUtterance)
    }
}
#Preview {
    ContentView()
}

Upvotes: 4

Vinoth
Vinoth

Reputation: 9734

In SwiftUI, it worked when I added the synthesizer property with the @State property wrapper. It's not working when I create the property inside the speak method.

struct SpeechView: View {
    @State private var speechSynthesizer: AVSpeechSynthesizer?
    
    var body: some View {
        Button("Speak") {
            speak(text: "Hello World")
        }
    }
    
    func speak(text: String) {
        let utterance = AVSpeechUtterance(string: text)
        utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
        utterance.rate = 0.1

        speechSynthesizer = AVSpeechSynthesizer()
        speechSynthesizer?.speak(utterance)
    }
}

Upvotes: 4

Symon
Symon

Reputation: 1065

Change let to var, then its works fine.

Declare synthesizer outside of the function and it should be var, not let

var synthesizer = AVSpeechSynthesizer()

Upvotes: 5

devdchaudhary
devdchaudhary

Reputation: 718

It means that you haven't changed a previous audioSession's category back to playback.

Are you also recording somewhere else?

If so set your audioSession back to playback when you finish recording like this.

do {
    try audioSession?.setCategory(.playback, mode: .default, options: .duckOthers)
    try audioSession?.setActive(false)
} catch {
    // handle errors
}

Upvotes: 1

Related Questions