diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift index 3000c5ee7..f5d2cf052 100644 --- a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift +++ b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift @@ -27,6 +27,16 @@ public class AzureAsrHelper: NSObject { private var networkMonitor: NetworkStateMonitor = NetworkStateMonitor() private var continuousCallback: ContinuousRecognizeCallback? private var isNetworkRecovering = false + + // 网络丢失计数器 + private var networkLostCount = 0 + // 最大网络丢失次数(3秒检测) + private let maxNetworkLostCount = 3 + + // 防抖机制相关变量 + private var lastNetworkLostTime: Int64 = 0 + private let networkLostDebounceInterval: Int64 = 3000 // 3秒防抖间隔 + // 状态管理 private var _isContinuousRecognitionActive = false @@ -141,61 +151,52 @@ public class AzureAsrHelper: NSObject { private func handleNetworkAvailable() { os_log("网络已恢复", log: log, type: .info) - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } + if !self.isNetworkRecovering { self.isNetworkRecovering = true os_log("网络恢复,准备重新启动识别", log: self.log, type: .info) - - // 如果之前在进行连续识别,重新启动 - DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { - self.restartContinuousRecognition() - } } - } + } - /** - * 重新启动连续识别(网络恢复时使用) + + /** + * 处理网络连接丢失(带防抖机制) */ - private func restartContinuousRecognition() { - os_log("重新启动连续识别", log: log, type: .info) + private func handleNetworkLost() { + let currentTime = Int64(Date().timeIntervalSince1970 * 1000) // 转换为毫秒 - // 检查continuousCallback是否为空 - guard let callback = continuousCallback else { - os_log("连续识别回调为空,无法重新启动", log: log, type: .info) + // 防抖机制:如果距离上次触发时间小于防抖间隔,则忽略本次触发 + if currentTime - lastNetworkLostTime < networkLostDebounceInterval { + os_log("网络丢失事件被防抖过滤,距离上次触发仅%{public}dms", log: log, type: .debug, currentTime - lastNetworkLostTime) return } - do { - _ = setupEventListeners(callback: callback) - isNetworkRecovering = false - os_log("连续识别重新启动成功", log: log, type: .info) - } catch { - os_log("重新启动连续识别失败: %@", log: log, type: .error, error.localizedDescription) - isNetworkRecovering = false - } - } - - - /** - * 立即停止音频处理 - */ - private func stopAudioProcessingImmediately() { - audioStream?.stopMicrophoneCapture() + // 更新最后触发时间 + lastNetworkLostTime = currentTime - if _isContinuousRecognitionActive { - do { - try recognizer?.stopContinuousRecognition() - _isContinuousRecognitionActive = false - os_log("因网络问题强制停止识别", log: log, type: .info) - } catch { - _isContinuousRecognitionActive = false - os_log("强制停止识别失败: %@", log: log, type: .error, error.localizedDescription) + // 这里启动一个3秒定时器,3秒后检查网络是否恢复 + DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { [weak self] in + guard let self = self else { return } + + os_log("网络不可用", log: self.log, type: .error) + let isNetworkAvailable = self.checkNetworkStatus() + + if isNetworkAvailable { + // 如果网络恢复,重置计数器和防抖时间 + os_log("网络已恢复,重置计数器", log: self.log, type: .info) + self.lastNetworkLostTime = 0 + self.isNetworkRecovering = true + } else { + self.continuousCallback?.onError(1000, "网络连接不可用,请检查网络设置") + os_log("网络仍未恢复,继续检测", log: self.log, type: .debug) + self.networkLostCount = 0 + self.stopContinuousRecognition() } } } + /** * 预初始化音频组件 * 在初始化阶段就准备好音频流和相关组件,减少首次启动延迟 @@ -245,13 +246,11 @@ public class AzureAsrHelper: NSObject { do { - guard recognizer != nil else { - if !setupRecognizer() { - print("重置识别器失败") - // callback.onError("重置识别器失败") - return false + if recognizer == nil { + // 检查continuousCallback是否为空,只有在不为空时才设置事件监听器 + if let callback = self.continuousCallback { + setupEventListeners(callback: callback) } - return false } print("startContinuousRecognition:\(audioSourceType)") @@ -266,7 +265,7 @@ public class AzureAsrHelper: NSObject { return true } catch { - audioStream?.stopMicrophoneCapture() + stopContinuousRecognition() _isContinuousRecognitionActive = false //callback.onError("启动连续识别失败: \(error.localizedDescription)") return false @@ -300,13 +299,10 @@ public class AzureAsrHelper: NSObject { do { _isContinuousRecognitionActive = false - if audioSourceType == .external { - //pushAudioData(data: Data()) - } - audioStream?.stopMicrophoneCapture() // 停止连续识别 try recognizer.stopContinuousRecognition() + self.recognizer = nil print("stopContinuousRecognition") return true } catch { @@ -320,6 +316,7 @@ public class AzureAsrHelper: NSObject { // 【修复】在 catch 块中安全地停止识别器,避免再次抛出异常 do { try recognizer.stopContinuousRecognition() + self.recognizer = nil } catch { // 如果强制停止也失败,记录错误但不再抛出异常 os_log("强制停止识别器失败: %@", log: log, type: .error, error.localizedDescription) @@ -623,18 +620,9 @@ public class AzureAsrHelper: NSObject { os_log("识别取消: %{public}@", log: self.log, type: .error, errorDetails) - // 检查是否为网络相关错误 - if self.isNetworkRelatedError(errorDetails) { - os_log("检测到网络相关错误,停止音频处理", log: self.log, type: .info) - self.stopAudioProcessingImmediately() - - // 如果不是正在恢复网络,通知上层网络错误 - if !self.isNetworkRecovering { - callback.onError(1000,"启动连续识别失败,网络连接已断开") - } - } else { + callback.onCanceled(reason, errorDetails) - } + } return true } @@ -845,75 +833,17 @@ extension AzureAsrHelper: NetworkStateMonitor.NetworkStateListener { func onNetworkAvailable() { os_log("网络已恢复", log: log, type: .info) - DispatchQueue.main.async { [weak self] in - self?.handleNetworkAvailable() - } + self.handleNetworkAvailable() + } - /** - * 处理网络丢失事件 - */ + + func onNetworkLost() { os_log("网络连接丢失", log: log, type: .error) - // 立即停止音频处理 - stopAudioProcessingImmediately() - - DispatchQueue.main.async { [weak self] in - self?.continuousCallback?.onError(1000,"网络连接已断开") - } + self.handleNetworkLost() } } -// //ios 语言检测 -// /** -// * 检测输入文本的语言,从支持的语言列表中选择最匹配的 -// * -// * @param text 需要检测的文本 -// * @return 从supportedLanguages中选择的最匹配语言代码 -// */ -// public func detectTextLanguage(_ text: String) -> String? { -// // 如果只有一种支持的语言,直接返回 -// if supportedLanguages.count == 1 { -// return supportedLanguages[0] -// } - -// // 获取所有可能的语言及其置信度 -// let languageResults = LanguageDetector.detectLanguageWithConfidence(from: text) - -// // 遍历检测结果,找到第一个在supportedLanguages中的语言 -// for result in languageResults { -// let azureLanguageCode = LanguageDetector.convertToAzureLanguageCode(result.language) -// if supportedLanguages.contains(azureLanguageCode) { -// return azureLanguageCode -// } -// } - -// // 如果没有找到匹配的语言,返回第一个支持的语言作为默认值 -// return supportedLanguages.first -// } - -// /** -// * 检测文本语言并返回详细信息 -// * -// * @param text 需要检测的文本 -// * @return 包含语言代码、置信度和语言名称的字典 -// */ -// public func detectTextLanguageWithDetails(_ text: String) -> [String: Any]? { -// let results = LanguageDetector.detectLanguageWithConfidence(from: text) -// guard let topResult = results.first else { -// return nil -// } - -// let azureLanguageCode = LanguageDetector.convertToAzureLanguageCode(topResult.language) -// let languageName = LanguageDetector.getLanguageName(from: topResult.language) - -// return [ -// "languageCode": azureLanguageCode, -// "confidence": topResult.confidence, -// "languageName": languageName, -// "originalCode": topResult.language -// ] -// } -