Browse Source

fix(audio): 优化耳机模式下的音频设置和麦克风选择逻辑

修正蓝牙耳机模式下音频模式选择问题,增加 A2DP 支持
针对电话和按住说话模式强制使用内置麦克风
优化音频会话配置逻辑,提升不同场景下的音频体验
weicu
liwei1dao 9 months ago
parent
commit
bb62534c66
  1. 43
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureTtsHelper.swift
  2. 25
      local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift

43
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 private var synthEventAudioCount = 0
public var isHeadphones = true public var isHeadphones = true
public var currentRecognitionMode: String = "normal" 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 { public func setPhoneCallMode(mod: String) -> Bool {
self.previousRecognitionMode = self.currentRecognitionMode
self.currentRecognitionMode = mod self.currentRecognitionMode = mod
self.isHeadphones = detectHeadphonesOutput() self.isHeadphones = detectHeadphonesOutput()
if isInitialized { if isInitialized {
@ -1359,41 +1361,50 @@ private func applyAudioSessionForTTS() -> Bool {
let desiredMode: AVAudioSession.Mode let desiredMode: AVAudioSession.Mode
var desiredOptions: AVAudioSession.CategoryOptions = [] 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 desiredCategory = .playback
desiredMode = .default desiredMode = .default
desiredOptions.insert(.duckOthers) desiredOptions.insert(.duckOthers)
} else if isRecording { } else if isRecording {
desiredCategory = .playAndRecord desiredCategory = .playAndRecord
if self.currentRecognitionMode == "phone_call" { if self.isHeadphones {
desiredMode = .voiceChat desiredMode = .default
desiredOptions.insert(.allowBluetooth)
} else {
desiredMode = self.isHeadphones ? .default : .videoChat
desiredOptions.insert(.allowBluetooth) desiredOptions.insert(.allowBluetooth)
desiredOptions.insert(.allowBluetoothA2DP) desiredOptions.insert(.allowBluetoothA2DP)
}
if self.isHeadphones {
if otherAudioPlaying { if otherAudioPlaying {
desiredOptions.insert(.duckOthers) desiredOptions.insert(.duckOthers)
} }
} else { } else {
desiredMode = .videoChat
desiredOptions.insert(.allowBluetooth)
desiredOptions.insert(.mixWithOthers) desiredOptions.insert(.mixWithOthers)
if !hasHeadphones {
desiredOptions.insert(.defaultToSpeaker) desiredOptions.insert(.defaultToSpeaker)
} }
}
} else if hasBluetoothHFP { } else if hasBluetoothHFP {
desiredCategory = .playback desiredCategory = .playback
desiredMode = .default desiredMode = .voicePrompt
desiredOptions.insert(.duckOthers) desiredOptions = [.interruptSpokenAudioAndMixWithOthers, .allowBluetooth]
} else { } else if hasHeadphones {
desiredCategory = .playback desiredCategory = .playback
desiredMode = .spokenAudio desiredMode = .default
if otherAudioPlaying { if otherAudioPlaying {
desiredOptions.insert(.duckOthers) desiredOptions.insert(.duckOthers)
desiredOptions.insert(.interruptSpokenAudioAndMixWithOthers)
} }
} else {
desiredCategory = .playback
desiredMode = .default
desiredOptions = [.duckOthers]
} }
do { do {
@ -1406,7 +1417,7 @@ private func applyAudioSessionForTTS() -> Bool {
_ = try? audioSession.setPreferredIOBufferDuration(0.02) _ = try? audioSession.setPreferredIOBufferDuration(0.02)
} }
try audioSession.setActive(true) try audioSession.setActive(true)
if self.currentRecognitionMode == "phone_call", desiredCategory == .playAndRecord, !hasHeadphones { if self.currentRecognitionMode == "phone_call", !self.isHeadphones {
_ = try? audioSession.overrideOutputAudioPort(.speaker) _ = try? audioSession.overrideOutputAudioPort(.speaker)
} }
break break

25
local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift

@ -170,12 +170,19 @@ public class SimpleAudioReceiver: NSObject {
if currentRecognitionMode == "phone_call" { if currentRecognitionMode == "phone_call" {
desiredMode = .voiceChat desiredMode = .voiceChat
desiredOptions = isHeadphones ? [.allowBluetooth] : [.allowBluetooth, .defaultToSpeaker] if isHeadphones {
// 修正:增加 A2DP 选项以支持高质量蓝牙音频播放
desiredOptions = [.allowBluetooth, .allowBluetoothA2DP]
} else {
desiredOptions = [.allowBluetooth, .defaultToSpeaker]
}
} else { // normal, push_to_talk, ble_wakeup 等 } else { // normal, push_to_talk, ble_wakeup 等
desiredMode = .videoChat
if isHeadphones { if isHeadphones {
// 修正:使用 .voiceChat 模式以避免 .videoChat 强制外放
desiredMode = .voiceChat
desiredOptions = [.allowBluetooth, .allowBluetoothA2DP, .mixWithOthers] desiredOptions = [.allowBluetooth, .allowBluetoothA2DP, .mixWithOthers]
} else { } else {
desiredMode = .videoChat
desiredOptions = [.mixWithOthers, .defaultToSpeaker] desiredOptions = [.mixWithOthers, .defaultToSpeaker]
} }
} }
@ -218,18 +225,26 @@ public class SimpleAudioReceiver: NSObject {
// 设置首选输入设备 // 设置首选输入设备
if let inputs = audioSession.availableInputs { 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 }) { if let builtInMic = inputs.first(where: { $0.portType == .builtInMic }) {
try audioSession.setPreferredInput(builtInMic) try audioSession.setPreferredInput(builtInMic)
print("混合外部模式: 首选输入已设置为内置麦克风") print("混合外部模式: 首选输入已设置为内置麦克风")
} }
} else if let btInput = inputs.first(where: { $0.portType == .bluetoothHFP }), isHeadphones { } else if let btInput = inputs.first(where: { $0.portType == .bluetoothHFP }), isHeadphones {
// 标准麦克风模式: 优先使用蓝牙耳机麦克风 // 其他耳机模式: 优先使用蓝牙耳机麦克风
try audioSession.setPreferredInput(btInput) try audioSession.setPreferredInput(btInput)
print("标准耳机模式: 首选输入已设置为蓝牙麦克风")
} else if let builtInMic = inputs.first(where: { $0.portType == .builtInMic }) { } else if let builtInMic = inputs.first(where: { $0.portType == .builtInMic }) {
// 兜底: 使用内置麦克风 // 兜底或无耳机: 使用内置麦克风
try audioSession.setPreferredInput(builtInMic) try audioSession.setPreferredInput(builtInMic)
print("兜底: 首选输入已设置为内置麦克风")
} }
} }
} else { // 纯外部源 } else { // 纯外部源

Loading…
Cancel
Save