Browse Source

fix(azure_speech): 优化蓝牙HFP麦克风检测和音频路由配置

动态检测蓝牙HFP输入设备并优先选择
移除默认外放选项,根据输出设备智能路由
添加音频会话配置的兜底逻辑
newdev_shunjiawei
liwei1dao 9 months ago
parent
commit
f1a8da1da1
  1. 2
      local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift
  2. 44
      local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift

2
local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift

@ -191,7 +191,7 @@ class AgentServiceImpl: NSObject {
""" """
} }
func initialize(config: [String: Any]) -> Bool { func initialize(config: [String: Any]) -> Bool {
if isInitialized { return true } // if isInitialized { return true }
// os_log("initialize: config=%{public}@", log: logger, type: .info, config) // os_log("initialize: config=%{public}@", log: logger, type: .info, config)
self.config = config self.config = config

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

@ -128,10 +128,11 @@ public class SimpleAudioReceiver: NSObject {
_isWriting=true _isWriting=true
self.audioSourceType = audioSourceType; self.audioSourceType = audioSourceType;
self.audioDataCallback = audioDataCallback self.audioDataCallback = audioDataCallback
print("startAudioRecord=audioSourceType\(audioSourceType)") print("音源设制---------- startAudioRecord=audioSourceType:\(audioSourceType)")
switch audioSourceType { switch audioSourceType {
case .microphone: case .microphone:
isReceiverHFP = true // 根据当前可用输入设备动态判定是否存在蓝牙HFP麦克风
isReceiverHFP = hasBluetoothHFPInput()
runMicrophoneCapture() runMicrophoneCapture()
case .external: case .external:
isReceiverHFP = false isReceiverHFP = false
@ -139,6 +140,21 @@ public class SimpleAudioReceiver: NSObject {
} }
} }
/**
* 检测是否存在蓝牙HFP输入设备
* 参数:无
* 返回值:存在返回true,否则返回false
* 异常:无
*/
private func hasBluetoothHFPInput() -> Bool {
let session = AVAudioSession.sharedInstance()
if let inputs = session.availableInputs {
return inputs.contains { $0.portType == .bluetoothHFP }
}
// 兜底使用当前路由的输入
return session.currentRoute.inputs.contains { $0.portType == .bluetoothHFP }
}
/** /**
* 开启音频写入线程 * 开启音频写入线程
* 修复:使用userInitiated QoS避免优先级反转 * 修复:使用userInitiated QoS避免优先级反转
@ -263,7 +279,7 @@ public class SimpleAudioReceiver: NSObject {
// 非通话:保持原有逻辑,但使用 .allowBluetooth 以支持录音(而不是 A2DP) // 非通话:保持原有逻辑,但使用 .allowBluetooth 以支持录音(而不是 A2DP)
desiredCategory = .playAndRecord desiredCategory = .playAndRecord
desiredMode = .videoChat desiredMode = .videoChat
desiredOptions = [.allowBluetooth, .mixWithOthers, .defaultToSpeaker] desiredOptions = [.allowBluetooth, .mixWithOthers]
//desiredOptions = [.mixWithOthers, .defaultToSpeaker] //desiredOptions = [.mixWithOthers, .defaultToSpeaker]
}else{ }else{
desiredCategory = .playAndRecord desiredCategory = .playAndRecord
@ -276,13 +292,13 @@ public class SimpleAudioReceiver: NSObject {
// 通话中:录音优先,避免 A2DP(仅播放),改用 HFP(.allowBluetooth) // 通话中:录音优先,避免 A2DP(仅播放),改用 HFP(.allowBluetooth)
desiredCategory = .record desiredCategory = .record
desiredMode = .voiceChat desiredMode = .voiceChat
desiredOptions = [.allowBluetoothA2DP] desiredOptions = [.allowBluetooth]
} else { } else {
if(isHeadphones){ if(isHeadphones){
// 非通话:保持原有逻辑,但使用 .allowBluetooth 以支持录音(而不是 A2DP) // 非通话:保持原有逻辑,但使用 .allowBluetooth 以支持录音(而不是 A2DP)
desiredCategory = .playAndRecord desiredCategory = .playAndRecord
desiredMode = .videoChat desiredMode = .videoChat
desiredOptions = [.allowBluetoothA2DP, .mixWithOthers, .defaultToSpeaker] desiredOptions = [.allowBluetoothA2DP, .mixWithOthers]
//desiredOptions = [.mixWithOthers, .defaultToSpeaker] //desiredOptions = [.mixWithOthers, .defaultToSpeaker]
}else{ }else{
desiredCategory = .playAndRecord desiredCategory = .playAndRecord
@ -307,6 +323,22 @@ public class SimpleAudioReceiver: NSObject {
// 保持激活;这里重复 setActive(true) 一般安全,但如果你观察到重复激活也触发路由回调,可在外层控制频率 // 保持激活;这里重复 setActive(true) 一般安全,但如果你观察到重复激活也触发路由回调,可在外层控制频率
try audioSession.setActive(true, options: .notifyOthersOnDeactivation) try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
// 路由校正:有蓝牙输出时不强制外放,并优先选择蓝牙输入(HFP)或内置麦克风
let outputs = audioSession.currentRoute.outputs
let hasBtOutput = outputs.contains { out in
out.portType == .bluetoothA2DP || out.portType == .bluetoothHFP || out.portType == .bluetoothLE
}
if hasBtOutput {
try audioSession.overrideOutputAudioPort(.none)
}
if let inputs = audioSession.availableInputs {
if isReceiverHFP, let btInput = inputs.first(where: { $0.portType == .bluetoothHFP }) {
try audioSession.setPreferredInput(btInput)
} else if let builtInMic = inputs.first(where: { $0.portType == .builtInMic }) {
try audioSession.setPreferredInput(builtInMic)
}
}
} catch { } catch {
// 兜底:尽量保证能开始录音 // 兜底:尽量保证能开始录音
print("音频会话配置失败,尝试兜底配置: \(error)") print("音频会话配置失败,尝试兜底配置: \(error)")
@ -561,5 +593,3 @@ private class LinkedBlockingQueue<T> {
} }
} }

Loading…
Cancel
Save