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 0f05370d8..03f33d64c 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 @@ -41,6 +41,11 @@ public class AzureAsrHelper: NSObject { private var lastAudioStartTime: Int64 = 0 private let audioOperationDebounceInterval: Int64 = 500 // 500毫秒防抖间隔 private var audioStartWorkItem: DispatchWorkItem? + // 串行队列和状态标记,用于顺序控制音频启动/停止,避免竞态 + private let audioOpQueue = DispatchQueue(label: "com.azure.speech.audio.operations") + private var isAudioStarting = false + private var isAudioStarted = false + private var pendingStopRequest = false // 状态管理 private var _isContinuousRecognitionActive = false @@ -269,9 +274,27 @@ public class AzureAsrHelper: NSObject { os_log("开始异步启动音频录制", log: self.log, type: .info) - // 在后台队列执行耗时的音频启动操作 - DispatchQueue.global(qos: .userInitiated).async { + // 使用串行队列,保证与 stop 顺序执行,避免竞态 + self.audioOpQueue.async { [weak self] in + guard let self = self else { + DispatchQueue.main.async { completion(false) } + return + } + + // 准备启动 + self.isAudioStarting = true + self.pendingStopRequest = false // 启动前清空旧的停止请求 let success = self.performAudioStart(audioSourceType: audioSourceType, audioDataCallback: audioDataCallback) + self.isAudioStarting = false + self.isAudioStarted = success + + // 如果启动过程中有 stop 请求,立即顺序停止,确保麦克风不会被重新“开启” + if self.pendingStopRequest { + self.pendingStopRequest = false + _ = self.performAudioStop() + self.isAudioStarted = false + os_log("启动完成后检测到待停止请求,已立即停止音频", log: self.log, type: .info) + } // 回到主队列执行完成回调 DispatchQueue.main.async { @@ -318,9 +341,18 @@ public class AzureAsrHelper: NSObject { private func stopAudioRecordAsync(completion: @escaping (Bool) -> Void) { os_log("开始立即停止音频录制", log: log, type: .info) - // 在后台队列执行耗时的音频停止操作 - DispatchQueue.global(qos: .userInitiated).async { + // 在串行队列顺序执行停止,避免与启动并发导致的竞态 + audioOpQueue.async { [weak self] in + guard let self = self else { + DispatchQueue.main.async { completion(false) } + return + } + // 若启动过程中收到停止请求,记录标记,启动完成后会立即停止 + if self.isAudioStarting { + self.pendingStopRequest = true + } let success = self.performAudioStop() + self.isAudioStarted = false // 回到主队列执行完成回调 DispatchQueue.main.async { @@ -333,7 +365,7 @@ public class AzureAsrHelper: NSObject { * 执行音频停止操作 */ private func performAudioStop() -> Bool { - do { + do { audioStream?.stopMicrophoneCapture() os_log("音频录制停止成功", log: log, type: .info) return true diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift index 47cef8139..4f9e3d02d 100644 --- a/local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift +++ b/local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift @@ -324,7 +324,6 @@ public func restoreOriginalAudioState() { public func stopMicrophoneCapture() { - guard _isWriting==true else { return } _isWriting=false micCapture.stopCapture()