|
|
@ -115,6 +115,11 @@ public class BleService: NSObject { |
|
|
// 音频发送配置常量 |
|
|
// 音频发送配置常量 |
|
|
private let AUDIO_CHUNK_SIZE = 120 // 每次发送120字节 |
|
|
private let AUDIO_CHUNK_SIZE = 120 // 每次发送120字节 |
|
|
private let AUDIO_SEND_INTERVAL: TimeInterval = 0.06 // 60毫秒间隔 |
|
|
private let AUDIO_SEND_INTERVAL: TimeInterval = 0.06 // 60毫秒间隔 |
|
|
|
|
|
// 收到 CODEC_CONTROL_CALL_Sleep 时插入的单次暂停时长(单位:秒) |
|
|
|
|
|
private let AUDIO_SEND_SLEEP_PAUSE: TimeInterval = 1.0 |
|
|
|
|
|
// 在该时间点之前 processAudioSendQueue 不消费队列,实现"插入一次 1000ms 暂停" |
|
|
|
|
|
private var nextSendEarliestAt: Date? |
|
|
|
|
|
private let nextSendEarliestLock = NSLock() |
|
|
|
|
|
|
|
|
private let audioQueueLock = NSLock() // 队列操作锁 |
|
|
private let audioQueueLock = NSLock() // 队列操作锁 |
|
|
|
|
|
|
|
|
@ -1414,6 +1419,24 @@ public class BleService: NSObject { |
|
|
"isNotification": true |
|
|
"isNotification": true |
|
|
] |
|
|
] |
|
|
notifyDeviceInfoReceived(infoType: Int(infoType), infoData: resultMap) |
|
|
notifyDeviceInfoReceived(infoType: Int(infoType), infoData: resultMap) |
|
|
|
|
|
case BleConst.CMD_CONTROL_CODEC: |
|
|
|
|
|
// 设备主动上报编解码控制状态,目前只关心 CODEC_CONTROL_CALL_Sleep (0xFF) |
|
|
|
|
|
// 帧格式: 0xCC 0x05 [len] [codecStatus, channelMode, ...] [crc] |
|
|
|
|
|
let codecStatus: Int = notifyData.count >= 1 ? Int(notifyData[0]) : -1 |
|
|
|
|
|
if codecStatus == Int(BleConst.CODEC_CONTROL_CALL_Sleep) { |
|
|
|
|
|
os_log("收到主动上报: 通话休眠 (codecStatus=0xFF)", log: logger, type: .info) |
|
|
|
|
|
handleCallSleepReceived() |
|
|
|
|
|
} else { |
|
|
|
|
|
os_log("收到主动上报编解码控制: codecStatus=0x%02X", log: logger, type: .debug, codecStatus) |
|
|
|
|
|
} |
|
|
|
|
|
let resultMap: [String: Any] = [ |
|
|
|
|
|
"success": true, |
|
|
|
|
|
"command": Int(infoType), |
|
|
|
|
|
"rawData": [UInt8](notifyData), |
|
|
|
|
|
"codecStatus": codecStatus, |
|
|
|
|
|
"isNotification": true |
|
|
|
|
|
] |
|
|
|
|
|
notifyDeviceInfoReceived(infoType: Int(infoType), infoData: resultMap) |
|
|
default: |
|
|
default: |
|
|
// 对于未知上报类型,返回原始数据 |
|
|
// 对于未知上报类型,返回原始数据 |
|
|
let resultMap: [String: Any] = [ |
|
|
let resultMap: [String: Any] = [ |
|
|
@ -1592,6 +1615,14 @@ extension BleService: SwiftOpusAudioProcessor.AudioDataCallback { |
|
|
* 处理音频发送队列 |
|
|
* 处理音频发送队列 |
|
|
*/ |
|
|
*/ |
|
|
private func processAudioSendQueue() { |
|
|
private func processAudioSendQueue() { |
|
|
|
|
|
// 若收到过 CODEC_CONTROL_CALL_Sleep,本轮直接放弃发送,等到 nextSendEarliestAt 之后再消费队列 |
|
|
|
|
|
nextSendEarliestLock.lock() |
|
|
|
|
|
let earliest = nextSendEarliestAt |
|
|
|
|
|
nextSendEarliestLock.unlock() |
|
|
|
|
|
if let earliest = earliest, Date() < earliest { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
audioQueueLock.lock() |
|
|
audioQueueLock.lock() |
|
|
defer { audioQueueLock.unlock() } |
|
|
defer { audioQueueLock.unlock() } |
|
|
|
|
|
|
|
|
@ -1606,6 +1637,18 @@ extension BleService: SwiftOpusAudioProcessor.AudioDataCallback { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 收到设备主动上报的 CODEC_CONTROL_CALL_Sleep 时调用, |
|
|
|
|
|
* 让音频发送定时器在 AUDIO_SEND_SLEEP_PAUSE 内跳过发送,相当于插入一次较长暂停, |
|
|
|
|
|
* 之后自动回到 60ms 节拍。期间重复触发会"刷新"暂停截止时间。 |
|
|
|
|
|
*/ |
|
|
|
|
|
private func handleCallSleepReceived() { |
|
|
|
|
|
nextSendEarliestLock.lock() |
|
|
|
|
|
nextSendEarliestAt = Date().addingTimeInterval(AUDIO_SEND_SLEEP_PAUSE) |
|
|
|
|
|
nextSendEarliestLock.unlock() |
|
|
|
|
|
os_log("收到通话休眠指令,音频发送将暂停 %.0f ms", log: logger, type: .info, AUDIO_SEND_SLEEP_PAUSE * 1000) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 发送音频数据块到蓝牙设备 |
|
|
* 发送音频数据块到蓝牙设备 |
|
|
* @param data 要发送的音频数据 |
|
|
* @param data 要发送的音频数据 |
|
|
|