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 a3b4380e2..0ae23d2e4 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 @@ -123,6 +123,9 @@ public class SimpleAudioReceiver: NSObject { /** * 开始音频输入 + * 参数:audioSourceType 音频源类型(microphone 或 external);audioDataCallback 音频数据回调 + * 返回值:无 + * 异常:无(内部捕获并打印错误,不抛出) */ public func startAudioRecord(audioSourceType: AudioSourceType = .microphone, audioDataCallback: AudioDataCallback?) { _isWriting=true @@ -131,8 +134,10 @@ public class SimpleAudioReceiver: NSObject { print("音源设制---------- startAudioRecord=audioSourceType:\(audioSourceType)") switch audioSourceType { case .microphone: - // 根据当前可用输入设备动态判定是否存在蓝牙HFP麦克风 - isReceiverHFP = hasBluetoothHFPInput() + // 唤醒后禁用通话音道(HFP),改为手机麦克风 + A2DP 输出 + isReceiverHFP = false + // 动态检测是否存在耳机/蓝牙输出,用于后续路由选项计算 + isHeadphones = detectHeadphonesOutput() runMicrophoneCapture() case .external: isReceiverHFP = false @@ -155,6 +160,23 @@ public class SimpleAudioReceiver: NSObject { return session.currentRoute.inputs.contains { $0.portType == .bluetoothHFP } } + /** + * 检测是否存在耳机/蓝牙输出设备(用于决定是否启用A2DP而非扬声器) + * 参数:无 + * 返回值:存在返回true,否则返回false + * 异常:无 + */ + private func detectHeadphonesOutput() -> Bool { + let session = AVAudioSession.sharedInstance() + let outputs = session.currentRoute.outputs + return outputs.contains { out in + out.portType == .bluetoothA2DP || + out.portType == .bluetoothHFP || + out.portType == .bluetoothLE || + out.portType == .headphones + } + } + /** * 开启音频写入线程 * 修复:使用userInitiated QoS避免优先级反转 @@ -246,13 +268,50 @@ public class SimpleAudioReceiver: NSObject { private func runExternalCapture() { if audioSourceType == .external { do { - // 根据通话状态进行安全的音频会话配置 - try safeConfigureAudioSessionForMic() + // 停止麦克风采集,确保不走通话音道 + micCapture.stopCapture() + // 外部模式会话配置:禁止HFP,仅允许A2DP/耳机输出 + try safeConfigureAudioSessionForExternal() } catch { print("设置音频会话失败: \(error.localizedDescription)") } //pushAudioData(data: Data()) - micCapture.stopCapture() + } + } + + /** + * 外部音频源的安全音频会话配置(禁止HFP通话音道) + * 参数:无 + * 返回值:无 + * 异常:可能抛出AVAudioSession设置错误(内部捕获并兜底) + */ + private func safeConfigureAudioSessionForExternal() throws { + let audioSession = self.audioSession + do { + // 外部模式不录麦,仅做播放路由;有耳机时只允许A2DP,禁止HFP + let outputs = audioSession.currentRoute.outputs + let hasHeadphones = outputs.contains { out in + out.portType == .bluetoothA2DP || + out.portType == .bluetoothLE || + out.portType == .headphones + } + let desiredCategory: AVAudioSession.Category = .playback + let desiredMode: AVAudioSession.Mode = .videoChat + let desiredOptions: AVAudioSession.CategoryOptions = hasHeadphones + ? [.allowBluetoothA2DP, .mixWithOthers] + : [.mixWithOthers, .defaultToSpeaker] + + let needsSetCategory = (audioSession.category != desiredCategory) || (audioSession.mode != desiredMode) + if needsSetCategory { + try audioSession.setCategory(desiredCategory, mode: desiredMode, options: desiredOptions) + } + // 取消扬声器强制,确保耳机/A2DP优先 + try audioSession.overrideOutputAudioPort(.none) + try audioSession.setActive(true, options: .notifyOthersOnDeactivation) + } catch { + print("外部模式音频会话配置失败,兜底到playback: \(error)") + try audioSession.setCategory(.playback, mode: .default, options: [.mixWithOthers, .defaultToSpeaker]) + try audioSession.setActive(true, options: .notifyOthersOnDeactivation) } } /** @@ -592,4 +651,3 @@ private class LinkedBlockingQueue { } } } -