From ef5c9d94aebbabff790227a4e4e07e056320baf7 Mon Sep 17 00:00:00 2001 From: Colton Grubbs Date: Fri, 10 Nov 2023 15:12:48 -0500 Subject: [PATCH 1/2] Fix synthesizeToFile on iOS 17+ --- ios/Classes/SwiftFlutterTtsPlugin.swift | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/ios/Classes/SwiftFlutterTtsPlugin.swift b/ios/Classes/SwiftFlutterTtsPlugin.swift index 3387b34..baa590a 100644 --- a/ios/Classes/SwiftFlutterTtsPlugin.swift +++ b/ios/Classes/SwiftFlutterTtsPlugin.swift @@ -193,19 +193,25 @@ public class SwiftFlutterTtsPlugin: NSObject, FlutterPlugin, AVSpeechSynthesizer let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent(fileName) NSLog("Saving utterance to file: \(fileURL.absoluteString)") - if output == nil { - do { - output = try AVAudioFile( - forWriting: fileURL, - settings: pcmBuffer.format.settings, - commonFormat: .pcmFormatInt16, - interleaved: false) - } catch { - NSLog(error.localizedDescription) + if output == nil { + do { + if #available(iOS 17.0, *) { + guard let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: Double(22050), channels: 1, interleaved: false) else { + NSLog("Error creating audio format for iOS 17+") failed = true return + } + output = try AVAudioFile(forWriting: fileURL, settings: audioFormat.settings) + } else { + output = try AVAudioFile(forWriting: fileURL, settings: pcmBuffer.format.settings, commonFormat: .pcmFormatInt16, interleaved: false) } + } catch { + NSLog("Error creating AVAudioFile: \(error.localizedDescription)") + failed = true + return } + } + try! output!.write(from: pcmBuffer) } From ed48bd1d924ed96d0567c8be171c2640780e0a10 Mon Sep 17 00:00:00 2001 From: sososdk <46806014+sososdk@users.noreply.github.com> Date: Mon, 18 Sep 2023 17:42:11 +0800 Subject: [PATCH 2/2] fix(android): ConcurrentModificationException. --- .../tundralabs/fluttertts/FlutterTtsPlugin.kt | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt b/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt index d934636..99b0bbf 100644 --- a/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt +++ b/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt @@ -199,11 +199,13 @@ class FlutterTtsPlugin : MethodCallHandler, FlutterPlugin { } // Handle pending method calls (sent while TTS was initializing) - isTtsInitialized = true - for (call in pendingMethodCalls) { - call.run() + synchronized(this@FlutterTtsPlugin) { + isTtsInitialized = true + for (call in pendingMethodCalls) { + call.run() + } + pendingMethodCalls.clear() } - pendingMethodCalls.clear() invokeMethod("tts.init", isTtsInitialized) } else { Log.e(tag, "Failed to initialize TextToSpeech with status: $status") @@ -227,9 +229,12 @@ class FlutterTtsPlugin : MethodCallHandler, FlutterPlugin { } // Handle pending method calls (sent while TTS was initializing) - isTtsInitialized = true - for (call in pendingMethodCalls) { - call.run() + synchronized(this@FlutterTtsPlugin) { + isTtsInitialized = true + for (call in pendingMethodCalls) { + call.run() + } + pendingMethodCalls.clear() } } else { Log.e(tag, "Failed to initialize TextToSpeech with status: $status") @@ -238,11 +243,13 @@ class FlutterTtsPlugin : MethodCallHandler, FlutterPlugin { override fun onMethodCall(call: MethodCall, result: Result) { // If TTS is still loading - if (!isTtsInitialized) { - // Suspend method call until the TTS engine is ready - val suspendedCall = Runnable { onMethodCall(call, result) } - pendingMethodCalls.add(suspendedCall) - return + synchronized(this@FlutterTtsPlugin) { + if (!isTtsInitialized) { + // Suspend method call until the TTS engine is ready + val suspendedCall = Runnable { onMethodCall(call, result) } + pendingMethodCalls.add(suspendedCall) + return + } } when (call.method) { "speak" -> { @@ -270,8 +277,10 @@ class FlutterTtsPlugin : MethodCallHandler, FlutterPlugin { } val b = speak(text) if (!b) { - val suspendedCall = Runnable { onMethodCall(call, result) } - pendingMethodCalls.add(suspendedCall) + synchronized(this@FlutterTtsPlugin) { + val suspendedCall = Runnable { onMethodCall(call, result) } + pendingMethodCalls.add(suspendedCall) + } return } // Only use await speak completion if queueMode is set to QUEUE_FLUSH