From: liangzhenying <867174124@qq.com> Date: Wed, 24 Dec 2025 03:04:30 +0000 (+0800) Subject: 修改蓝牙连接管理 X-Git-Tag: 1.0.2~21 X-Git-Url: http://git.snicker.com.cn/Users/apple/Desktop/static/gitweb.css?a=commitdiff_plain;h=d7eef34715bb3ce20a72c1064737e59bcd31f859;p=mirrors%2FShenYin.git 修改蓝牙连接管理 --- diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/DCRecordManager.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/DCRecordManager.swift deleted file mode 100644 index e5c9f04..0000000 --- a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/DCRecordManager.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// Record.swift -// Example -// -// Created by liangshi on 2025/12/19. -// -//import DeepChordsSdk -// -//class DCRecordManager{ -// static let shared = DCRecordManager() -// -// func setupRecord(){ -// DCBleRecord.shared.codeCallback = { [weak self] code in -// guard let self = self else{return} -// if code == 20001 { -// if let vc = App.shared.topVC() as? EarPhoneRecordVC { -// // vc.startRecord() -// }else{ -// App.shared.goToPage(EarPhoneRecordVC()) -// } -// } -// else if code == 20002 || code == 20003{ -//// self.recordBtn.isSelected = false -// } -// -// } -// } -//} diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/PlayerManager.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/PlayerManager.swift deleted file mode 100644 index 2e5361d..0000000 --- a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/PlayerManager.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// Untitled.swift -// Example -// -// Created by liangshi on 2025/12/15. -// - -import Foundation -import AVFoundation - -class PlayerManager:NSObject{ - public static let shared = PlayerManager() - private var finishCallback:((_ success:Bool,_ dialoIg:Int) -> Void)? - var dialoIg = 0 - - private override init() { - super.init() - } - - var player = AVAudioPlayer() - - func play(filePath:String,dialoIg:Int,finished: ((_ success: Bool,_ dialoIg:Int) -> Void)? = nil) { - self.dialoIg = dialoIg - print("声音播放: \(filePath)") - self.finishCallback = finished - let url = URL(fileURLWithPath: filePath) - do { - try player = AVAudioPlayer(contentsOf: url) - player.prepareToPlay() - player.delegate = self - player.play() - } catch let error as NSError { - print("声音播放失败 \(error.description)") - self.finishCallback?(false,dialoIg) - } - } - - func stop(){ - if player.isPlaying{ - player.stop() - } - } -} - -extension PlayerManager:AVAudioPlayerDelegate{ - func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { - print("播放结束 \(flag)") - self.finishCallback?(true,self.dialoIg) - } - - func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) { - if let error = error { - print("解码错误: \(error.localizedDescription)") - } - self.finishCallback?(false,self.dialoIg) - } -} - - diff --git a/ShenYin/ShenYin.xcodeproj/project.pbxproj b/ShenYin/ShenYin.xcodeproj/project.pbxproj index 6890572..ac87ccd 100644 --- a/ShenYin/ShenYin.xcodeproj/project.pbxproj +++ b/ShenYin/ShenYin.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 3F7602F12EFA8BAB00588C18 /* DeepChordsSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */; }; + 3F7602F22EFA8BAB00588C18 /* DeepChordsSdk.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3F79C6142E6055E500EC38B9 /* JoyGemAI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */; }; 3F79C6152E6055E500EC38B9 /* JoyGemAI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3F8F58292EBCA2B800FFC00B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */; }; @@ -20,6 +22,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 3F7602F22EFA8BAB00588C18 /* DeepChordsSdk.framework in Embed Frameworks */, 3F79C6152E6055E500EC38B9 /* JoyGemAI.framework in Embed Frameworks */, ); name = "Embed Frameworks"; @@ -29,6 +32,7 @@ /* Begin PBXFileReference section */ 3862D5561144E20721225B96 /* Pods_ShenYin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShenYin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DeepChordsSdk.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JoyGemAI.framework; sourceTree = ""; }; 3F887B9C2E38D8DC00C98658 /* ShenYin.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShenYin.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; @@ -65,6 +69,7 @@ buildActionMask = 2147483647; files = ( F2E449CAD5874BE652A69B50 /* Pods_ShenYin.framework in Frameworks */, + 3F7602F12EFA8BAB00588C18 /* DeepChordsSdk.framework in Frameworks */, 3F79C6142E6055E500EC38B9 /* JoyGemAI.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -113,6 +118,7 @@ 676B86A4BA2639E8694D56B4 /* Frameworks */ = { isa = PBXGroup; children = ( + 3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */, 3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */, 3862D5561144E20721225B96 /* Pods_ShenYin.framework */, ); diff --git a/ShenYin/ShenYin.xcworkspace/contents.xcworkspacedata b/ShenYin/ShenYin.xcworkspace/contents.xcworkspacedata index b1846c8..44c3dc7 100644 --- a/ShenYin/ShenYin.xcworkspace/contents.xcworkspacedata +++ b/ShenYin/ShenYin.xcworkspace/contents.xcworkspacedata @@ -7,4 +7,7 @@ + + diff --git a/ShenYin/ShenYin/DcSdk/DCChatManager.swift b/ShenYin/ShenYin/DcSdk/DCChatManager.swift new file mode 100644 index 0000000..005b2e8 --- /dev/null +++ b/ShenYin/ShenYin/DcSdk/DCChatManager.swift @@ -0,0 +1,165 @@ +// +// DCChatManager.swift +// Example +// +// Created by liangshi on 2025/12/15. +// +import AVFoundation +import DeepChordsSdk +//typedef NS_OPTIONS(NSInteger,StarburstCode) { +// StarburstCode_Start_Record = 20001,///开始录音 +// StarburstCode_Stop_Record = 20002,///停止录音 +// StarburstCode_Record_Error = 20003,///录音出错 +// StarburstCode_Ble_Disconected = 20004,///蓝牙断开 +// StarburstCode_Websocket_Connected = 30001,///socket连上 +// StarburstCode_Websocket_Disconnected = 30002,///socket断开连接 +// StarburstCode_Websocket_Connecting = 30003,///socket连接中... +// StarburstCode_Websocket_pingTimeOut = 30004,///ping超时 +// StarburstCode_Net_Error = 50000,///网络错误 +// StarburstCode_UnAuth = 60000,///未鉴权 +//}; + + +class DCChatManager:NSObject{ + static let shared = DCChatManager() + private var isTtsPlaying = false + private var audioData: Data? + + public var dataList:[ChatCellModel] = [] + public var chatNeedReloadData:(()->Void)? + /// 状态码回调 + public var codeCallback:((Int)->Void)? + /// 结束对话回调 + public var finishCallback:((String?)->Void)? + + var role:DCRole? { + didSet{ + setupChat() + } + } + + public func stopChat(){ + DCChat.shared.stopChat() + } + public func startChat(){ + DCChat.shared.startChat() + } + public func getVcSpeekerList(finished:@escaping ([DCRole]?,Bool)->Void){ + DCChat.shared.getVcSpeekerList(finished: finished) + } + + func preparePlay(){ + 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 setupChat(){ + preparePlay() + DCChat.shared.role = role + 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,sampleRate) 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,sampleRate) + PcmSound.sharedInstance().feed(data) + } + DCChat.shared.codeCallback = {[weak self] code in + guard let self = self else { return } + self.codeCallback?(code) + + 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 = {[weak self] path in + self?.preparePlay() + self?.finishCallback?(path) + } + + } + +// 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 DCChatManager : PcmSoundDelegate { + func remaining(_ frames: UInt) { + DCLogger.debug("[frame:\(frames)]"); + if (frames == 0) { + DCChat.shared.stopPlayTtsAudio() + } + } +} diff --git a/ShenYin/ShenYin/DcSdk/DCSdkManager.swift b/ShenYin/ShenYin/DcSdk/DCSdkManager.swift new file mode 100644 index 0000000..f249c97 --- /dev/null +++ b/ShenYin/ShenYin/DcSdk/DCSdkManager.swift @@ -0,0 +1,53 @@ +// +// DCSdkManager.swift +// Example +// +// Created by liangshi on 2025/12/19. +// +import DeepChordsSdk + +class DCSdkManager{ + static let shared = DCSdkManager() + + + func initSdk(){ + DeepChordsAiSdk.shared.initSDK() +// DCRecordManager.shared.setupRecord() + DCChatManager.shared.setupChat() + + DCDevice.shared.eventCallback = { event in + switch event { + case 0x01: +// if let vc = App.shared.topVC() as? ChatVC { +// // vc.startRecord() +// }else{ +// App.shared.goToPage(ChatVC()) +// } + break + case 0x02: +// if let vc = App.shared.topVC() as? ChatVC { +// // vc.startRecord() +// }else{ +// App.shared.goToPage(ChatVC()) +// } + break + case 0x03: +// if let vc = App.shared.topVC() as? EarPhoneRecordVC { +// // vc.startRecord() +// }else{ +// App.shared.goToPage(EarPhoneRecordVC()) +// } + break + case 0x04: +// if let vc = App.shared.topVC() as? EarPhoneRecordVC { +// // vc.startRecord() +// }else{ +// App.shared.goToPage(EarPhoneRecordVC()) +// } + break + default: + break + } + } + } +} diff --git a/ShenYin/ShenYin/JoySdk/JoyBleManager.swift b/ShenYin/ShenYin/JoySdk/JoyBleManager.swift new file mode 100644 index 0000000..971d7c7 --- /dev/null +++ b/ShenYin/ShenYin/JoySdk/JoyBleManager.swift @@ -0,0 +1,88 @@ +//// +//// JotBleManager.swift +//// ShenYin +//// +//// Created by liangshi on 2025/12/23. +//// +// +//public class JoyBleManager { +// public static let shared = JoyBleManager() +// private var connectPeripheral: CBPeripheral? +// private var writeCha: CBCharacteristic? +//} +//extension JoyBleManager{ +// static func getMac(_ dict:[String:Any])->String?{ +// if let advMsd = dict[CBAdvertisementDataManufacturerDataKey] as? Data { +// if (advMsd.count >= 13) { +// let mac = advMsd[7...12]; +// return mac.map { String($0, radix: 16).padLeft(toLength: 2, withPad: "0") }.joined(separator: ":").uppercased() +// } else { +// return nil +// } +// } else { +// return nil +// } +// } +//} +////public extension JoyBleManager{ +//// func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { +//// Logger.debug("蓝牙已连接 \(peripheral)") +//// connectPeripheral = peripheral +//// } +//// func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { +//// Logger.debug("peripheral: %@ failed to connect", peripheral) +//// } +//// func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { +//// Logger.debug("蓝牙已断开 \(peripheral)") +//// } +//// +////// func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { +////// Logger.debug("发现服务成功") +////// for service in peripheral.services! { +////// Logger.debug("peripheral service: %@", service) +////// peripheral.discoverCharacteristics(nil, for: service) +////// } +////// +////// } +////// func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { +////// if let list = service.characteristics{ +////// Logger.debug("发现特征",list) +////// for char in list{ +////// Logger.debug(char) +////// peripheral.setNotifyValue(true, for: char) +////// if char.uuid.uuidString == "AE03" { +////// writeCha = char +////// StarburstSdk.shared().bleConnected() +////// } +////// } +////// } +////// } +////// +////// func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { +////// // Logger.debug("收 ",characteristic.uuid,characteristic.value?.joined() ?? "") +////// guard let data = characteristic.value else { return } +////// if data.count > 4 && data[0] == 0xBA { +////// if let sender = BleSender.answer(data) { +////// sender.completion?(.response.code(.success).value(data)) +////// if data[1] == 0x10,data[2] == 0x01{ +////// //音乐列表分包,解析的时候处理 +////// } +////// else{ +////// sender.deinitTimer() +////// sender.remove() +////// } +////// return +////// } +////// else if data[1] == 0x0D{ +////// let subData = data.subdata(in: 2..String?{ + static func getMac(_ dict:[String:Any])->String?{ if let advMsd = dict[CBAdvertisementDataManufacturerDataKey] as? Data { if (advMsd.count >= 13) { let mac = advMsd[7...12]; diff --git a/ShenYin/ShenYin/Launch/AppManager.swift b/ShenYin/ShenYin/Launch/AppManager.swift index 4f5a36e..5ca0a88 100644 --- a/ShenYin/ShenYin/Launch/AppManager.swift +++ b/ShenYin/ShenYin/Launch/AppManager.swift @@ -25,6 +25,7 @@ class App{ Logger.debug(DCFolder.record) window?.rootViewController = BaseTC() JoySdkManager.shared.chat.loadChatCache() +// DCSdkManager.shared.initSdk() } func goToLogin(){ window?.rootViewController = BaseNC(rootViewController: LoginVC()) diff --git a/ShenYin/ShenYin/UI/Base/BaseTC.swift b/ShenYin/ShenYin/UI/Base/BaseTC.swift index 792eb34..748c887 100644 --- a/ShenYin/ShenYin/UI/Base/BaseTC.swift +++ b/ShenYin/ShenYin/UI/Base/BaseTC.swift @@ -23,7 +23,7 @@ class BaseTC:UITabBarController{ func setupUI(){ - let item0 = UITabBarItem(title: "智能".l10n + " " + "AI", image: UIImage(named: "tab_0_normal")?.withRenderingMode(.alwaysOriginal), selectedImage: UIImage(named: "tab_0_selected")?.withRenderingMode(.alwaysOriginal)) + let item0 = UITabBarItem(title: "AI" + " " + "智能".l10n , image: UIImage(named: "tab_0_normal")?.withRenderingMode(.alwaysOriginal), selectedImage: UIImage(named: "tab_0_selected")?.withRenderingMode(.alwaysOriginal)) let nc0 = BaseNC(rootViewController: homeVC) nc0.tabBarItem = item0