骨传导调试
authorliangzhenying <867174124@qq.com>
Mon, 15 Dec 2025 09:14:44 +0000 (17:14 +0800)
committerliangzhenying <867174124@qq.com>
Mon, 15 Dec 2025 09:14:44 +0000 (17:14 +0800)
23 files changed:
DeepChordsSdk_iOS/DeepChordsSdk/Example/DeepChordsSdk/DCBleRecord.swift [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/DeepChordsSdk/DCChat.swift [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/DeepChordsSdk/DCRecord.swift [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example.xcodeproj/project.pbxproj
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/Info.plist
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BaseVC.swift
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BleSdkBleChatVC.swift [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BleSdkEarPhonesAsrVC.swift [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BleSdkPhoneAsrVC.swift [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/ChatManager.swift [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/Demo.h [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/Demo.m [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/DeviceListVC.swift
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/Example-Bridging-Header.h [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/HomeVC.swift
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/LogVC.swift
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/PcmSound.h [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/PlayerManager.swift [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/SceneDelegate.swift
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/SdkLogVC.swift
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/SelectLanuageVC.swift [new file with mode: 0644]
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/BleManager.swift
ShenYin/ShenYin/Api/LogManager.swift

diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/DeepChordsSdk/DCBleRecord.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/DeepChordsSdk/DCBleRecord.swift
new file mode 100644 (file)
index 0000000..b54d987
--- /dev/null
@@ -0,0 +1,57 @@
+//
+//  DCBleRecord.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/9.
+//
+
+import StarburstSdk
+
+public class DCBleRecord {
+    public static let shared = DCBleRecord()
+    
+    
+    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
+            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)")
+                textCallback(text)
+            }
+            
+        } 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("文件录音保存失败")
+            }
+        }
+    }
+    
+
+    public func startAction(){
+        let config = StarburstBleAsrConfig()
+        config.type = 0x0c/// 0x00实时录音,0x0c通话录音
+        //开始录音
+        StarburstSdk.shared().startDeviceRecord(config)
+        
+    }
+    public func stopAction(){
+        StarburstSdk.shared().stopDeviceRecord()
+    }
+}
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/DeepChordsSdk/DCChat.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/DeepChordsSdk/DCChat.swift
new file mode 100644 (file)
index 0000000..896baa4
--- /dev/null
@@ -0,0 +1,79 @@
+//
+//  DCChat.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/15.
+//
+
+import StarburstSdk
+
+public class DCChat{
+    public static let shared = DCChat()
+    var speakerList = [StarbusrtSpeaker]()
+    public var dialogId = 0
+    
+    public func getVcSpeekerList(finished:@escaping (Any,Bool)->Void){
+        StarburstSdk.shared().getVcSpeekerList { [weak self] (list, success) in
+            guard let self = self else { return }
+            finished(list,success)
+        }
+    }
+    
+    public func setup(asrCallback:@escaping (String)->Void,responseCallback:@escaping (String)->Void,dataCallback:@escaping (Int,Data?,Bool)->Void,codeCallback:@escaping (Int)->Void){
+        let config = StarburstVoiceChatConfig()
+        config.tts = true
+        config.ttsAudioFormat = "mp3"
+        //以下配置从音色列表获取
+        if speakerList.count > 0 {
+            //            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
+        }
+        
+        StarburstSdk.shared().setupVoiceChat(with: config) { dialogId in
+            print("开始对话 = \(dialogId)")
+        } textCallback: {[weak self] model in
+            guard let model = model else { return }
+            self?.dialogId = model.dialogId
+
+            if let textResult = model.textResult,textResult.count > 0 {
+                let text = "[send]" + model.textResult + "\n"
+                DCLogger.debug(text)
+                asrCallback(model.textResult)
+            } else if model.conversationFinish == true && model.responseText != nil
+                        && model.responseText!.count > 0
+            {
+                let text = "[send]" + model.responseText + "\n"
+                DCLogger.debug(text)
+                responseCallback(model.responseText)
+            } else {
+                return
+            }
+            
+        } responseVoice: { [weak self] (dialogId,data, finish) in
+            guard let self = self else { return }
+            self.dialogId = dialogId
+            dataCallback(dialogId,data,finish)
+        } stateChange: {code in
+            DCLogger.debug("状态改变 \(code)")
+            codeCallback(code.rawValue)
+        } finished: { filePath in
+            DCLogger.debug("结束对话")
+        }
+    }
+    public func startChat(){
+        
+    }
+    public func stopChat(){
+        StarburstSdk.shared().stopVoiceChat(self.dialogId)
+    }
+    public func startPlayTtsAudio(){
+        StarburstSdk.shared().startPlayTtsAudio(self.dialogId)
+    }
+    public func stopPlayTtsAudio(){
+        StarburstSdk.shared().stopPlayTtsAudio(self.dialogId)
+    }
+}
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/DeepChordsSdk/DCRecord.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/DeepChordsSdk/DCRecord.swift
new file mode 100644 (file)
index 0000000..868d90b
--- /dev/null
@@ -0,0 +1,64 @@
+//
+//  DC.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/9.
+//
+import StarburstSdk
+
+public class DCRecord {
+    public static let shared = DCRecord()    
+    
+    public func start(fromLanguage:String,toLanguage:String,textCallback:@escaping (String)->Void){
+        let config = StarburstAsrConfig()
+//        config.isTranslate = true;
+//        config.fromLanguage = fromLanguage
+//        config.toLanguage = toLanguage
+//        config.isTTs = true
+//        config.ttsFormat = "mp3"
+        
+        StarburstSdk.shared().startRecordAsr(config) {voiceData in
+            //print("录音的音频流 = \(voiceData!)")
+        } recognizeText: {[weak self] model in
+            DCLogger.debug(model)
+            guard let model = model else {return}
+            if let text = model.textResult ,model.definite{
+                DCLogger.debug("确定  text = \(text)")
+                textCallback(text)
+            }
+//            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
+//            }
+        } interruption: { [weak self]  in
+//            self?.stopAction()
+            
+        }
+    }
+    public func stop(){
+        StarburstSdk.shared().stopRecordAsr {filePath in
+            DCLogger.debug("文件录音保存路径 \(filePath)")
+        }
+
+    }
+}
index 5055fcd..3e37ec9 100644 (file)
                                TargetAttributes = {
                                        3F3F01E22ED451920038A1C8 = {
                                                CreatedOnToolsVersion = 16.4;
+                                               LastSwiftMigration = 1640;
                                        };
                                        3F3F13E22ED5A8C10038A1C8 = {
                                                CreatedOnToolsVersion = 16.4;
                        buildSettings = {
                                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                                ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+                               CLANG_ENABLE_MODULES = YES;
                                CODE_SIGN_STYLE = Automatic;
                                CURRENT_PROJECT_VERSION = 1;
                                DEVELOPMENT_TEAM = G23X75CJ67;
                                PRODUCT_BUNDLE_IDENTIFIER = deepchords.guchuandao.Example;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SWIFT_EMIT_LOC_STRINGS = YES;
+                               SWIFT_OBJC_BRIDGING_HEADER = "Example/VC/Example-Bridging-Header.h";
+                               SWIFT_OPTIMIZATION_LEVEL = "-Onone";
                                SWIFT_VERSION = 5.0;
                                TARGETED_DEVICE_FAMILY = "1,2";
                        };
                        buildSettings = {
                                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                                ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+                               CLANG_ENABLE_MODULES = YES;
                                CODE_SIGN_STYLE = Automatic;
                                CURRENT_PROJECT_VERSION = 1;
                                DEVELOPMENT_TEAM = G23X75CJ67;
                                PRODUCT_BUNDLE_IDENTIFIER = deepchords.guchuandao.Example;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SWIFT_EMIT_LOC_STRINGS = YES;
+                               SWIFT_OBJC_BRIDGING_HEADER = "Example/VC/Example-Bridging-Header.h";
                                SWIFT_VERSION = 5.0;
                                TARGETED_DEVICE_FAMILY = "1,2";
                        };
index 87b8afa..b571c8d 100644 (file)
@@ -28,5 +28,7 @@
        </dict>
        <key>CFBundleDisplayName</key>
        <string>骨传导sdk</string>
+       <key>NSMicrophoneUsageDescription</key>
+       <string>使用麦克风哦</string>
 </dict>
 </plist>
index ec48eee..e37c695 100644 (file)
@@ -21,7 +21,7 @@ class BaseVC: UIViewController {
         logBtn.backgroundColor = .blue
         logBtn.layer.cornerRadius = 30
         logBtn.layer.masksToBounds = true
-        logBtn.setTitle("log1", for: .normal)
+        logBtn.setTitle("app log", for: .normal)
         logBtn.addTarget(self, action: #selector(logAction), for: .touchUpInside)
         self.view.addSubview(logBtn)
         
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BleSdkBleChatVC.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BleSdkBleChatVC.swift
new file mode 100644 (file)
index 0000000..6aadc88
--- /dev/null
@@ -0,0 +1,76 @@
+//
+//  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()
+    }
+    
+
+
+}
+
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BleSdkEarPhonesAsrVC.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BleSdkEarPhonesAsrVC.swift
new file mode 100644 (file)
index 0000000..162cb9c
--- /dev/null
@@ -0,0 +1,84 @@
+//
+//  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 = ""
+        }
+    }
+}
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BleSdkPhoneAsrVC.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/BleSdkPhoneAsrVC.swift
new file mode 100644 (file)
index 0000000..de577c7
--- /dev/null
@@ -0,0 +1,173 @@
+//
+//  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)
+    }
+}
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/ChatManager.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/ChatManager.swift
new file mode 100644 (file)
index 0000000..0359daf
--- /dev/null
@@ -0,0 +1,112 @@
+//
+//  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()
+        }
+    }
+}
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/Demo.h b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/Demo.h
new file mode 100644 (file)
index 0000000..00760aa
--- /dev/null
@@ -0,0 +1,16 @@
+//
+//  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
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/Demo.m b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/Demo.m
new file mode 100644 (file)
index 0000000..9d53b65
--- /dev/null
@@ -0,0 +1,12 @@
+//
+//  Demo.m
+//  Example
+//
+//  Created by liangshi on 2025/12/15.
+//
+
+#import "Demo.h"
+
+@implementation Demo
+
+@end
index 8cc78b1..34efe20 100644 (file)
@@ -8,6 +8,7 @@
 import UIKit
 import SnapKit
 import CoreBluetooth
+import DeepChordsSdk
 class DeviceListVC: BaseVC{
     let tableView = UITableView(frame: .zero, style: .plain)
     var list:[CBPeripheral] = [ ]
@@ -18,6 +19,7 @@ class DeviceListVC: BaseVC{
         
         setupViews()
         setupBle()
+        setupSdk()
     }
     
     func setupViews(){
@@ -39,6 +41,20 @@ class DeviceListVC: BaseVC{
             self?.navigationController?.popViewController(animated: true)
         }
     }
+    func setupSdk(){
+        DeepChordsAiSdk.shared.authCallback = { [weak self] (code,string) in
+            DCLogger.debug("鉴权结果",code,string)
+            App.shared.window?.hideToastActivity()
+            if code == 200{
+                
+                App.shared.window?.makeToast("鉴权成功")
+                App.shared.window?.rootViewController = UINavigationController(rootViewController: HomeVC())
+            }
+            else{
+                App.shared.window?.makeToast(string)
+            }
+        }
+    }
 }
 
 extension DeviceListVC:UITableViewDelegate,UITableViewDataSource {
@@ -56,8 +72,9 @@ extension DeviceListVC:UITableViewDelegate,UITableViewDataSource {
         return cell
     }
     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        App.shared.window?.makeToastActivity(.center)
         let data = list[indexPath.row]
-        didSelectedCallback?(data)
-        BleManager.shared.stopScanDevice()
+        BleManager.shared.connectPeripheral(data)
+//        App.shared.window?.rootViewController = UINavigationController(rootViewController: HomeVC())
     }
 }
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/Example-Bridging-Header.h b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/Example-Bridging-Header.h
new file mode 100644 (file)
index 0000000..2ffc88b
--- /dev/null
@@ -0,0 +1,5 @@
+//
+//  Use this file to import your target's public headers that you would like to expose to Swift.
+//
+
+#import "PcmSound.h"
index 6daa043..e4ac6bc 100644 (file)
@@ -15,6 +15,9 @@ class HomeVC: BaseVC{
         ("获取电量","batteryAction"),
         ("获取软件版本","softVersionAction"),
         ("获取硬件版本","hardVersionAction"),
+        ("现场录音","recordAction"),
+        ("耳机录音","bleAsrAction"),
+        ("对话","chatAction"),
     ]
 
     override func viewDidLoad() {
@@ -22,15 +25,19 @@ class HomeVC: BaseVC{
         // Do any additional setup after loading the view.
         
         setupViews()
-        setupSdk()
         setupBle()
+        
+        DispatchQueue.main.asyncAfter(deadline:.now() + 2) {
+            ChatManager.shared.setupSdk()
+        }
+
     }
     
     func setupViews(){
         self.title = "设备鉴权+设备采集音频"
-        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "扫描", style: .done, target: self, action: #selector(scanAction))
+//        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "扫描", style: .done, target: self, action: #selector(scanAction))
         
-        let tableView = UITableView(frame: CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height), style: .plain)
+        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")
@@ -84,21 +91,19 @@ extension HomeVC{
             }
         }
     }
+    
+    @objc func recordAction(){
+        self.navigationController?.pushViewController(BleSdkPhoneAsrVC(), animated: true)
+    }
+    @objc func bleAsrAction(){
+        navigationController?.pushViewController(BleSdkEarPhonesAsrVC(), animated: true)
+    }
+    @objc func chatAction(){
+        navigationController?.pushViewController(BleSdkBleChatVC(), animated: true)
+    }
 }
 
 extension HomeVC{
-    func setupSdk(){
-        DeepChordsAiSdk.shared.authCallback = { [weak self] (code,string) in
-            DCLogger.debug("鉴权结果",code,string)
-            if code == 200{
-               
-                App.shared.window?.makeToast("鉴权成功")
-            }
-            else{
-                App.shared.window?.makeToast(string)
-            }
-        }
-    }
     func setupBle(){
         let shared = BleManager.shared
         shared.autoConnect()
@@ -110,13 +115,14 @@ extension HomeVC{
             //蓝牙已经断开
         }
     }
+
     
-    @objc func scanAction(){
-        let scanVC = DeviceListVC()
-        navigationController?.pushViewController(scanVC, animated: true)
-        scanVC.list = BleManager.shared.devices
-        scanVC.didSelectedCallback = { device in
-            BleManager.shared.connectPeripheral(device)
-        }
-    }
+//    @objc func scanAction(){
+//        let scanVC = DeviceListVC()
+//        navigationController?.pushViewController(scanVC, animated: true)
+//        scanVC.list = BleManager.shared.devices
+//        scanVC.didSelectedCallback = { device in
+//            BleManager.shared.connectPeripheral(device)
+//        }
+//    }
 }
index ede1643..7b687b6 100644 (file)
@@ -22,8 +22,9 @@ class LogVC: UIViewController {
     
     override func viewDidAppear(_ animated: Bool) {
         super.viewDidAppear(animated)
-        
-        textView.text = DCLogger.logs.joined()
+//        var version = (Bundle.main.appVersion ?? "") + "\n"
+        let version = "2025151001" + "\n"
+        textView.text =  "版本:\(version)" +  DCLogger.logs.joined()
         let range = NSMakeRange(textView.text.count - 1, 1)
         textView.scrollRangeToVisible(range)
     }
@@ -38,7 +39,7 @@ class LogVC: UIViewController {
             return
         }
         // 构建压缩文件路径
-        let filePath = cacheDirectory.appendingPathComponent("DeepChordsSdk_\(name).txt").path
+        let filePath = cacheDirectory.appendingPathComponent("DeepChords_\(name).txt").path
         
         let url = URL(fileURLWithPath: filePath)
         let data = self.textView.text.data(using:.utf8)
@@ -69,3 +70,12 @@ extension LogVC:UIDocumentPickerDelegate{
         controller.dismiss(animated: true, completion: nil)
     }
 }
+extension Bundle {
+    var appVersion: String? {
+        return infoDictionary?["CFBundleShortVersionString"] as? String
+    }
+    
+    var appBuild: String? {
+        return infoDictionary?["CFBundleVersion"] as? String
+    }
+}
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/PcmSound.h b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/PcmSound.h
new file mode 100644 (file)
index 0000000..b599bea
--- /dev/null
@@ -0,0 +1,33 @@
+
+
+#import <Foundation/Foundation.h>
+
+#define NAMESPACE @"pcm_sound"
+
+@protocol PcmSoundDelegate <NSObject>
+
+-(void)remaining:(NSUInteger)frames;
+
+@end
+
+@interface PcmSound : NSObject
+
++ (PcmSound*)sharedInstance;
+
+@property(nonatomic,weak) id<PcmSoundDelegate> delegate;
+
+-(BOOL)isPlaying;
+
+-(void)setLogLevel:(NSNumber*)logLevelNumber;
+
+-(void)setup:(int)sampleRate withchannels:(int)numChannels;
+
+-(void)feed:(NSData*)buffer;
+
+-(void)setFeedThreshold:(NSNumber*)feedThreshold;
+
+-(void)stopAudioUnit;
+
+- (void)cleanup;
+
+@end
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/PlayerManager.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/PlayerManager.swift
new file mode 100644 (file)
index 0000000..2e5361d
--- /dev/null
@@ -0,0 +1,59 @@
+//
+//  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 321585c..4922e1a 100644 (file)
@@ -18,7 +18,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
         // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
         guard let _ = (scene as? UIWindowScene) else { return }
         App.shared.window = window
-        window?.rootViewController = UINavigationController(rootViewController: HomeVC())
+        window?.rootViewController = UINavigationController(rootViewController: DeviceListVC())
         DeepChordsAiSdk.shared.initSDK()
     }
 
index da29f19..373b67b 100644 (file)
@@ -33,7 +33,7 @@ class SdkLogVC: UIViewController {
         formatter.dateFormat = "yyyyMMddHHmmss"
         let name = formatter.string(from: Date())
         
-        let filePath = "\(NSHomeDirectory())/Documents/DeepChordsSdk_\(name).txt"
+        let filePath = "\(NSHomeDirectory())/Documents/StarburstSdk_\(name).txt"
         let url = URL(fileURLWithPath: filePath)
         let data = self.textView.text.data(using:.utf8)
         do {
@@ -46,15 +46,15 @@ class SdkLogVC: UIViewController {
     }
     
     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)
-        
-//        let vc = UIActivityViewController(activityItems: [URL(fileURLWithPath: filePath)], applicationActivities: nil)
+//        let fUrl = URL(fileURLWithPath: filePath)
+//        let vc = UIDocumentPickerViewController(url: fUrl, in:.exportToService)
+//        vc.delegate = self
 //        vc.modalPresentationStyle = .overFullScreen
-//        App.shared.topVC().present(vc, animated: true)
+//        self.present(vc, animated: true, completion: nil)
+        
+        let vc = UIActivityViewController(activityItems: [URL(fileURLWithPath: filePath)], applicationActivities: nil)
+        vc.modalPresentationStyle = .overFullScreen
+        App.shared.topVC().present(vc, animated: true)
     }
 }
 
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/SelectLanuageVC.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/SelectLanuageVC.swift
new file mode 100644 (file)
index 0000000..3f821a3
--- /dev/null
@@ -0,0 +1,65 @@
+//
+//  Untitled.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/9.
+//
+
+import UIKit
+import StarburstSdk
+import Toast_Swift
+
+class SelectLanuageVC: BaseVC {
+    private var tableView: UITableView!
+    private var list:[(name: String,value:String)] = [
+        ("简体中文" ,"zh-CN"),
+        ("四川话", "sc"),
+        ("粤语", "cant"),
+        ("上海话" ,"zh_shanghai"),
+        ("英文",  "en-US"),
+        ("日语", "ja-JP"),
+        ("韩语", "ko-KR"),
+        ("法语", "fr-FR"),
+        ("西班牙语" ,"es-MX"),
+        ("葡萄牙语", "pt-BR"),
+        ("印尼语" ,"id-ID"),
+        ("俄语","ru-RU"),
+        ("马来语", "ms-MY"),
+    ]
+    var didSelectedCallback: ((String,String) -> 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()
+        }
+    }
+}
+extension SelectLanuageVC: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) {
+        view.makeToastActivity(.center)
+        let model = list[indexPath.row]
+        didSelectedCallback?(model.name,model.value)
+        self.navigationController?.popViewController(animated: true)
+        
+    }
+}
index 508e6c7..0fcd128 100644 (file)
@@ -52,9 +52,9 @@ class BleManager: NSObject {
         centralManager.connect(peripheral, options: [CBConnectPeripheralOptionNotifyOnConnectionKey: true])
     }
     func autoConnect(){
-        if let peripheral = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: "AE30")]).first{
-            connectPeripheral(peripheral)
-        }
+//        if let peripheral = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: "AE30")]).first{
+//            connectPeripheral(peripheral)
+//        }
     }
 }
 extension BleManager:CBCentralManagerDelegate{
@@ -108,6 +108,7 @@ extension BleManager:CBCentralManagerDelegate{
         disConnectDeviceCallback?(peripheral)
         DCBleManager.shared.centralManager(central, didDisconnectPeripheral: peripheral, error: nil)
         App.shared.window?.makeToast("蓝牙已断开连接")
+        App.shared.window?.rootViewController = UINavigationController(rootViewController: DeviceListVC())
     }
 }
 
index f61e054..8735333 100644 (file)
@@ -9,7 +9,7 @@ import Foundation
 
 /// 日记管理
 class Logger {
-    static var isDebug: Bool = false
+    static var isDebug: Bool = true
     
     fileprivate static let shared = Logger()
     private var fileHandle:FileHandle?