|
|
@ -66,6 +66,9 @@ import os.log |
|
|
// 处理队列 |
|
|
// 处理队列 |
|
|
private let processingQueue = DispatchQueue(label: "com.azure.speech.processing", qos: .userInitiated) |
|
|
private let processingQueue = DispatchQueue(label: "com.azure.speech.processing", qos: .userInitiated) |
|
|
|
|
|
|
|
|
|
|
|
// 合成中的音频缓存 |
|
|
|
|
|
private var ttsBuffer = Data() |
|
|
|
|
|
|
|
|
// MARK: - Configuration Structures |
|
|
// MARK: - Configuration Structures |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -478,6 +481,7 @@ import os.log |
|
|
// 合成开始事件 |
|
|
// 合成开始事件 |
|
|
synthesizer?.addSynthesisStartedEventHandler { [weak self] (synthesizer, event) in |
|
|
synthesizer?.addSynthesisStartedEventHandler { [weak self] (synthesizer, event) in |
|
|
guard let self = self else { return } |
|
|
guard let self = self else { return } |
|
|
|
|
|
self.ttsBuffer = Data() |
|
|
|
|
|
|
|
|
os_log("合成开始事件", log: self.log, type: .info) |
|
|
os_log("合成开始事件", log: self.log, type: .info) |
|
|
self.serviceState.isSynthesizing = true |
|
|
self.serviceState.isSynthesizing = true |
|
|
@ -487,7 +491,7 @@ import os.log |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 合成进行中事件 - 修改为返回音频数据 |
|
|
// 合成进行中事件 - 增量发送音频分片(按1280字节对齐) |
|
|
synthesizer?.addSynthesizingEventHandler { [weak self] (synthesizer, event) in |
|
|
synthesizer?.addSynthesizingEventHandler { [weak self] (synthesizer, event) in |
|
|
guard let self = self else { return } |
|
|
guard let self = self else { return } |
|
|
// 安全解包audioData |
|
|
// 安全解包audioData |
|
|
@ -495,8 +499,8 @@ import os.log |
|
|
os_log("合成进行中事件,音频数据为空", log: self.log, type: .debug) |
|
|
os_log("合成进行中事件,音频数据为空", log: self.log, type: .debug) |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
os_log("合成进行中事件,音频数据长度: %d bytes", log: self.log, type: .debug, audioData.count) |
|
|
self.processSynthesisAudioChunk(text: "", incoming: audioData, multiple: 1280) |
|
|
|
|
|
os_log("合成进行中事件,累计缓存长度: %d bytes", log: self.log, type: .debug, self.ttsBuffer.count) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 合成完成事件 |
|
|
// 合成完成事件 |
|
|
@ -505,16 +509,14 @@ import os.log |
|
|
|
|
|
|
|
|
os_log("合成完成事件", log: self.log, type: .info) |
|
|
os_log("合成完成事件", log: self.log, type: .info) |
|
|
// 安全解包audioData |
|
|
// 安全解包audioData |
|
|
guard let audioData = event.result.audioData else { |
|
|
|
|
|
os_log("合成完成事件,音频数据为空", log: self.log, type: .debug) |
|
|
// 发送缓存中的剩余数据(可能非1280对齐的余量) |
|
|
return |
|
|
let remaining = self.ttsBuffer |
|
|
} |
|
|
self.ttsBuffer = Data() |
|
|
os_log("合成完成事件,音频数据长度: %d bytes", log: self.log, type: .debug, audioData.count) |
|
|
|
|
|
DispatchQueue.main.async { |
|
|
DispatchQueue.main.async { |
|
|
self.serviceState.isSynthesizing = false |
|
|
self.serviceState.isSynthesizing = false |
|
|
// 立即返回当前生成的音频数据 |
|
|
self.eventCallback?.onSynthesisAudioGenerated(text: "", audioData: remaining) |
|
|
self.eventCallback?.onSynthesisAudioGenerated(text: "", audioData: audioData) |
|
|
self.eventCallback?.onStateChanged(component: "Synthesis", isActive: false) |
|
|
self.eventCallback?.onStateChanged(component: "Synthesis", isActive: false) |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
@ -525,6 +527,8 @@ import os.log |
|
|
|
|
|
|
|
|
os_log("合成取消事件", log: self.log, type: .info) |
|
|
os_log("合成取消事件", log: self.log, type: .info) |
|
|
self.serviceState.isSynthesizing = false |
|
|
self.serviceState.isSynthesizing = false |
|
|
|
|
|
// 取消时清空缓存,避免脏数据 |
|
|
|
|
|
self.ttsBuffer = Data() |
|
|
|
|
|
|
|
|
// 修复:移除可选链,因为event.result不是可选类型 |
|
|
// 修复:移除可选链,因为event.result不是可选类型 |
|
|
let reason = event.result.reason |
|
|
let reason = event.result.reason |
|
|
@ -542,6 +546,32 @@ import os.log |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 处理合成音频分片(按multiple字节对齐,默认1280) |
|
|
|
|
|
* - 参数 text: 正在合成的文本 |
|
|
|
|
|
* - 参数 incoming: 新到达的音频数据块 |
|
|
|
|
|
* - 参数 multiple: 对齐字节倍数(例如16000Hz/16bit/mono下常用1280) |
|
|
|
|
|
* 将incoming追加到缓存,仅当累计长度达到multiple的整数倍时, |
|
|
|
|
|
* 发送对齐部分;余数继续保留在缓存,等待后续数据到来或合成完成时一次性发送。 |
|
|
|
|
|
*/ |
|
|
|
|
|
private func processSynthesisAudioChunk(text: String, incoming: Data?, multiple: Int = 1280) { |
|
|
|
|
|
guard let incoming = incoming, !incoming.isEmpty else { return } |
|
|
|
|
|
// 追加到缓存 |
|
|
|
|
|
ttsBuffer.append(incoming) |
|
|
|
|
|
// 计算可发送的对齐长度 |
|
|
|
|
|
let sendLen = (ttsBuffer.count / multiple) * multiple |
|
|
|
|
|
if sendLen > 0 { |
|
|
|
|
|
let chunk = ttsBuffer.prefix(sendLen) |
|
|
|
|
|
// 发送对齐部分 |
|
|
|
|
|
let toSend = Data(chunk) |
|
|
|
|
|
DispatchQueue.main.async { [weak self] in |
|
|
|
|
|
self?.eventCallback?.onSynthesisAudioGenerated(text: text, audioData: toSend) |
|
|
|
|
|
} |
|
|
|
|
|
// 保留余数 |
|
|
|
|
|
ttsBuffer = Data(ttsBuffer.suffix(ttsBuffer.count - sendLen)) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// MARK: - Public Methods |
|
|
// MARK: - Public Methods |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
|