import Flutter import UIKit import MicrosoftCognitiveServicesSpeech import AVFoundation @available(iOS 13.0, *) public class SwiftAzureSpeechRecognitionPlugin: NSObject, FlutterPlugin { private var azureChannel: FlutterMethodChannel private var ttsChannel: FlutterMethodChannel private var asrHelper: AzureAsrHelper private var ttsHelper: AzureTtsHelper private static var eventStreamHandler: AzureEventStreamHandler? // 创建方法到通道的映射 private static var ttsMethodHandlers = [String: FlutterMethodCallHandler]() private static var asrMethodHandlers = [String: FlutterMethodCallHandler]() public static func register(with registrar: FlutterPluginRegistrar) { // ASR通道 let channel = FlutterMethodChannel(name: "com.deep_voice.azure_asr", binaryMessenger: registrar.messenger()) // TTS通道 let ttsChannel = FlutterMethodChannel(name: "com.deep_voice.azure_tts", binaryMessenger: registrar.messenger()) // 设置ASR事件通道 let eventChannel = FlutterEventChannel(name: "com.deep_voice.azure_asr_events", binaryMessenger: registrar.messenger()) eventStreamHandler = AzureEventStreamHandler() eventChannel.setStreamHandler(eventStreamHandler) let instance = SwiftAzureSpeechRecognitionPlugin( azureChannel: channel, ttsChannel: ttsChannel, eventStreamHandler: eventStreamHandler! ) // 直接设置各自通道的处理器 channel.setMethodCallHandler(instance.handleAsrMethodCalls) ttsChannel.setMethodCallHandler(instance.handleTtsMethodCalls) } // 新增直接处理方法调用的函数 private func handleTtsMethodCalls(_ call: FlutterMethodCall, result: @escaping FlutterResult) { handleTtsMethod(call, result) } private func handleAsrMethodCalls(_ call: FlutterMethodCall, result: @escaping FlutterResult) { handleAsrMethod(call, result) } init(azureChannel: FlutterMethodChannel, ttsChannel: FlutterMethodChannel, eventStreamHandler: AzureEventStreamHandler) { self.azureChannel = azureChannel self.ttsChannel = ttsChannel // 创建辅助类实例,使用自定义事件回调处理器 let eventHandler: (String, [String: Any]) -> Void = { eventName, arguments in DispatchQueue.main.async { if let eventSink = SwiftAzureSpeechRecognitionPlugin.eventStreamHandler?.eventSink { var eventData = arguments eventData["type"] = eventName eventSink(eventData) } } } asrHelper = AzureAsrHelper(eventHandler: eventHandler) ttsHelper = AzureTtsHelper(eventHandler: eventHandler) super.init() } private func handleAsrMethod(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { let args = call.arguments as? Dictionary switch call.method { case "initialize": // 仅在初始化时读取必要参数 guard let speechSubscriptionKey = args?["subscriptionKey"] as? String, !speechSubscriptionKey.isEmpty else { let errorMsg = "语音订阅密钥不能为空" print("[AzurePlugin] 错误: \(errorMsg)") result(FlutterError(code: "INVALID_SUBSCRIPTION_KEY", message: errorMsg, details: nil)) return } guard let serviceRegion = args?["region"] as? String, !serviceRegion.isEmpty else { let errorMsg = "服务区域不能为空" print("[AzurePlugin] 错误: \(errorMsg)") result(FlutterError(code: "INVALID_REGION", message: errorMsg, details: nil)) return } let supportedLanguages = args?["supportedLanguages"] as? [String] ?? [] let success = asrHelper.initialize( speechSubscriptionKey: speechSubscriptionKey, serviceRegion: serviceRegion, supportedLanguages: supportedLanguages.isEmpty ? nil : supportedLanguages ) result(success) case "startContinuousRecognition": // 只有使用参数时才验证 let success = asrHelper.startContinuousRecognition() result(success) case "stopContinuousRecognition": // 不需要额外参数 let success = asrHelper.stopContinuousRecognition() result(success) case "recognizeOnce": // 只有使用参数时才验证 let success = asrHelper.recognizeOnce() result(success) case "isContinuousRecognitionActive": // 不需要额外参数 result(asrHelper.isContinuousRecognitionActive()) case "dispose": // 不需要额外参数 print("[AzurePlugin] 释放ASR资源") asrHelper.dispose() result(true) default: print("[AzurePlugin] 错误: 未知ASR方法: \(call.method)") result(FlutterMethodNotImplemented) } } private func handleTtsMethod(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { let args = call.arguments as? Dictionary switch call.method { case "initialize": // 仅在初始化时验证参数 guard let speechSubscriptionKey = args?["subscriptionKey"] as? String, !speechSubscriptionKey.isEmpty else { let errorMsg = "语音订阅密钥不能为空" print("[AzurePlugin] 错误: \(errorMsg)") result(FlutterError(code: "INVALID_SUBSCRIPTION_KEY", message: errorMsg, details: nil)) return } guard let serviceRegion = args?["region"] as? String, !serviceRegion.isEmpty else { let errorMsg = "服务区域不能为空" print("[AzurePlugin] 错误: \(errorMsg)") result(FlutterError(code: "INVALID_REGION", message: errorMsg, details: nil)) return } let language = args?["language"] as? String ?? "zh-CN" print("[AzurePlugin] 初始化TTS,语言: \(language)") let success = ttsHelper.initialize(speechSubscriptionKey: speechSubscriptionKey, serviceRegion: serviceRegion, language: language) result(success) case "setVoice": // 仅获取voice参数 guard let voiceName = args?["voiceName"] as? String, !voiceName.isEmpty else { let errorMsg = "声音名称不能为空" print("[AzurePlugin] 错误: \(errorMsg)") result(FlutterError(code: "INVALID_VOICE", message: errorMsg, details: nil)) return } print("[AzurePlugin] 设置声音: \(voiceName)") let success = ttsHelper.setVoice(voiceName: voiceName) result(success) case "speakText": // 仅获取text参数 let text = args?["text"] as? String ?? "" if text.isEmpty { print("[AzurePlugin] 警告: 要播放的文本为空") result("OK") return } print("[AzurePlugin] 播放文本: \(text.prefix(50))...") let success = ttsHelper.speakText(text: text) result(success ? "OK" : "ERROR") case "speakSsml": // 仅获取ssml参数 guard let ssml = args?["ssml"] as? String, !ssml.isEmpty else { let errorMsg = "SSML内容不能为空" print("[AzurePlugin] 错误: \(errorMsg)") result(FlutterError(code: "INVALID_SSML", message: errorMsg, details: nil)) return } print("[AzurePlugin] 播放SSML: \(ssml.prefix(100))...") // 由于我们移除了speakSsml方法,这里改用speakText方法 // Azure SDK内部会自动检测是普通文本还是SSML let success = ttsHelper.speakText(text: ssml) result(success) case "stopSpeaking": // 不需要参数 print("[AzurePlugin] 停止播放") let success = ttsHelper.stopSpeaking() result(success) case "isSpeaking": // 不需要参数 result(ttsHelper.isSpeaking()) case "setSpeechParams": // 仅获取语音参数 let rate = args?["rate"] as? Int ?? 0 let pitch = args?["pitch"] as? Int ?? 0 let volume = args?["volume"] as? Int ?? 100 print("[AzurePlugin] 设置语音参数: rate=\(rate), pitch=\(pitch), volume=\(volume)") let success = ttsHelper.setSpeechParams(rate: rate, pitch: pitch, volume: volume) result(success) case "dispose": // 释放TTS资源 print("[AzurePlugin] 释放TTS资源") ttsHelper.dispose() result(true) default: print("[AzurePlugin] 错误: 未知TTS方法: \(call.method)") result(FlutterMethodNotImplemented) } } } // 用于处理事件流的辅助类 @available(iOS 13.0, *) class AzureEventStreamHandler: NSObject, FlutterStreamHandler { var eventSink: FlutterEventSink? func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { self.eventSink = events // 通知Flutter端事件通道已准备好 DispatchQueue.main.async { events(["type": "channelReady"]) } return nil } func onCancel(withArguments arguments: Any?) -> FlutterError? { self.eventSink = nil return nil } }