func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
DCLogger.debug("收 ",characteristic.uuid,characteristic.value?.joined() ?? "")
guard let data = characteristic.value else { return }
- if data.count < 4 {
- return
+ if data.count > 4 && data[0] == 0xBA {
+ if let sender = BleSender.answer(data) {
+ sender.completion?(.response.code(.success).value(data))
+ sender.deinitTimer()
+ sender.remove()
+ return
+ }
+ else if data[1] == 0x0D{
+ let subData = data.subdata(in: 2..<data.count - 3)
+ //DCLogger.debug("传给字节sdk",subData.joined())
+ StarburstSdk.shared().receiveBleData(subData)
+ }else{
+ receiveNoticeData(data)
+ }
+ }
+ else{
+ DCLogger.debug("收到异常数据!!!!!!!!!!!")
+ }
+ }
+}
+
+extension DCBleManager{
+ func receiveNoticeData(_ data:Data){
+ if data[1] == 0x10,data[2] == 0x06{
+ DCDevice.shared.receiveNotice(data)
}
-
- if let sender = BleSender.answer(data) {
- sender.completion?(.response.code(.success).value(data))
- sender.deinitTimer()
- sender.remove()
- return
+ else if data[1] == 0x0F{
+ switch data[2] {
+ case 0x01:
+ DCLogger.debug("打开AI对话")
+ case 0x02:
+ DCLogger.debug("关闭AI对话")
+ DCChat.shared.stopChat()
+ case 0x03:
+ DCLogger.debug("打开耳机录音")
+ DCBleRecord.shared.start()
+ case 0x04:
+ DCLogger.debug("关闭耳机录音")
+ DCBleRecord.shared.stop()
+ default:
+ break
+ }
+
+
}
- else if data[1] == 0x0D{
- let subData = data.subdata(in: 2..<data.count - 2)
-// DCLogger.debug("传给字节sdk",subData.joined())
- StarburstSdk.shared().receiveBleData(subData)
+ }
+ static func contentData(_ data:Data)->Data{
+ if data.count > 4 && data[0] == 0xBA {
+ return data.subdata(in: 2..<data.count - 3)
}
+ return data
}
}
public class DCBleRecord {
public static let shared = DCBleRecord()
- var recordList : [(String,Int)] = []
- var recordText = ""
+ /// 语⾔编码,默认为普通话(zh-CN),auto_lang自动识别
+ public var fromLanguage:String = ""
+ /// ⽬标语⾔编码,默认为英语(en-US),auto_lang自动识别
+ public var toLanguage:String = ""
+ /// 是否翻译,默认false。如果为true翻译源语言和目标语言不能是同一种语言
+ public var isTranslate = false
+ /// 是否进⾏Tts,默认false
+ public var isTTs = false
+ /// 默认pcm ⽀持pcm / ogg_opus / mp3
+ public var ttsFormat = "mp3"
+ /// 识别回调
+ public var asrCallback:((String)->Void)?
+ /// 识别回调
+ public var translateCallback:((String)->Void)?
+ /// 状态码回调
+ public var codeCallback:((Int)->Void)?
+ /// 录音文件回调
+ public var filePathCallBack:((String?)->Void)?
- public func setup(textCallback:@escaping (String)->Void){
- let asr = StarburstAsrConfig()
-// asr.isTranslate = true;
-// asr.fromLanguage = "zh-CN"
-// asr.toLanguage = "en-US"
-// asr.isTTs = true
-// asr.ttsFormat = "mp3"
- StarburstSdk.shared().setupDeviceRecord(with: nil, asrConfig: asr) { config in
+ var asrList : [(String,Int)] = []
+ var asrText = ""
+
+ var translateList : [(String,Int)] = []
+ var translateText = ""
+
+ func setupRecord(){
+ let config = StarburstAsrConfig()
+ config.isTranslate = isTranslate
+ config.fromLanguage = fromLanguage
+ config.toLanguage = toLanguage
+ config.isTTs = isTTs
+ config.ttsFormat = ttsFormat
+
+ StarburstSdk.shared().setupDeviceRecord(with: nil, asrConfig: config) { config in
DCLogger.debug("录音类型 \(config!.type == 0x00 ? "实时录音" : "通话录音")")
} recognizeText: { [weak self] model in
guard let self = self else {return}
guard let model = model else {return}
if let text = model.textResult{
- DCLogger.debug("识别 = \(text)")
- let msg = recordList.firstIndex (where: { (str,idx) in
+ DCLogger.debug("asr = \(text)")
+ let msg = asrList.firstIndex (where: { (str,idx) in
return idx == model.definiteIndex;
})
if (msg == nil) {
- recordList.append((model.textResult,model.definiteIndex))
+ asrList.append((text,model.definiteIndex))
+ } else {
+ asrList[msg!] = (text,model.definiteIndex)
+ }
+ asrText = asrList.compactMap({ (str,idx) in
+ return str
+ }).joined(separator: "\n")
+
+ asrCallback?(asrText)
+ }
+ if let translate = model.translateResult,let text = translate.text{
+ DCLogger.debug("translate = \(text)")
+ let msg = translateList.firstIndex (where: { (str,idx) in
+ return idx == translate.definiteIndex;
+ })
+ if (msg == nil) {
+ translateList.append((text,Int(translate.definiteIndex)))
} else {
- recordList[msg!] = (model.textResult,model.definiteIndex)
+ translateList[msg!] = (text,Int(translate.definiteIndex))
}
- recordText = recordList.compactMap({ (str,idx) in
+ translateText = translateList.compactMap({ (str,idx) in
return str
}).joined(separator: "\n")
- textCallback(recordText)
+ translateCallback?(translateText)
}
} stateChange: { [weak self] code in
- guard let self = self else {return}
- DCLogger.debug("状态改变 \(code)")
- } finished: { filePath in
- if let path = filePath,path.count > 0 {
- // 文件转存到自己想要保存的位置
- DCLogger.debug("文件录音保存路径 \(path)")
- }
- else{
- DCLogger.debug("文件录音保存失败")
- }
+ DCLogger.debug("状态改变",code)
+ self?.codeCallback?(code.rawValue)
+ } finished: {[weak self] filePath in
+ DCLogger.debug("文件录音保存路径 \(filePath ?? "")")
+ self?.filePathCallBack?(filePath)
}
}
- public func startAction(){
+ public func start(){
+ asrList = []
+ asrText = ""
+
+ translateList = []
+ translateText = ""
+
+ setupRecord()
let config = StarburstBleAsrConfig()
config.type = 0x0c/// 0x00实时录音,0x0c通话录音
//开始录音
StarburstSdk.shared().startDeviceRecord(config)
}
- public func stopAction(){
+ public func stop(){
StarburstSdk.shared().stopDeviceRecord()
}
}
import StarburstSdk
-/// Ai回应模型
-public class ChatCellModel:NSObject,NSCoding {
- public var type: Int = 0//1发,0收
- public var content: String = ""
- public var id:Int = 0
-
- required public override init() { }
-
- public func encode(with aCoder: NSCoder) {
- aCoder.encode("\(type)", forKey: "type")
- aCoder.encode(content, forKey: "content")
- aCoder.encode("\(id)", forKey: "id")
- }
-
- required public init?(coder aDecoder: NSCoder) {
- type = Int(aDecoder.decodeObject(forKey: "type") as? String ?? "0") ?? 0
- content = aDecoder.decodeObject(forKey: "content") as? String ?? ""
- id = Int(aDecoder.decodeObject(forKey: "id") as? String ?? "0") ?? 0
- }
+public class DCRole{
+ /// 音色id
+ public var sid:String = ""
+ /// 名称
+ public var name:String = ""
+ /// 类型
+ public var type:String = ""
+ /// 角色
+ public var role:String = ""
}
-
public class DCChat{
public static let shared = DCChat()
- var speakerList = [StarbusrtSpeaker]()
-
-
- var dataList:[ChatCellModel] = []
- public var chatStateChange:((Int)->Void)?
- public var chatNeedReloadData:(()->Void)?
+ var speakerList = [DCRole]()
public var dialogId = 0
+ /// 识别回调
+ public var asrCallback:((String,Int)->Void)?
+ /// 回复回调
+ public var responseCallback:((String,Int)->Void)?
+ /// 对话语音回调
+ public var dataCallback:((Int,Data?,Bool)->Void)?
+ /// 状态码回调
+ public var codeCallback:((Int)->Void)?
+ /// 结束对话回调
+ public var finishCallback:((String?)->Void)?
- public func getVcSpeekerList(finished:@escaping (Any,Bool)->Void){
+ /// 智能体
+ public var role:DCRole?
+ /// 是否进⾏Tts,默认false
+ public var tts:Bool = true
+ /// 默认pcm。⽀持pcm / ogg_opus / mp3
+ public var ttsAudioFormat:String = "mp3"
+ /// 语⾔编码,默认为普通话(zh-CN)
+ public var language:String = ""
+}
+extension DCChat{
+ public func getVcSpeekerList(finished:@escaping ([DCRole]?,Bool)->Void){
StarburstSdk.shared().getVcSpeekerList { [weak self] (list, success) in
guard let self = self else { return }
- finished(list,success)
+ if success,let list = list {
+ var temp = [DCRole]()
+ for item in list {
+ var role = DCRole()
+ role.sid = item.sid
+ role.name = item.name
+ role.type = item.type
+ role.role = item.role
+ temp.append(role)
+ }
+ finished(temp,success)
+ }
+ else{
+ finished(nil,success)
+ }
+
}
}
- public func setup(asrCallback:@escaping (String)->Void,responseCallback:@escaping (String)->Void,dataCallback:@escaping (Int,Data?,Bool)->Void,codeCallback:@escaping (Int)->Void){
+ public func initChat(){
let config = StarburstVoiceChatConfig()
- config.tts = true
- config.ttsAudioFormat = "mp3"
- //以下配置从音色列表获取
- if speakerList.count > 0 {
+ config.tts = tts
+ config.ttsAudioFormat = ttsAudioFormat
+ if let speaker = role {
// config.role = "spongebob"
// config.ttsSpeakerType = "default"
// config.ttsSpeakerId = "BV063_streaming"
- config.role = speakerList[0].role
- config.ttsSpeakerType = speakerList[0].type
- config.ttsSpeakerId = speakerList[0].sid
+ config.role = speaker.role
+ config.ttsSpeakerType = speaker.type
+ config.ttsSpeakerId = speaker.sid
}
StarburstSdk.shared().setupVoiceChat(with: config) { dialogId in
- print("开始对话 = \(dialogId)")
+ DCLogger.debug("开始对话 = \(dialogId)")
} textCallback: {[weak self] model in
guard let self = self else { return }
guard let textModel = model else { return }
self.dialogId = textModel.dialogId
-
+ DCLogger.debug("[recv] = \(textModel.dialogId),\(textModel.conversationFinish),\(textModel.sequence),\(textModel.textResult),\(textModel.responseText)")
if let text = textModel.textResult{
- asrCallback(text)
+ //DCLogger.debug("[send] = \(textModel.sequence),\(text)")
+ asrCallback?(text,self.dialogId)
}
else if let text = textModel.responseText{
- responseCallback(text)
+ //DCLogger.debug("[recv] = \(textModel.sequence),\(text)")
+ responseCallback?(text,self.dialogId)
}
-// Logger.debug(text,index)
-// guard let text = text else{
-// return
-// }
-
-// if dataList.last?.id == -1 {
-// dataList.removeLast()
-// }
-// if let model = dataList.last,model.id == textModel.definiteIndex,model.type == 1,let text = textModel.textResult {
-// model.content = text
-// }
-// else{
-// let model = ChatCellModel()
-// model.type = 1
-// model.content = textModel.textResult ?? ""
-// model.id = textModel.definiteIndex
-// dataList.append(model)
-// }
-// chatNeedReloadData?()
-
} responseVoice: { [weak self] (dialogId,data, finish) in
guard let self = self else { return }
self.dialogId = dialogId
- dataCallback(dialogId,data,finish)
- } stateChange: {code in
+ dataCallback?(dialogId,data,finish)
+ } stateChange: {[weak self] code in
DCLogger.debug("状态改变 \(code)")
- codeCallback(code.rawValue)
- } finished: { filePath in
+ self?.codeCallback?(code.rawValue)
+ } finished: {[weak self] filePath in
DCLogger.debug("结束对话")
+ self?.finishCallback?(filePath)
}
}
+
public func startChat(){
-
+ initChat()
}
public func stopChat(){
StarburstSdk.shared().stopVoiceChat(self.dialogId)
public class DCDevice{
public static let shared = DCDevice()
+ func receiveNotice(_ data:Data){
+ if data[1] == 0x10,data[2] == 0x06{
+ let index = UInt16(data[3...4].int)
+ let pro = UInt16(data[5...6].int)
+ let total = UInt16(data[7...8].int)
+ DCLogger.debug("播放进度index = \(index),total = \(total),pro = \(pro)")
+ }
+ }
+}
+ extension DCDevice{
public func getBatery(finished:@escaping ((Int,Int)?)->Void){
- var data = Data.dataWithHexString("BA0900")
- data.addCrc()
-
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x09
+ var data:UInt8 = 00
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.addCrc()
+
let sender = BleSender()
- sender.data = data
+ sender.data = total
sender.completion = { result in
DCLogger.debug("\(result.description)")
if result.isSuccess{
DCBleManager.shared.send(sender)
}
public func getSoftVersion(finished:@escaping (String?)->Void){
- var data = Data.dataWithHexString("BA0A00")
- data.addCrc()
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x0A
+ var data:UInt8 = 00
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.addCrc()
let sender = BleSender()
- sender.data = data
+ sender.data = total
sender.completion = { result in
DCLogger.debug("\(result.description)")
if result.isSuccess{
let data = result.data[2...6]
let text = String(data: data, encoding:.utf8)
- DCLogger.debug(text)
+ DCLogger.debug(text ?? "")
finished((text))
}
else{
DCBleManager.shared.send(sender)
}
public func getHardVersion(finished:@escaping (String?)->Void){
- var data = Data.dataWithHexString("BA0A01")
- data.addCrc()
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x0A
+ var data:UInt8 = 01
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.addCrc()
let sender = BleSender()
- sender.data = data
+ sender.data = total
sender.completion = { result in
DCLogger.debug("\(result.description)")
if result.isSuccess{
let data = result.data[2...6]
let text = String(data: data, encoding:.utf8)
- DCLogger.debug(text)
+ DCLogger.debug(text ?? "")
finished((text))
}
else{
}
DCBleManager.shared.send(sender)
}
+
+ /// state 0关闭,1打开
+ public func findDevice(state:UInt8,finished:@escaping (Bool)->Void){
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x0B
+ var data:UInt8 = state
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let value = result.data[2].int
+ DCLogger.debug(value)
+ finished(true)
+ }
+ else{
+ finished(false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+
+ /// type, 0x00(正常模式)
+ // 0x01(流行)
+ // 0x02(经典)
+ // 0x03(爵士)
+ // 0x04(摇滚)
+ // 0x05(自定义)
+ public func setEQ(type:UInt8,finished:@escaping (Bool)->Void){
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x0C
+ var data:UInt8 = type
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let value = result.data[2].int
+ DCLogger.debug(value)
+ finished(value == 0)
+ }
+ else{
+ finished(false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+ /// vaue,只有自定义才有,索引 0-9(对应10段EQ调节)(-12~12)
+ public func setCustomEQ(index:UInt8,value:Int,finished:@escaping (Bool)->Void){
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x0C
+ var data:UInt8 = 0x06
+ var index:UInt8 = UInt8(index)
+ var value:UInt8 = UInt8(value)
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.append(&index, count: 1)
+ total.append(&value, count: 1)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let value = result.data[2].int
+ DCLogger.debug(value)
+ finished(value == 0)
+ }
+ else{
+ finished(false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+ public func getEQ(finished:@escaping ((type:UInt8,value:[Int])?,Bool)->Void){
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x0E
+ var data:UInt8 = 0x00
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let type = UInt8(result.data[2].int)
+ DCLogger.debug(type)
+ if type == 5 {
+
+ }
+ finished((type,[]),true)
+ }
+ else{
+ finished(nil,false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+}
+
+extension DCDevice{
+ public func getMusicList(size:UInt8,index:UInt16,finished:@escaping ([DCMusic]?,Bool)->Void){
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x10
+ var data:UInt8 = 0x01
+ var pageSize = size
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.append(&pageSize, count: 1)
+ total.appendInt16(index)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+// let data = DCBleManager.contentData(result.data)
+ let data = result.data.subdata(in: 3..<result.data.count - 3)
+ let str = String(data: data, encoding: .utf8)
+ DCLogger.debug(str ?? "")
+ guard let list = JSON.decode([DCMusic].self, from: data) else { return }
+// var list = [DCMusic]()
+ finished(list,true)
+ }
+ else{
+ finished(nil,false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+
+// 0x00:顺序循环
+// 0x01:随机
+// 0x02:单曲
+ public func setMusicPlayMode(mode:UInt8,finished:@escaping (Bool)->Void){
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x10
+ var data:UInt8 = 0x02
+ var mode:UInt8 = mode
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.append(&mode, count: 1)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let value = result.data[2].int
+ DCLogger.debug(value)
+ finished(value == 0)
+ }
+ else{
+ finished(false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+ public func getMusicPlayMode(finished:@escaping (UInt8?,Bool)->Void){
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x10
+ var data:UInt8 = 0x03
+ var content:UInt8 = 0x00
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.append(&content, count: 1)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let value = UInt8(result.data[3].int)
+ DCLogger.debug(value)
+ finished(value,true)
+ }
+ else{
+ finished(nil,false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+
+ public func musicPlay(index:UInt16?,finished:@escaping (UInt16?,Bool)->Void){
+ if let index = index {
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x10
+ var data:UInt8 = 0x05
+
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.appendInt16(index)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let value = UInt16(result.data[3...4].int)
+ DCLogger.debug(value)
+ finished(value,true)
+ }
+ else{
+ finished(nil,false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+ else{
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x10
+ var data:UInt8 = 0x04
+ var content:UInt8 = 0x00
+
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.append(&content, count: 1)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let value = UInt16(result.data[3...4].int)
+ DCLogger.debug(value)
+ finished(value,true)
+ }
+ else{
+ finished(nil,false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+ }
+ public func musicPause(finished:@escaping (UInt16?,Bool)->Void){
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x10
+ var data:UInt8 = 0x04
+ var content:UInt8 = 0x01
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.append(&content, count: 1)
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let value = UInt16(result.data[3...4].int)
+ DCLogger.debug(value)
+ finished(value,true)
+ }
+ else{
+ finished(nil,false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+ public func musicDelete(list:[UInt16],finished:@escaping (Bool)->Void){
+ var head: UInt8 = 0xBA
+ var cmd: UInt8 = 0x10
+ var data:UInt8 = 0x07
+ var content:UInt8 = UInt8(list.count)
+ var total = Data()
+ total.append(&head, count: 1)
+ total.append(&cmd, count: 1)
+ total.append(&data, count: 1)
+ total.append(&content, count: 1)
+ for item in list {
+ total.appendInt16(item)
+ }
+ total.addCrc()
+
+ let sender = BleSender()
+ sender.data = total
+ sender.completion = { result in
+ DCLogger.debug("\(result.description)")
+ if result.isSuccess{
+ let value = UInt16(result.data[3].int)
+ DCLogger.debug(value)
+ finished(value == 0)
+ }
+ else{
+ finished(false)
+ }
+ }
+ DCBleManager.shared.send(sender)
+ }
+
}
--- /dev/null
+//
+// DCMusic.swift
+// Example
+//
+// Created by liangshi on 2025/12/17.
+//
+
+public class DCMusic:Codable{
+ /// id
+ public var id = ""
+ /// 名字
+ public var name = ""
+ /// 大小
+ public var size = ""
+ /// 时长
+ public var dur = 0
+}
public class DCRecord {
public static let shared = DCRecord()
- var recordList : [(String,Int)] = []
- var recordText = ""
+ /// 语⾔编码,默认为普通话(zh-CN),auto_lang自动识别
+ public var fromLanguage:String = ""
+ /// ⽬标语⾔编码,默认为英语(en-US),auto_lang自动识别
+ public var toLanguage:String = ""
+ /// 是否翻译,默认false。如果为true翻译源语言和目标语言不能是同一种语言
+ public var isTranslate = false
+ /// 是否进⾏Tts,默认false
+ public var isTTs = false
+ /// 默认pcm ⽀持pcm / ogg_opus / mp3
+ public var ttsFormat = "mp3"
+ /// 识别回调
+ public var asrCallback:((String)->Void)?
+ /// 识别回调
+ public var translateCallback:((String)->Void)?
+ /// 状态码回调
+ public var codeCallback:((Int)->Void)?
+ /// 打断
+ public var interruptionCallBack:(()->Void)?
+ /// 录音文件回调
+ public var filePathCallBack:((String?)->Void)?
- public func start(fromLanguage:String,toLanguage:String,textCallback:@escaping (String)->Void){
+ var asrList : [(String,Int)] = []
+ var asrText = ""
+
+ var translateList : [(String,Int)] = []
+ var translateText = ""
+
+ public func start(){
let config = StarburstAsrConfig()
-// config.isTranslate = true;
-// config.fromLanguage = fromLanguage
-// config.toLanguage = toLanguage
-// config.isTTs = true
-// config.ttsFormat = "mp3"
+ config.isTranslate = isTranslate
+ config.fromLanguage = fromLanguage
+ config.toLanguage = toLanguage
+ config.isTTs = isTTs
+ config.ttsFormat = ttsFormat
+ asrList = []
+ asrText = ""
+
+ translateList = []
+ translateText = ""
StarburstSdk.shared().startRecordAsr(config) {voiceData in
- //print("录音的音频流 = \(voiceData!)")
+ //DCLogger.debug("录音的音频流 = \(voiceData!)")
} recognizeText: {[weak self] model in
guard let self = self else {return}
guard let model = model else {return}
if let text = model.textResult{
- DCLogger.debug("识别 = \(text)")
- let msg = recordList.firstIndex (where: { (str,idx) in
+ DCLogger.debug("asr = \(text)")
+ let msg = asrList.firstIndex (where: { (str,idx) in
return idx == model.definiteIndex;
})
if (msg == nil) {
- recordList.append((model.textResult,model.definiteIndex))
+ asrList.append((text,model.definiteIndex))
} else {
- recordList[msg!] = (model.textResult,model.definiteIndex)
+ asrList[msg!] = (text,model.definiteIndex)
}
- recordText = recordList.compactMap({ (str,idx) in
+ asrText = asrList.compactMap({ (str,idx) in
return str
}).joined(separator: "\n")
- textCallback(recordText)
+ asrCallback?(asrText)
+ }
+ if let translate = model.translateResult,let text = translate.text{
+ DCLogger.debug("translate = \(text)")
+ let msg = translateList.firstIndex (where: { (str,idx) in
+ return idx == translate.definiteIndex;
+ })
+ if (msg == nil) {
+ translateList.append((text,Int(translate.definiteIndex)))
+ } else {
+ translateList[msg!] = (text,Int(translate.definiteIndex))
+ }
+ translateText = translateList.compactMap({ (str,idx) in
+ return str
+ }).joined(separator: "\n")
+
+ translateCallback?(translateText)
}
-
-// guard let self = self else {return}
-// self.resetTimer()
-// guard let model = model else {return}
-//
-// if let translate = model.translateResult,let text = translate.text,translate.definite == true {
-// print("确定 text = \(text)")
-// self.addText(text)
-// }
-// if let ttsData = model.ttsResult?.streamPiece {
-// //收到的tts
-// if self.ttsData == nil{
-// self.ttsData = Data()
-// }
-// if let data = Data(base64Encoded: ttsData){
-// self.ttsData?.append(data)
-// }
-// }
} stateChange: {[weak self] code in
DCLogger.debug("状态改变",code)
-// guard let self = self else {return}
-// if code == .unAuth{
-// self.view.makeToast("未鉴权")
-// self.recordBtn.isSelected = false
-// }
+ self?.codeCallback?(code.rawValue)
} interruption: { [weak self] in
-// self?.stopAction()
-
+ self?.interruptionCallBack?()
}
}
public func stop(){
- StarburstSdk.shared().stopRecordAsr {filePath in
- DCLogger.debug("文件录音保存路径 \(filePath)")
+ StarburstSdk.shared().stopRecordAsr {[weak self] filePath in
+ DCLogger.debug("文件录音保存路径 \(filePath ?? "")")
+ self?.filePathCallBack?(filePath)
}
}
}
mutating func addCrc(){
- var len = UInt8(self.count - 2)
- self.append(&len, count: 1)
+ var len = UInt16(self.count - 2)
+ self.appendInt16(len)
var crc = Data.crc8(self)
self.append(&crc, count: 1)
}
// var crc = chargestore_crc8(list, len: list.count)
// self.append(&crc, count: 1)
// }
+
+ mutating func appendInt16(_ value:UInt16){
+ var byte1 = UInt8(value & 0xFF)
+ var byte2 = UInt8((value >> 8) & 0xFF)
+ self.append(&byte1, count: 1)
+ self.append(&byte2, count: 1)
+
+ }
}
return crc
}
-//// 调用示例
-//let data: [UInt8] = [0x01, 0x02, 0x03]
-//let crcResult = data.withUnsafeBufferPointer { buffer in
-// chargestore_crc8(buffer.baseAddress!, len: buffer.count)
-//}
-//print("CRC8 结果: \(crcResult)")
+class JSON {
+ /// JSON decode
+ static func decode<T: Decodable>(_ decodable: T.Type, from data: Data) -> T? {
+ do {
+ return try JSONDecoder().decode(decodable.self, from: data)
+ } catch { }
+ return nil
+ }
+
+ /// JSON decode
+ static func decode<T: Decodable>(_ decodable: T.Type, from jsonString: String) -> T? {
+ guard let data = jsonString.data(using: .utf8) else { return nil }
+ return decode(decodable, from: data)
+ }
+}
//debug模式会打印日志
- StarburstConfig.shared().isDebug = true
+ StarburstConfig.shared().isDebug = false
// sdk缓存路径
StarburstConfig.shared().sdkFolder = NSHomeDirectory() + "/Documents/DeepChordsSdk"
// 日志路径
sdklogBtn.backgroundColor = .blue
sdklogBtn.layer.cornerRadius = 30
sdklogBtn.layer.masksToBounds = true
- sdklogBtn.setTitle("log sdk", for: .normal)
+ sdklogBtn.setTitle("sdk log", for: .normal)
sdklogBtn.addTarget(self, action: #selector(sdkAction), for: .touchUpInside)
self.view.addSubview(sdklogBtn)
}
+++ /dev/null
-//
-// Untitled.swift
-// Example
-//
-// Created by liangshi on 2025/12/15.
-//
-
-import UIKit
-import DeepChordsSdk
-import AVFoundation
-class BleSdkBleChatVC: BaseVC {
- var recordBtn = UIButton(type: .custom)
- private var textView = UITextView()
-
-
- deinit {
- stopAction()
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- setupViews()
- setupSDk()
- }
-
- func setupViews() {
- self.title = "耳机对话"
-
- textView.isEditable = false
- self.view.addSubview(textView)
- textView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
-
- recordBtn.backgroundColor = .blue
- recordBtn.setTitle("stop", for: .normal)
- recordBtn.setTitle("stop", for: .selected)
- recordBtn.addTarget(self, action: #selector(recordAction), for: .touchUpInside)
- recordBtn.frame = CGRectMake(0, 0, 80, 40)
- self.navigationItem.rightBarButtonItems = [UIBarButtonItem(customView: recordBtn)]
- }
- func setupSDk(){
- ChatManager.shared.asrCallBack = {[weak self] text in
- guard let self = self else{return}
- let text = "[sebd]" + text + "\n\n"
- self.textView.text = self.textView.text + text
- let range = NSRange(
- location: self.textView.text.count - 1, length: 1)
- self.textView.scrollRangeToVisible(range)
- }
- ChatManager.shared.reponseCallBack = {[weak self] text in
- guard let self = self else{return}
- let text = "[recieve]" + text + "\n\n"
- self.textView.text = self.textView.text + text
- let range = NSRange(
- location: self.textView.text.count - 1, length: 1)
- self.textView.scrollRangeToVisible(range)
- }
- }
- @objc func recordAction() {
-// self.recordBtn.isSelected = !self.recordBtn.isSelected
-// if self.recordBtn.isSelected {
-// DCChat.shared.startChat()
-// }
-// else{
- stopAction()
-// }
- }
- func stopAction() {
- DCChat.shared.stopChat()
- }
-
-
-
-}
-
+++ /dev/null
-//
-// Untitled.swift
-// Example
-//
-// Created by liangshi on 2025/12/9.
-//
-
-import UIKit
-import DeepChordsSdk
-class BleSdkEarPhonesAsrVC: BaseVC {
- var textView = UITextView()
- var recordBtn = UIButton(type: .custom)
- var preText = ""
-
- override func viewDidLoad() {
- super.viewDidLoad()
- setupViews()
- setupSdk()
- }
-
- override func viewWillDisappear(_ animated: Bool) {
- super.viewWillDisappear(animated)
- stopAction()
- }
-
- func setupViews(){
- title = "耳机录音"
- view.backgroundColor = .white
-
- recordBtn.backgroundColor = .blue
- recordBtn.setTitle("start", for: .normal)
- recordBtn.setTitle("stop", for: .selected)
- recordBtn.addTarget(self, action: #selector(recordAction), for: .touchUpInside)
- recordBtn.frame = CGRectMake(0, 0, 80, 40)
- self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: recordBtn)
-
- textView.isEditable = false
- view.addSubview(textView)
- textView.frame = CGRectMake(0, 100, view.bounds.size.width, view.bounds.size.height - 100)
- }
- func setupSdk(){
- //设置回调
- DCBleRecord.shared.setup {[weak self] text in
- guard let self = self else{return}
-
- self.textView.text = text
- let range = NSMakeRange(textView.text.count - 1, 1)
- self.textView.scrollRangeToVisible(range)
- }
- }
-
- @objc func recordAction() {
- self.recordBtn.isSelected = !self.recordBtn.isSelected
- if self.recordBtn.isSelected {
- startAction()
- }
- else{
- stopAction()
- }
- }
-}
-extension BleSdkEarPhonesAsrVC{
- func startAction(){
- DCBleRecord.shared.startAction()
-
- }
- func stopAction(){
- DCBleRecord.shared.stopAction()
- }
-}
-
-extension BleSdkEarPhonesAsrVC{
- func addText(_ text:String){
- self.textView.text += text
- let range = NSMakeRange(textView.text.count - 1, 1)
- self.textView.scrollRangeToVisible(range)
- }
- func removePreText(){
- if self.textView.text.count - self.preText.count > 0{
- self.textView.text = String(self.textView.text.prefix(self.textView.text.count - self.preText.count))
- self.preText = ""
- }
- }
-}
+++ /dev/null
-//
-// Ble.swift
-// Example
-//
-// Created by liangshi on 2025/12/9.
-//
-
-import UIKit
-import DeepChordsSdk
-
-class BleSdkPhoneAsrVC: BaseVC {
- var textView = UITextView()
- var recordBtn = UIButton(type: .custom)
- var preText = ""
- var ttsData:Data?
- var timer: Timer?
-
- var fromLanguage = "zh-CN"
- var toLanguage = "en-US"
- var fromItem:UIBarButtonItem!
- var toItem:UIBarButtonItem!
-
- override func viewDidLoad() {
- super.viewDidLoad()
- title = "手机录音"
- view.backgroundColor = .white
-
-// fromItem = UIBarButtonItem(title: "源语言", style: .done, target: self, action: #selector(fromLanguageAction))
-// toItem = UIBarButtonItem(title: "目标语言", style: .done, target: self, action: #selector(toLanguageAction))
-// self.navigationItem.rightBarButtonItems = [
-// fromItem,toItem
-// ];
-//
- recordBtn.backgroundColor = .blue
- recordBtn.setTitle("开始录音", for: .normal)
- recordBtn.setTitle("停止录音", for: .selected)
- recordBtn.addTarget(self, action: #selector(recordAction), for: .touchUpInside)
- view.addSubview(recordBtn)
- recordBtn.snp.makeConstraints { make in
- make.width.centerX.bottom.equalToSuperview()
- make.height.equalTo(80)
- }
-
- textView.isEditable = false
- view.addSubview(textView)
- textView.snp.makeConstraints { make in
- make.width.centerX.equalToSuperview()
- make.top.equalToSuperview().inset(120)
- make.bottom.equalTo(recordBtn.snp.top)
- }
- }
-
-
-
- override func viewWillDisappear(_ animated: Bool) {
- super.viewWillDisappear(animated)
- stopAction()
- }
-
- func setupSdk(){
-
- }
-
- @objc func fromLanguageAction(){
- let vc = SelectLanuageVC()
- vc.didSelectedCallback = { (name,value) in
- self.fromLanguage = value
- self.fromItem.title = name
- }
- navigationController?.pushViewController(vc, animated: true)
- }
- @objc func toLanguageAction(){
- let vc = SelectLanuageVC()
- vc.didSelectedCallback = { (name,value) in
- self.toLanguage = value
- self.toItem.title = name
- }
- navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func recordAction() {
- self.recordBtn.isSelected = !self.recordBtn.isSelected
- if self.recordBtn.isSelected {
- startAction()
- }
- else{
- stopAction()
- }
- }
-}
-
-extension BleSdkPhoneAsrVC{
- func startAction(){
- DCRecord.shared.start(fromLanguage: fromLanguage, toLanguage: toLanguage, textCallback: { [weak self] text in
- guard let self = self else{return}
-
- self.textView.text = text
- let range = NSMakeRange(textView.text.count - 1, 1)
- self.textView.scrollRangeToVisible(range)
- })
- }
-
- func stopAction(){
-// StarburstSdk.shared().stopRecordAsr {filePath in
-// if let path = filePath,path.count > 0 {
-// // 文件转存到自己想要保存的位置
-// print("文件录音保存路径 \(path)")
-// }
-// else{
-// print("文件录音保存失败")
-// }
-// }
-// self.invalidateTimer()
- DCRecord.shared.stop()
- }
-
- func resetTimer() {
- self.invalidateTimer()
- self.timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(timerFired), userInfo: nil, repeats: false)
- }
-
- func invalidateTimer() {
- self.timer?.invalidate()
- self.timer = nil
- }
-
- @objc func timerFired() {
- if let data = self.ttsData {
- self.saveToFile(data: data)
- self.ttsData = nil
- }
- }
-}
-
-extension BleSdkPhoneAsrVC{
- func addText(_ text:String){
- self.textView.text += text
- let range = NSMakeRange(textView.text.count - 1, 1)
- self.textView.scrollRangeToVisible(range)
- }
- func saveToFile(data: Data) {
- let format = DateFormatter()
- format.dateFormat = "yyyyMMddHHmmss"
- let time = format.string(from: Date())
-
-// let filePath = NSHomeDirectory() + "/Documents/\(time).mp3"
-// let url = URL(fileURLWithPath: filePath)
-// do {
-// try data.write(to: url)
-// print("\(filePath)")
-// PlayerManager.shared.play(filePath: filePath,dialoIg: 0) { (success,dialoIg) in
-// print("播放结束 = \(success)")
-// }
-// // saveFile(withFilePath: filePath)
-// } catch let error {
-// print("\(error)")
-// }
- }
-
- func saveFile(withFilePath filePath: String) {
- let fUrl = URL(fileURLWithPath: filePath)
- let vc = UIDocumentPickerViewController(url: fUrl, in:.exportToService)
- vc.delegate = self
- vc.modalPresentationStyle = .overFullScreen
- self.present(vc, animated: true, completion: nil)
- }
-}
-
-extension BleSdkPhoneAsrVC:UIDocumentPickerDelegate{
- func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
- controller.dismiss(animated: true, completion: nil)
- }
-}
+++ /dev/null
-//
-// ChatManager.swift
-// Example
-//
-// Created by liangshi on 2025/12/15.
-//
-import AVFoundation
-import DeepChordsSdk
-
-class ChatManager:NSObject{
- static let shared = ChatManager()
- var isTtsPlaying = false
-
- private var audioData: Data?
-
- var asrCallBack:((String)->Void)?
- var reponseCallBack:((String)->Void)?
-
- func setupSdk(){
-
- PcmSound.sharedInstance().setup(16000, withchannels: 1)
- let options: AVAudioSession.CategoryOptions = [.allowBluetooth]
- do {
- try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
- try AVAudioSession.sharedInstance().setActive(true)
- } catch {
- DCLogger.debug(error)
- }
-
- setupChat()
- }
-
- func setupChat(){
- DCChat.shared.getVcSpeekerList { list, success in
-
- }
- DCChat.shared.setup { text in
- self.asrCallBack?(text)
- } responseCallback: { text in
- self.reponseCallBack?(text)
- } dataCallback: {[weak self] dialogId, data, finish in
- guard let self = self else { return }
-// PcmSound.sharedInstance().delegate = self
-// if (!isTtsPlaying) {
-// isTtsPlaying = true
-// DCLogger.debug("开始播放")
-// DCChat.shared.startPlayTtsAudio()
-// }
-// DCLogger.debug("收到音频数据", data?.count ?? 0)
-// PcmSound.sharedInstance().feed(data)
-
- if finish {
- self.saveToFile(data: self.audioData!)
- self.audioData = nil
- } else {
- if self.audioData == nil {
- self.audioData = Data()
- }
- self.audioData?.append(data!)
- }
- }codeCallback: { code in
-// if code == 20001 {
-// if (self.isTtsPlaying) {
-// self.isTtsPlaying = false
-// PcmSound.sharedInstance().cleanup()
-// PcmSound.sharedInstance().setup(16000, withchannels: 1)
-//
-// var options: AVAudioSession.CategoryOptions = [.allowBluetooth]
-// do {
-// try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
-// try AVAudioSession.sharedInstance().setActive(true)
-// } catch {
-// DCLogger.debug(error)
-// }
-// }
-// }
- }
- }
-
- func saveToFile(data: Data) {
- let filePath = NSHomeDirectory() + "/Documents/1.mp3"
- let url = URL(fileURLWithPath: filePath)
- do {
- try data.write(to: url)
- print("\(filePath)")
-
- var options: AVAudioSession.CategoryOptions = [.allowBluetooth]
- do {
- try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
- try AVAudioSession.sharedInstance().setActive(true)
- } catch {
- DCLogger.debug(error)
- }
- //这个要传开始播放的tts的dialogid
- DCChat.shared.startPlayTtsAudio()
- PlayerManager.shared.play(filePath: filePath,dialoIg:0) { (success,dialoIg) in
- print("播放结束 = \(success)")
- DCChat.shared.stopPlayTtsAudio()
- }
- } catch let error {
- print("\(error)")
- }
- }
-}
-extension ChatManager : PcmSoundDelegate {
- func remaining(_ frames: UInt) {
- DCLogger.debug("[frame:\(frames)]");
- if (frames == 0) {
- DCChat.shared.stopPlayTtsAudio()
- }
- }
-}
--- /dev/null
+//
+// Untitled.swift
+// Example
+//
+// Created by liangshi on 2025/12/15.
+//
+
+public var kScreenWid: CGFloat { return UIScreen.main.bounds.size.width }
+
+public var kScreenHei: CGFloat { return UIScreen.main.bounds.size.height }
+
+import UIKit
+import DeepChordsSdk
+import AVFoundation
+class ChatVC: BaseVC {
+ var recordBtn = UIButton(type: .custom)
+ let tableView = UITableView(frame: CGRectZero, style: .plain)
+
+
+ deinit {
+ stopAction()
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupViews()
+ setupSDk()
+ }
+ override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+ stopAction()
+ }
+ func setupViews() {
+ self.title = "耳机对话"
+ self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "智能体", style: .done, target: self, action: #selector(roleAction))
+
+ tableView.backgroundColor = .clear
+ tableView.delegate = self
+ tableView.dataSource = self
+ tableView.estimatedRowHeight = 60
+ tableView.separatorStyle = .none
+ tableView.register(ChatCell.self, forCellReuseIdentifier: ChatCell.reuseID)
+ self.view.addSubview(tableView)
+ tableView.snp.makeConstraints { make in
+ make.left.right.top.equalToSuperview()
+ make.bottom.equalToSuperview().inset(100)
+ }
+
+ recordBtn.backgroundColor = .blue
+ recordBtn.setTitle("开始录音", for: .normal)
+ recordBtn.setTitle("停止录音", for: .selected)
+ recordBtn.addTarget(self, action: #selector(recordAction), for: .touchUpInside)
+ view.addSubview(recordBtn)
+ recordBtn.snp.makeConstraints { make in
+ make.width.centerX.bottom.equalToSuperview()
+ make.height.equalTo(80)
+ }
+ }
+ func setupSDk(){
+ ChatManager.shared.chatNeedReloadData = {[weak self] in
+ guard let self = self else{return}
+ tableView.reloadData()
+ }
+ }
+ func reloadData(){
+
+ }
+ @objc func recordAction() {
+// self.recordBtn.isSelected = !self.recordBtn.isSelected
+// if self.recordBtn.isSelected {
+// DCChat.shared.startChat()
+// }
+// else{
+ stopAction()
+// }
+ }
+ func stopAction() {
+ DCChat.shared.stopChat()
+ }
+ @objc func roleAction(){
+ let vc = RoleVC()
+ vc.didSelectedCallback = { role in
+ ChatManager.shared.role = role
+ }
+ navigationController?.pushViewController(vc, animated: true)
+ }
+}
+
+extension ChatVC:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return ChatManager.shared.dataList.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: ChatCell.reuseID, for: indexPath) as? ChatCell
+ cell!.data = ChatManager.shared.dataList[indexPath.row]
+ return cell!
+ }
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+
+ }
+}
+class ChatCell:UITableViewCell{
+ let bgView = UIView()
+ let originalLabel = UILabel()
+
+ public static var reuseID: String {
+ return NSStringFromClass(Self.self).components(separatedBy: ".").last!
+ }
+
+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+ super.init(style: style, reuseIdentifier: reuseIdentifier)
+ setupViews()
+ setupLayout()
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ func setupViews() {
+ contentView.backgroundColor = .clear
+
+ bgView.do { v in
+// v.yc.setCornerRadius(12)
+ v.backgroundColor = .white
+ }
+ originalLabel.do { v in
+ v.font = .boldSystemFont(ofSize: 14)
+ v.textColor = .darkGray
+ v.numberOfLines = 0
+ v.textAlignment = .left
+ }
+
+ contentView.addSubview(bgView)
+ bgView.addSubview(originalLabel)
+ }
+
+ func setupLayout() {
+ bgView.snp.makeConstraints { make in
+ make.top.bottom.equalToSuperview().inset(10)
+ make.width.lessThanOrEqualTo(kScreenWid - 36)
+ make.left.equalToSuperview().inset(18)
+ }
+
+ originalLabel.snp.makeConstraints { make in
+ make.top.bottom.equalToSuperview().inset(14)
+ make.left.right.equalToSuperview().inset(12)
+ make.width.lessThanOrEqualTo(kScreenWid - 60)
+ make.width.greaterThanOrEqualTo(10)
+ make.height.greaterThanOrEqualTo(19)
+ }
+ }
+
+ var data:ChatCellModel!{
+ didSet{
+ if data.content.isEmpty{
+ originalLabel.text = ""
+ }
+ else{
+ originalLabel.text = data.content
+ }
+ if data.type == 1 {
+ bgView.backgroundColor = .blue
+ originalLabel.textColor = .white
+
+ bgView.snp.remakeConstraints { make in
+ make.top.bottom.equalToSuperview().inset(10)
+ make.right.equalToSuperview().inset(20)
+ }
+ }
+ else{
+ bgView.backgroundColor = .lightGray
+ originalLabel.textColor = .darkGray
+
+ bgView.snp.remakeConstraints { make in
+ make.top.bottom.equalToSuperview().inset(10)
+ make.left.equalToSuperview().inset(20)
+ }
+ }
+ }
+ }
+}
+++ /dev/null
-//
-// Demo.h
-// Example
-//
-// Created by liangshi on 2025/12/15.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface Demo : NSObject
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Demo.m
-// Example
-//
-// Created by liangshi on 2025/12/15.
-//
-
-#import "Demo.h"
-
-@implementation Demo
-
-@end
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
- cell.textLabel?.text = list[indexPath.row].name
+ cell.textLabel?.text = list[indexPath.row].name! + list[indexPath.row].identifier.uuidString
return cell
}
--- /dev/null
+//
+// Untitled.swift
+// Example
+//
+// Created by liangshi on 2025/12/9.
+//
+
+import UIKit
+import DeepChordsSdk
+
+class EarPhoneRecordVC: BaseVC {
+ var fromTextView = UITextView()
+ var toTextView = UITextView()
+ var recordBtn = UIButton(type: .custom)
+
+ var fromLanguage = "zh-CN"
+ var toLanguage = "en-US"
+ var fromItem:UIBarButtonItem!
+ var toItem:UIBarButtonItem!
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupView()
+ setupSdk()
+ }
+
+ override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+ stopAction()
+ }
+ func setupView(){
+ title = "手机录音"
+ view.backgroundColor = .white
+
+ fromItem = UIBarButtonItem(title: "源语言", style: .done, target: self, action: #selector(fromLanguageAction))
+ toItem = UIBarButtonItem(title: "目标语言", style: .done, target: self, action: #selector(toLanguageAction))
+ self.navigationItem.rightBarButtonItems = [
+ fromItem,toItem
+ ];
+
+ recordBtn.backgroundColor = .blue
+ recordBtn.setTitle("开始录音", for: .normal)
+ recordBtn.setTitle("停止录音", for: .selected)
+ recordBtn.addTarget(self, action: #selector(recordAction), for: .touchUpInside)
+ view.addSubview(recordBtn)
+ recordBtn.snp.makeConstraints { make in
+ make.width.centerX.bottom.equalToSuperview()
+ make.height.equalTo(80)
+ }
+
+ fromTextView.isEditable = false
+ fromTextView.layer.borderColor = UIColor.black.cgColor
+ fromTextView.layer.borderWidth = 1
+ view.addSubview(fromTextView)
+ fromTextView.snp.makeConstraints { make in
+ make.width.centerX.equalToSuperview()
+ make.top.equalToSuperview().inset(100)
+ make.height.equalTo((kScreenHei - 200)/2)
+ }
+
+ toTextView.isEditable = false
+ toTextView.layer.borderColor = UIColor.black.cgColor
+ toTextView.layer.borderWidth = 1
+ view.addSubview(toTextView)
+ toTextView.snp.makeConstraints { make in
+ make.width.centerX.equalToSuperview()
+ make.top.equalTo(fromTextView.snp.bottom).offset(20)
+ make.bottom.equalTo(recordBtn.snp.top)
+ }
+ }
+ func setupSdk(){
+ DCBleRecord.shared.asrCallback = { [weak self] text in
+ guard let self = self else{return}
+ self.fromTextView.text = text
+ let range = NSMakeRange(fromTextView.text.count - 1, 1)
+ self.fromTextView.scrollRangeToVisible(range)
+ }
+ DCBleRecord.shared.translateCallback = { [weak self] text in
+ guard let self = self else{return}
+ self.toTextView.text = text
+ let range = NSMakeRange(toTextView.text.count - 1, 1)
+ self.toTextView.scrollRangeToVisible(range)
+ }
+ DCBleRecord.shared.filePathCallBack = { [weak self] path in
+ guard let self = self else{return}
+ }
+ }
+
+ @objc func fromLanguageAction(){
+ let vc = LanuageVC()
+ vc.didSelectedCallback = { (name,value) in
+ self.fromLanguage = value
+ self.fromItem.title = name
+
+ }
+ navigationController?.pushViewController(vc, animated: true)
+ }
+ @objc func toLanguageAction(){
+ let vc = LanuageVC()
+ vc.didSelectedCallback = { (name,value) in
+ self.toLanguage = value
+ self.toItem.title = name
+
+ }
+ navigationController?.pushViewController(vc, animated: true)
+ }
+
+ @objc func recordAction() {
+ self.recordBtn.isSelected = !self.recordBtn.isSelected
+ if self.recordBtn.isSelected {
+ startAction()
+ }
+ else{
+ stopAction()
+ }
+ }
+}
+
+extension EarPhoneRecordVC{
+ func startAction(){
+ DCBleRecord.shared.fromLanguage = fromLanguage
+ DCBleRecord.shared.toLanguage = toLanguage
+ DCBleRecord.shared.isTranslate = true
+ DCBleRecord.shared.start()
+ }
+
+ func stopAction(){
+ DCBleRecord.shared.stop()
+ }
+}
--- /dev/null
+//
+// EqVC.swift
+// Example
+//
+// Created by liangshi on 2025/12/17.
+//
+
+import UIKit
+import SnapKit
+import DeepChordsSdk
+import Toast_Swift
+class EqVC: BaseVC{
+ let list:[(name:String,action:String)] = [
+ ("获取eq","getEQAction"),
+ ("正常","normalAction"),
+ ("流行","popAction"),
+ ("经典","classicAction"),
+ ("爵士","jazzAction"),
+ ("摇滚","rockAction"),
+ ("自定义","customAction"),
+
+ ]
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ // Do any additional setup after loading the view.
+
+ setupViews()
+ }
+
+ func setupViews(){
+ self.title = "eq"
+ let tableView = UITableView(frame: CGRectMake(0, 80, self.view.bounds.size.width, self.view.bounds.size.height), style: .plain)
+ tableView.delegate = self
+ tableView.dataSource = self
+ tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
+ view.addSubview(tableView)
+ }
+}
+
+extension EqVC:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+ return 60
+ }
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
+ cell.textLabel?.text = list[indexPath.row].name
+
+ return cell
+ }
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let data = list[indexPath.row]
+ let action = Selector(data.action)
+ self.perform(action)
+ }
+}
+
+extension EqVC {
+ @objc func getEQAction(){
+ DCDevice.shared.getEQ { (arg0,result) in
+ }
+ }
+ @objc func normalAction(){
+ view.makeToastActivity(.center)
+ DCDevice.shared.setEQ(type: 0x00) {[weak self] result in
+ self?.view.hideToastActivity()
+ }
+ }
+ @objc func popAction(){
+ view.makeToastActivity(.center)
+ DCDevice.shared.setEQ(type: 0x01) {[weak self] result in
+ self?.view.hideToastActivity()
+ }
+ }
+ @objc func classicAction(){
+ view.makeToastActivity(.center)
+ DCDevice.shared.setEQ(type: 0x02) {[weak self] result in
+ self?.view.hideToastActivity()
+ }
+ }
+ @objc func jazzAction(){
+ view.makeToastActivity(.center)
+ DCDevice.shared.setEQ(type: 0x03) {[weak self] result in
+ self?.view.hideToastActivity()
+ }
+ }
+ @objc func rockAction(){
+ view.makeToastActivity(.center)
+ DCDevice.shared.setEQ(type: 0x04) {[weak self] result in
+ self?.view.hideToastActivity()
+ }
+ }
+ @objc func customAction(){
+ let list = [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ ]
+ view.makeToastActivity(.center)
+
+ let dispatchGroup = DispatchGroup()
+ for (index,item) in list.enumerated() {
+ dispatchGroup.enter()
+ DCDevice.shared.setCustomEQ(index: UInt8(index), value: item) {result in
+ dispatchGroup.leave()
+ }
+ }
+
+ dispatchGroup.notify(queue:.main) {
+ self.view.hideToastActivity()
+ DCDevice.shared.setEQ(type: 0x05) {[weak self] result in
+ self?.view.hideToastActivity()
+ }
+ }
+
+ }
+}
import Toast_Swift
class HomeVC: BaseVC{
let list:[(name:String,action:String)] = [
+ ("开始查找耳机","startFindAction"),
+ ("停止查找耳机","stopFindAction"),
("获取电量","batteryAction"),
("获取软件版本","softVersionAction"),
("获取硬件版本","hardVersionAction"),
+ ("EQ","eqAction"),
+ ("音乐","musicAction"),
("现场录音","recordAction"),
("耳机录音","bleAsrAction"),
("对话","chatAction"),
DispatchQueue.main.asyncAfter(deadline:.now() + 2) {
ChatManager.shared.setupSdk()
}
-
}
func setupViews(){
- self.title = "设备鉴权+设备采集音频"
+ self.title = "DeepChords SDK"
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "扫描", style: .done, target: self, action: #selector(scanAction))
let tableView = UITableView(frame: CGRectMake(0, 80, self.view.bounds.size.width, self.view.bounds.size.height), style: .plain)
}
extension HomeVC{
+
+ @objc func startFindAction(){
+ view.makeToastActivity(.center)
+ DCDevice.shared.findDevice(state: 1) {[weak self] result in
+ self?.view.hideToastActivity()
+ }
+ }
+ @objc func stopFindAction(){
+ view.makeToastActivity(.center)
+ DCDevice.shared.findDevice(state: 0) {[weak self] result in
+ self?.view.hideToastActivity()
+ }
+ }
@objc func batteryAction(){
view.makeToastActivity(.center)
DCDevice.shared.getBatery {[weak self] result in
self?.view.hideToastActivity()
- if let (left,right) = result{
- }
}
}
@objc func softVersionAction(){
view.makeToastActivity(.center)
DCDevice.shared.getSoftVersion {[weak self] result in
self?.view.hideToastActivity()
- if let version = result{
- }
}
}
@objc func hardVersionAction(){
view.makeToastActivity(.center)
DCDevice.shared.getHardVersion {[weak self] result in
self?.view.hideToastActivity()
- if let version = result{
- }
}
}
+ @objc func eqAction(){
+ self.navigationController?.pushViewController(EqVC(), animated: true)
+ }
+ @objc func musicAction(){
+ self.navigationController?.pushViewController(MusicVC(), animated: true)
+ }
@objc func recordAction(){
- self.navigationController?.pushViewController(BleSdkPhoneAsrVC(), animated: true)
+ self.navigationController?.pushViewController(PhoneRecordVC(), animated: true)
}
@objc func bleAsrAction(){
- navigationController?.pushViewController(BleSdkEarPhonesAsrVC(), animated: true)
+ navigationController?.pushViewController(EarPhoneRecordVC(), animated: true)
}
@objc func chatAction(){
- navigationController?.pushViewController(BleSdkBleChatVC(), animated: true)
+ navigationController?.pushViewController(ChatVC(), animated: true)
}
}
//
import UIKit
-import StarburstSdk
import Toast_Swift
-class SelectLanuageVC: BaseVC {
+class LanuageVC: BaseVC {
private var tableView: UITableView!
private var list:[(name: String,value:String)] = [
("简体中文" ,"zh-CN"),
}
}
}
-extension SelectLanuageVC:UITableViewDataSource, UITableViewDelegate{
+extension LanuageVC:UITableViewDataSource, UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
var textView = UITextView()
override func viewDidLoad() {
- title = "log"
+ title = "app log"
view.backgroundColor = .white
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "save", style: .done, target: self, action: #selector(shareAction))
textView.isEditable = false
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// var version = (Bundle.main.appVersion ?? "") + "\n"
- let version = "2025151001" + "\n"
+ let version = "2025151801" + "\n"
textView.text = "版本:\(version)" + DCLogger.logs.joined()
let range = NSMakeRange(textView.text.count - 1, 1)
textView.scrollRangeToVisible(range)
--- /dev/null
+//
+// MusicVC.swift
+// Example
+//
+// Created by liangshi on 2025/12/17.
+//
+
+import UIKit
+import SnapKit
+import DeepChordsSdk
+import Toast_Swift
+class MusicVC: BaseVC{
+ let list = [DCMusic]()
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ // Do any additional setup after loading the view.
+
+ setupViews()
+ loadData()
+ }
+
+ func setupViews(){
+ self.title = "音乐"
+ let tableView = UITableView(frame: CGRectMake(0, 80, self.view.bounds.size.width, self.view.bounds.size.height), style: .plain)
+ tableView.delegate = self
+ tableView.dataSource = self
+ tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
+ view.addSubview(tableView)
+ }
+}
+
+extension MusicVC:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+ return 60
+ }
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
+ cell.textLabel?.text = list[indexPath.row].name
+
+ return cell
+ }
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let data = list[indexPath.row]
+ navigationController?.pushViewController(PlayerVC(music: data), animated: true)
+ }
+ func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
+ if editingStyle == .delete {
+ guard let id = UInt16(list[indexPath.row].id) else {return}
+ DCDevice.shared.musicDelete(list: [id]) { result in
+
+ }
+
+ }
+ }
+ func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
+ return true
+ }
+ func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
+ return "删除"
+ }
+}
+
+extension MusicVC {
+ func loadData(){
+ DCDevice.shared.getMusicList(size: 10, index: 0) {[weak self] (list, result) in
+ guard let self = self else{return}
+ guard let list = list else{return}
+ }
+ }
+
+}
--- /dev/null
+//
+// Ble.swift
+// Example
+//
+// Created by liangshi on 2025/12/9.
+//
+
+import UIKit
+import DeepChordsSdk
+
+class PhoneRecordVC: BaseVC {
+ var fromTextView = UITextView()
+ var toTextView = UITextView()
+ var recordBtn = UIButton(type: .custom)
+
+ var fromLanguage = "zh-CN"
+ var toLanguage = "en-US"
+ var fromItem:UIBarButtonItem!
+ var toItem:UIBarButtonItem!
+
+
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupView()
+ setupSdk()
+ }
+
+ override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+ stopAction()
+ }
+ func setupView(){
+ title = "手机录音"
+ view.backgroundColor = .white
+
+ fromItem = UIBarButtonItem(title: "源语言", style: .done, target: self, action: #selector(fromLanguageAction))
+ toItem = UIBarButtonItem(title: "目标语言", style: .done, target: self, action: #selector(toLanguageAction))
+ self.navigationItem.rightBarButtonItems = [
+ fromItem,toItem
+ ];
+
+ recordBtn.backgroundColor = .blue
+ recordBtn.setTitle("开始录音", for: .normal)
+ recordBtn.setTitle("停止录音", for: .selected)
+ recordBtn.addTarget(self, action: #selector(recordAction), for: .touchUpInside)
+ view.addSubview(recordBtn)
+ recordBtn.snp.makeConstraints { make in
+ make.width.centerX.bottom.equalToSuperview()
+ make.height.equalTo(80)
+ }
+
+ fromTextView.isEditable = false
+ fromTextView.layer.borderColor = UIColor.black.cgColor
+ fromTextView.layer.borderWidth = 1
+ view.addSubview(fromTextView)
+ fromTextView.snp.makeConstraints { make in
+ make.width.centerX.equalToSuperview()
+ make.top.equalToSuperview().inset(100)
+ make.height.equalTo((kScreenHei - 200)/2)
+ }
+
+ toTextView.isEditable = false
+ toTextView.layer.borderColor = UIColor.black.cgColor
+ toTextView.layer.borderWidth = 1
+ view.addSubview(toTextView)
+ toTextView.snp.makeConstraints { make in
+ make.width.centerX.equalToSuperview()
+ make.top.equalTo(fromTextView.snp.bottom).offset(20)
+ make.bottom.equalTo(recordBtn.snp.top)
+ }
+ }
+ func setupSdk(){
+ DCRecord.shared.asrCallback = { [weak self] text in
+ guard let self = self else{return}
+ self.fromTextView.text = text
+ let range = NSMakeRange(fromTextView.text.count - 1, 1)
+ self.fromTextView.scrollRangeToVisible(range)
+ }
+ DCRecord.shared.translateCallback = { [weak self] text in
+ guard let self = self else{return}
+ self.toTextView.text = text
+ let range = NSMakeRange(toTextView.text.count - 1, 1)
+ self.toTextView.scrollRangeToVisible(range)
+ }
+ DCRecord.shared.filePathCallBack = { [weak self] path in
+ guard let self = self else{return}
+ }
+ }
+
+ @objc func fromLanguageAction(){
+ let vc = LanuageVC()
+ vc.didSelectedCallback = { (name,value) in
+ self.fromLanguage = value
+ self.fromItem.title = name
+
+ }
+ navigationController?.pushViewController(vc, animated: true)
+ }
+ @objc func toLanguageAction(){
+ let vc = LanuageVC()
+ vc.didSelectedCallback = { (name,value) in
+ self.toLanguage = value
+ self.toItem.title = name
+
+ }
+ navigationController?.pushViewController(vc, animated: true)
+ }
+
+ @objc func recordAction() {
+ self.recordBtn.isSelected = !self.recordBtn.isSelected
+ if self.recordBtn.isSelected {
+ startAction()
+ }
+ else{
+ stopAction()
+ }
+ }
+}
+
+extension PhoneRecordVC{
+ func startAction(){
+ DCRecord.shared.fromLanguage = fromLanguage
+ DCRecord.shared.toLanguage = toLanguage
+ DCRecord.shared.isTranslate = true
+ DCRecord.shared.start()
+ }
+
+ func stopAction(){
+ DCRecord.shared.stop()
+ }
+}
--- /dev/null
+//
+// PlayerVC.swift
+// Example
+//
+// Created by liangshi on 2025/12/18.
+//
+
+import UIKit
+import SnapKit
+import DeepChordsSdk
+import Toast_Swift
+class PlayerVC: BaseVC{
+ let playBtn = UIButton(type: .custom)
+ let modeBtn = UIButton(type: .custom)
+ let music:DCMusic
+ init(music:DCMusic) {
+ self.music = music
+ super.init()
+ }
+
+ @MainActor required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ // Do any additional setup after loading the view.
+
+ setupViews()
+ }
+
+ func setupViews(){
+ self.title = "eq"
+
+ playBtn.do { v in
+ v.setTitle("播放", for: .normal)
+ v.setTitle("暂停", for: .selected)
+ v.addTarget(self, action: #selector(playBtnAction), for: .touchUpInside)
+ }
+ playBtn.frame = CGRect(x: 0, y: 0, width: 50, height: 44)
+ self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: playBtn)
+
+ modeBtn.do { v in
+ v.setTitle("播放", for: .normal)
+ v.setTitle("暂停", for: .selected)
+ v.addTarget(self, action: #selector(playBtnAction), for: .touchUpInside)
+ }
+ }
+ @objc func playBtnAction(){
+ guard let id = UInt16(music.id) else {return}
+ playBtn.isSelected = !playBtn.isSelected
+ if playBtn.isSelected {
+ DCDevice.shared.musicPlay(index: id) { index, result in
+
+ }
+ }
+ else{
+ DCDevice.shared.musicPause { index, result in
+
+ }
+ }
+ }
+}
--- /dev/null
+//
+// Untitled.swift
+// Example
+//
+// Created by liangshi on 2025/12/18.
+//
+
+import UIKit
+import Toast_Swift
+import DeepChordsSdk
+
+class RoleVC: BaseVC {
+ private var tableView: UITableView!
+ private var list = [DCRole]()
+ var didSelectedCallback: ((DCRole) -> Void)?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ view.backgroundColor = .white
+
+ tableView = UITableView(frame:.zero, style:.plain)
+ tableView.dataSource = self
+ tableView.delegate = self
+ tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
+ view.addSubview(tableView)
+ tableView.snp.makeConstraints { make in
+ make.edges.equalToSuperview()
+ }
+ DCChat.shared.getVcSpeekerList { [weak self] (list, success) in
+ if let list = list{
+ self?.list = list
+ self?.tableView.reloadData()
+ }
+ }
+ }
+}
+extension RoleVC:UITableViewDataSource, UITableViewDelegate{
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
+ let model = list[indexPath.row]
+ cell.textLabel?.text = model.name
+
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let model = list[indexPath.row]
+ didSelectedCallback?(model)
+ self.navigationController?.popViewController(animated: true)
+
+ }
+}
var textView = UITextView()
override func viewDidLoad() {
- title = "log"
+ title = "sdk log"
view.backgroundColor = .white
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "save", style: .done, target: self, action: #selector(shareAction))
textView.isEditable = false
func connectPeripheral(_ peripheral: CBPeripheral) {
DCLogger.debug("正在连接...",peripheral)
centralManager.connect(peripheral, options: [CBConnectPeripheralOptionNotifyOnConnectionKey: true])
+ }
+ func cancel(){
+
}
func autoConnect(){
// if let peripheral = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: "AE30")]).first{
--- /dev/null
+//
+// ChatManager.swift
+// Example
+//
+// Created by liangshi on 2025/12/15.
+//
+import AVFoundation
+import DeepChordsSdk
+
+/// Ai回应模型
+public class ChatCellModel:NSObject,NSCoding {
+ public var type: Int = 0//1发,0收
+ public var content: String = ""
+ public var id:Int = 0
+
+ required public override init() { }
+
+ public func encode(with aCoder: NSCoder) {
+ aCoder.encode("\(type)", forKey: "type")
+ aCoder.encode(content, forKey: "content")
+ aCoder.encode("\(id)", forKey: "id")
+ }
+
+ required public init?(coder aDecoder: NSCoder) {
+ type = Int(aDecoder.decodeObject(forKey: "type") as? String ?? "0") ?? 0
+ content = aDecoder.decodeObject(forKey: "content") as? String ?? ""
+ id = Int(aDecoder.decodeObject(forKey: "id") as? String ?? "0") ?? 0
+ }
+}
+
+
+class ChatManager:NSObject{
+ static let shared = ChatManager()
+ var isTtsPlaying = false
+ private var audioData: Data?
+
+ var dataList:[ChatCellModel] = []
+ var chatNeedReloadData:(()->Void)?
+
+ var role:DCRole? {
+ didSet{
+ setupChat()
+ }
+ }
+
+ public func stop(){
+ DCChat.shared.stopChat()
+ }
+ public func getVcSpeekerList(finished:@escaping ([DCRole]?,Bool)->Void){
+ DCChat.shared.getVcSpeekerList(finished: finished)
+ }
+
+ func setupSdk(){
+
+ PcmSound.sharedInstance().setup(16000, withchannels: 1)
+ let options: AVAudioSession.CategoryOptions = [.allowBluetooth]
+ do {
+ try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
+ try AVAudioSession.sharedInstance().setActive(true)
+ } catch {
+ DCLogger.debug(error)
+ }
+
+ setupChat()
+ }
+
+ func setupChat(){
+ DCChat.shared.role = role
+ DCChat.shared.initChat()
+ DCChat.shared.asrCallback = {[weak self] (text,index) in
+ guard let self = self else{return}
+ if let model = dataList.last,model.id == index,model.type == 1 {
+ model.content = text
+ }
+ else{
+ let model = ChatCellModel()
+ model.type = 1
+ model.content = text
+ model.id = Int(index)
+ dataList.append(model)
+ }
+ chatNeedReloadData?()
+ }
+ DCChat.shared.responseCallback = { [weak self] (text,index) in
+ guard let self = self else{return}
+ if let model = dataList.last,model.id == index,model.type == 2 {
+ model.content = text
+ }
+ else{
+ let model = ChatCellModel()
+ model.type = 2
+ model.content = text
+ model.id = Int(index)
+ dataList.append(model)
+ }
+ chatNeedReloadData?()
+ }
+ DCChat.shared.dataCallback = {[weak self] dialogId, data, finish in
+ // PcmSound.sharedInstance().delegate = self
+ guard let self = self else { return }
+ // if (!isTtsPlaying) {
+ // isTtsPlaying = true
+ // DCLogger.debug("开始播放")
+ // DCChat.shared.startPlayTtsAudio()
+ // }
+ // DCLogger.debug("收到音频数据", data?.count ?? 0)
+ // PcmSound.sharedInstance().feed(data)
+
+ if finish {
+ self.saveToFile(data: self.audioData!)
+ self.audioData = nil
+ } else {
+ if self.audioData == nil {
+ self.audioData = Data()
+ }
+ self.audioData?.append(data!)
+ }
+ }
+ DCChat.shared.codeCallback = { code in
+ // if code == 20001 {
+ // if (self.isTtsPlaying) {
+ // self.isTtsPlaying = false
+ // PcmSound.sharedInstance().cleanup()
+ // PcmSound.sharedInstance().setup(16000, withchannels: 1)
+ //
+ //// var options: AVAudioSession.CategoryOptions = [.allowBluetooth]
+ //// do {
+ //// try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
+ //// try AVAudioSession.sharedInstance().setActive(true)
+ //// } catch {
+ //// DCLogger.debug(error)
+ //// }
+ // }
+ // }
+ }
+ DCChat.shared.finishCallback = { path in
+
+ }
+ }
+
+ func saveToFile(data: Data) {
+ let filePath = NSHomeDirectory() + "/Documents/1.mp3"
+ let url = URL(fileURLWithPath: filePath)
+ do {
+ try data.write(to: url)
+ print("\(filePath)")
+
+ var options: AVAudioSession.CategoryOptions = [.allowBluetooth]
+ do {
+ try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
+ try AVAudioSession.sharedInstance().setActive(true)
+ } catch {
+ DCLogger.debug(error)
+ }
+ //这个要传开始播放的tts的dialogid
+ DCChat.shared.startPlayTtsAudio()
+ PlayerManager.shared.play(filePath: filePath,dialoIg:0) { (success,dialoIg) in
+ print("播放结束 = \(success)")
+ DCChat.shared.stopPlayTtsAudio()
+ }
+ } catch let error {
+ print("\(error)")
+ }
+ }
+}
+extension ChatManager : PcmSoundDelegate {
+ func remaining(_ frames: UInt) {
+ DCLogger.debug("[frame:\(frames)]");
+ if (frames == 0) {
+ DCChat.shared.stopPlayTtsAudio()
+ }
+ }
+}
--- /dev/null
+//
+// then.swift
+// Example
+//
+// Created by liangshi on 2025/12/16.
+//
+
+import Foundation
+import CoreGraphics
+#if os(iOS) || os(tvOS)
+import UIKit.UIGeometry
+#endif
+
+public protocol Then {}
+
+extension Then where Self: Any {
+
+ /// Makes it available to set properties with closures just after initializing and copying the value types.
+ ///
+ /// let frame = CGRect().with {
+ /// $0.origin.x = 10
+ /// $0.size.width = 100
+ /// }
+ public func with(_ block: (inout Self) throws -> Void) rethrows -> Self {
+ var copy = self
+ try block(©)
+ return copy
+ }
+
+ /// Makes it available to execute something with closures.
+ ///
+ /// UserDefaults.standard.do {
+ /// $0.set("devxoul", forKey: "username")
+ /// $0.set("devxoul@gmail.com", forKey: "email")
+ /// $0.synchronize()
+ /// }
+ public func `do`(_ block: (Self) throws -> Void) rethrows {
+ try block(self)
+ }
+
+}
+
+extension Then where Self: AnyObject {
+
+ /// Makes it available to set properties with closures just after initializing.
+ ///
+ /// let label = UILabel().then {
+ /// $0.textAlignment = .center
+ /// $0.textColor = UIColor.black
+ /// $0.text = "Hello, World!"
+ /// }
+ public func then(_ block: (Self) throws -> Void) rethrows -> Self {
+ try block(self)
+ return self
+ }
+
+}
+
+extension NSObject: Then {}
+
+extension CGPoint: Then {}
+extension CGRect: Then {}
+extension CGSize: Then {}
+extension CGVector: Then {}
+extension Array: Then {}
+extension Dictionary: Then {}
+extension Set: Then {}
+
+#if os(iOS) || os(tvOS)
+extension UIEdgeInsets: Then {}
+extension UIOffset: Then {}
+extension UIRectEdge: Then {}
+#endif
+
+
+extension Then where Self: UIView {
+ public func add(toSuperView superView: UIView) -> Self {
+ guard superview != self else { return self }
+ superView.addSubview(self)
+ return self
+ }
+}
+
+extension Array where Element: UIView {
+ public func `do`(_ block: (Element) throws -> Void) rethrows {
+ for e in self {
+ try block(e)
+ }
+ }
+}