修改蓝牙连接管理
authorliangzhenying <867174124@qq.com>
Wed, 24 Dec 2025 03:04:30 +0000 (11:04 +0800)
committerliangzhenying <867174124@qq.com>
Wed, 24 Dec 2025 03:04:30 +0000 (11:04 +0800)
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/DCRecordManager.swift [deleted file]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/PlayerManager.swift [deleted file]
ShenYin/ShenYin.xcodeproj/project.pbxproj
ShenYin/ShenYin.xcworkspace/contents.xcworkspacedata
ShenYin/ShenYin/DcSdk/DCChatManager.swift [new file with mode: 0644]
ShenYin/ShenYin/DcSdk/DCSdkManager.swift [new file with mode: 0644]
ShenYin/ShenYin/JoySdk/JoyBleManager.swift [new file with mode: 0644]
ShenYin/ShenYin/JoySdk/JoySdkManager.swift
ShenYin/ShenYin/Launch/AppManager.swift
ShenYin/ShenYin/UI/Base/BaseTC.swift

diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/DCRecordManager.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/DCRecordManager.swift
deleted file mode 100644 (file)
index e5c9f04..0000000
+++ /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 (file)
index 2e5361d..0000000
+++ /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)
-    }
-}
-
-
index 6890572..ac87ccd 100644 (file)
@@ -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 = "<group>"; };
                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 = "<group>"; };
@@ -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;
                676B86A4BA2639E8694D56B4 /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */,
                                3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */,
                                3862D5561144E20721225B96 /* Pods_ShenYin.framework */,
                        );
index b1846c8..44c3dc7 100644 (file)
@@ -7,4 +7,7 @@
    <FileRef
       location = "group:Pods/Pods.xcodeproj">
    </FileRef>
+   <FileRef
+      location = "container:../DeepChordsSdk_iOS/DeepChordsSdk/Example/Example.xcodeproj">
+   </FileRef>
 </Workspace>
diff --git a/ShenYin/ShenYin/DcSdk/DCChatManager.swift b/ShenYin/ShenYin/DcSdk/DCChatManager.swift
new file mode 100644 (file)
index 0000000..005b2e8
--- /dev/null
@@ -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 (file)
index 0000000..f249c97
--- /dev/null
@@ -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 (file)
index 0000000..971d7c7
--- /dev/null
@@ -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..<data.count - 3)
+//////                //Logger.debug("传给字节sdk",subData.joined())
+//////                StarburstSdk.shared().receiveBleData(subData)
+//////            }else{
+//////                receiveNoticeData(data)
+//////            }
+//////        }
+//////        else{
+//////            Logger.debug("收到异常数据!!!!!!!!!!!")
+//////        }
+//////    }
+////}
index 94cf34e..dcf455d 100644 (file)
@@ -45,8 +45,7 @@ extension JoySdkManager {
     
     func setupLog(){
         //MARK: 配置日志类型
-        //JoyGemAIManager.shared().setLogMode(JoyGemLogMode.all)
-        JoyGemAIManager.shared().setLogMode(JoyGemLogMode.close)
+        JoyGemAIManager.shared().setLogMode(.close)
         
         let fileManager = FileManager.default
         if let appSupportDirectory = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
@@ -108,6 +107,9 @@ extension JoySdkManager {
     func bleConnected(){
         JoyGemAIManager.shared().bleConnected()
     }
+    func bleDisConnected(){
+        JoyGemAIManager.shared().bleDisConnected()
+    }
     func receiveValue(_ characteristic:CBCharacteristic){
         JoyGemAIManager.shared().receiveValue(characteristic)
     }
@@ -205,7 +207,7 @@ extension JoySdkManager : JoyGemAIManagerDataSource {
 
 
 extension JoySdkManager{
-   static func getMac(_ dict:[String:Any])->String?{
+    static func getMac(_ dict:[String:Any])->String?{
         if let advMsd = dict[CBAdvertisementDataManufacturerDataKey] as? Data {
             if (advMsd.count >= 13) {
                 let mac = advMsd[7...12];
index 4f5a36e..5ca0a88 100644 (file)
@@ -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())
index 792eb34..748c887 100644 (file)
@@ -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