From bb62534c6698c45e2fd9772176a7b038a9fde096 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Wed, 21 Jan 2026 22:39:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(audio):=20=E4=BC=98=E5=8C=96=E8=80=B3?= =?UTF-8?q?=E6=9C=BA=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=9A=84=E9=9F=B3=E9=A2=91?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E5=92=8C=E9=BA=A6=E5=85=8B=E9=A3=8E=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修正蓝牙耳机模式下音频模式选择问题,增加 A2DP 支持 针对电话和按住说话模式强制使用内置麦克风 优化音频会话配置逻辑,提升不同场景下的音频体验 --- .../Sources/azure_speech/AzureTtsHelper.swift | 45 ++++++++++++------- .../Sources/tools/SimpleAudioReceiver.swift | 25 ++++++++--- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureTtsHelper.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureTtsHelper.swift index 181fc90c4..89cba21d4 100644 --- a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureTtsHelper.swift +++ b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureTtsHelper.swift @@ -79,6 +79,7 @@ public class AzureTtsHelper: NSObject, ITtsService, AVAudioPlayerDelegate { private var synthEventAudioCount = 0 public var isHeadphones = true public var currentRecognitionMode: String = "normal" + private var previousRecognitionMode: String = "normal" @@ -415,6 +416,7 @@ public class AzureTtsHelper: NSObject, ITtsService, AVAudioPlayerDelegate { public func setPhoneCallMode(mod: String) -> Bool { + self.previousRecognitionMode = self.currentRecognitionMode self.currentRecognitionMode = mod self.isHeadphones = detectHeadphonesOutput() if isInitialized { @@ -1359,41 +1361,50 @@ private func applyAudioSessionForTTS() -> Bool { let desiredMode: AVAudioSession.Mode var desiredOptions: AVAudioSession.CategoryOptions = [] - if self.isTelephonyActive() { + let isHeadphonesConnected = outputs.contains(where: { $0.portType == .headphones || $0.portType == .headsetMic || $0.portType == .bluetoothA2DP }) + + if self.currentRecognitionMode == "phone_call" || self.currentRecognitionMode == "push_to_talk" { + desiredCategory = .playAndRecord + if isHeadphonesConnected { + desiredMode = .voiceChat + desiredOptions = [.allowBluetooth, .duckOthers] + } else { + desiredMode = .videoChat + desiredOptions = [.allowBluetooth, .defaultToSpeaker] + } + } else if self.isTelephonyActive() { desiredCategory = .playback desiredMode = .default desiredOptions.insert(.duckOthers) } else if isRecording { desiredCategory = .playAndRecord - if self.currentRecognitionMode == "phone_call" { - desiredMode = .voiceChat - desiredOptions.insert(.allowBluetooth) - } else { - desiredMode = self.isHeadphones ? .default : .videoChat + if self.isHeadphones { + desiredMode = .default desiredOptions.insert(.allowBluetooth) desiredOptions.insert(.allowBluetoothA2DP) - } - if self.isHeadphones { if otherAudioPlaying { desiredOptions.insert(.duckOthers) } } else { + desiredMode = .videoChat + desiredOptions.insert(.allowBluetooth) desiredOptions.insert(.mixWithOthers) - if !hasHeadphones { - desiredOptions.insert(.defaultToSpeaker) - } + desiredOptions.insert(.defaultToSpeaker) } } else if hasBluetoothHFP { desiredCategory = .playback - desiredMode = .default - desiredOptions.insert(.duckOthers) - } else { + desiredMode = .voicePrompt + desiredOptions = [.interruptSpokenAudioAndMixWithOthers, .allowBluetooth] + } else if hasHeadphones { desiredCategory = .playback - desiredMode = .spokenAudio + desiredMode = .default if otherAudioPlaying { desiredOptions.insert(.duckOthers) - desiredOptions.insert(.interruptSpokenAudioAndMixWithOthers) } + } else { + desiredCategory = .playback + desiredMode = .default + desiredOptions = [.duckOthers] } do { @@ -1406,7 +1417,7 @@ private func applyAudioSessionForTTS() -> Bool { _ = try? audioSession.setPreferredIOBufferDuration(0.02) } try audioSession.setActive(true) - if self.currentRecognitionMode == "phone_call", desiredCategory == .playAndRecord, !hasHeadphones { + if self.currentRecognitionMode == "phone_call", !self.isHeadphones { _ = try? audioSession.overrideOutputAudioPort(.speaker) } break 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 3944b0b0a..a2488a30c 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 @@ -170,12 +170,19 @@ public class SimpleAudioReceiver: NSObject { if currentRecognitionMode == "phone_call" { desiredMode = .voiceChat - desiredOptions = isHeadphones ? [.allowBluetooth] : [.allowBluetooth, .defaultToSpeaker] + if isHeadphones { + // 修正:增加 A2DP 选项以支持高质量蓝牙音频播放 + desiredOptions = [.allowBluetooth, .allowBluetoothA2DP] + } else { + desiredOptions = [.allowBluetooth, .defaultToSpeaker] + } } else { // normal, push_to_talk, ble_wakeup 等 - desiredMode = .videoChat if isHeadphones { + // 修正:使用 .voiceChat 模式以避免 .videoChat 强制外放 + desiredMode = .voiceChat desiredOptions = [.allowBluetooth, .allowBluetoothA2DP, .mixWithOthers] } else { + desiredMode = .videoChat desiredOptions = [.mixWithOthers, .defaultToSpeaker] } } @@ -218,18 +225,26 @@ public class SimpleAudioReceiver: NSObject { // 设置首选输入设备 if let inputs = audioSession.availableInputs { - if isHybridExternalMode { + // 针对电话和按住说话模式,在连接耳机时强制使用内置麦克风 + if isHeadphones && (currentRecognitionMode == "phone_call" || currentRecognitionMode == "push_to_talk") { + if let builtInMic = inputs.first(where: { $0.portType == .builtInMic }) { + try audioSession.setPreferredInput(builtInMic) + print("耳机模式下,为 \(currentRecognitionMode) 模式强制设置内置麦克风") + } + } else if isHybridExternalMode { // 混合模式: 强制使用内置麦克风 if let builtInMic = inputs.first(where: { $0.portType == .builtInMic }) { try audioSession.setPreferredInput(builtInMic) print("混合外部模式: 首选输入已设置为内置麦克风") } } else if let btInput = inputs.first(where: { $0.portType == .bluetoothHFP }), isHeadphones { - // 标准麦克风模式: 优先使用蓝牙耳机麦克风 + // 其他耳机模式: 优先使用蓝牙耳机麦克风 try audioSession.setPreferredInput(btInput) + print("标准耳机模式: 首选输入已设置为蓝牙麦克风") } else if let builtInMic = inputs.first(where: { $0.portType == .builtInMic }) { - // 兜底: 使用内置麦克风 + // 兜底或无耳机: 使用内置麦克风 try audioSession.setPreferredInput(builtInMic) + print("兜底: 首选输入已设置为内置麦克风") } } } else { // 纯外部源