Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions ios/Plugin/TextToSpeech.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ enum QUEUE_STRATEGY: Int {
let synthesizer = AVSpeechSynthesizer()
var calls: [CAPPluginCall] = []
let queue = DispatchQueue(label: "backgroundAudioSetup", qos: .userInitiated, attributes: [], autoreleaseFrequency: .inherit, target: nil)
private weak var plugin: TextToSpeechPlugin?

override init() {
super.init()
Expand All @@ -25,6 +26,22 @@ enum QUEUE_STRATEGY: Int {
}
}

init(plugin: TextToSpeechPlugin) {
self.plugin = plugin
super.init()
self.synthesizer.delegate = self
// set session in background to avoid UI hangs.
queue.async {
do {
let avAudioSessionCategory: AVAudioSession.Category = .playback
try AVAudioSession.sharedInstance().setCategory(avAudioSessionCategory, mode: .default, options: .duckOthers)
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print("Error setting up AVAudioSession: \(error)")
}
}
}

public func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {
self.resolveCurrentCall()
}
Expand All @@ -33,6 +50,24 @@ enum QUEUE_STRATEGY: Int {
self.resolveCurrentCall()
}

public func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
guard let plugin = self.plugin else { return }

let start = characterRange.location
let end = characterRange.location + characterRange.length

if let range = Range(characterRange, in: utterance.speechString) {
let spokenWord = String(utterance.speechString[range])
let ret = [
"start": start,
"end": end,
"spokenWord": spokenWord
] as [String: Any]

plugin.notifyListeners("onRangeStart", data: ret)
}
}

@objc public func speak(_ text: String, _ lang: String, _ rate: Float, _ pitch: Float, _ category: String, _ volume: Float, _ voice: Int, _ queueStrategy: Int, _ call: CAPPluginCall) throws {
if queueStrategy == QUEUE_STRATEGY.QUEUE_FLUSH.rawValue {
self.synthesizer.stopSpeaking(at: .immediate)
Expand Down
6 changes: 5 additions & 1 deletion ios/Plugin/TextToSpeechPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import AVFoundation
public class TextToSpeechPlugin: CAPPlugin {
private static let errorUnsupportedLanguage = "This language is not supported."

private let implementation = TextToSpeech()
private var implementation: TextToSpeech!

public override func load() {
implementation = TextToSpeech(plugin: self)
}

@objc public func speak(_ call: CAPPluginCall) {
let text = call.getString("text") ?? ""
Expand Down