I am having an issue with the code that I posted below. I capture voice in my CarPlay app, then allow the user to have it read back to them using AVSpeechUtterance.
This works fine on some cars, but many of my beta testers report no audio being played. I have also experienced this in a rental car where the audio was either too quiet or the audio didn't play.
Does anyone see any issue with the code that I posted? This is for CarPlay specifically.
class CarPlayTextToSpeechService: NSObject, ObservableObject, AVSpeechSynthesizerDelegate {
private var speechSynthesizer = AVSpeechSynthesizer()
static let shared = CarPlayTextToSpeechService()
/// Completion callback
private var completionCallback: (() -> Void)?
override init() {
super.init()
speechSynthesizer.delegate = self
}
func configureAudioSession() {
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .voicePrompt, options: [.duckOthers, .interruptSpokenAudioAndMixWithOthers, .allowBluetoothHFP])
} catch {
print("Failed to set audio session category: \(error.localizedDescription)")
}
}
public func speak(_ text: String, completion: (() -> Void)? = nil) {
self.configureAudioSession()
// Store the completion callback
self.completionCallback = completion
Task(priority: .high) {
let speechUtterance = AVSpeechUtterance(string: text)
let langCode = Locale.preferredLocalLanguageCountryCode
if langCode == "en-US" {
speechUtterance.voice = AVSpeechSynthesisVoice(identifier: AVSpeechSynthesisVoiceIdentifierAlex)
} else {
speechUtterance.voice = AVSpeechSynthesisVoice(language: langCode)
}
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
speechSynthesizer.speak(speechUtterance)
}
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
Task {
stopSpeech()
try AVAudioSession.sharedInstance().setActive(false)
}
// Call completion callback if available
self.completionCallback?()
self.completionCallback = nil
}
func stopSpeech() {
speechSynthesizer.stopSpeaking(at: .immediate)
}
}