获取设备信息改用新指令
authorliangzhenying <867174124@qq.com>
Wed, 4 Dec 2024 09:16:47 +0000 (17:16 +0800)
committerliangzhenying <867174124@qq.com>
Wed, 4 Dec 2024 09:16:47 +0000 (17:16 +0800)
16 files changed:
MixSdk/Example/Example/BleChatVC.swift
MixSdk/Example/Example/BluetoothManager.swift
MixSdk/Example/Example/ViewController.swift
MixSdk/MixSdk/MixSdk.xcodeproj/project.pbxproj
MixSdk/MixSdk/MixSdk/MSCompress.swift [deleted file]
MixSdk/MixSdk/MixSdk/MSVoiceChatSdk.swift
MixSdk/MixSdk/MixSdk/Tools/MSTool.swift
MixSdk/MixSdk/MixSdk/auth/MSAuth.swift [moved from MixSdk/MixSdk/MixSdk/MSAuth.swift with 98% similarity]
MixSdk/MixSdk/MixSdk/auth/MSAuthModel.swift [moved from MixSdk/MixSdk/MixSdk/MSAuthModel.swift with 100% similarity]
MixSdk/MixSdk/MixSdk/ble/MSBle.swift [moved from MixSdk/MixSdk/MixSdk/MSBle.swift with 65% similarity]
MixSdk/MixSdk/MixSdk/ble/MSBleInfo.swift [moved from MixSdk/MixSdk/MixSdk/MSBleInfo.swift with 100% similarity]
MixSdk/MixSdk/MixSdk/ble/MSBleManager.swift [new file with mode: 0644]
MixSdk/MixSdk/MixSdk/ble/MSBleSender.swift [moved from MixSdk/MixSdk/MixSdk/MSBleSender.swift with 100% similarity]
MixSdk/MixSdk/MixSdk/ble/NSBleManager.swift [new file with mode: 0644]
MixSdk/MixSdk/MixSdk/chat/MSVoiceChat.swift [moved from MixSdk/MixSdk/MixSdk/MSVoiceChat.swift with 100% similarity]
MixSdk/MixSdk/MixSdk/chat/MSVoiceChatModel.swift [moved from MixSdk/MixSdk/MixSdk/MSVoiceChatModel.swift with 100% similarity]

index 5a7bc5d..69c375d 100644 (file)
@@ -61,7 +61,7 @@ class BleChatVC: UIViewController{
     }
 
     func setupVoiceChat(){
-        MSVoiceChatSdk.shared.ble.authCallBack = {[unowned self] in
+        MSVoiceChatSdk.shared.auth.authCallBack = {[unowned self] in
             self.view.makeToast("鉴权成功!" )
         }
         MSVoiceChatSdk.shared.voiceChat.start()
index cb78a82..4fccdab 100644 (file)
@@ -9,10 +9,9 @@ import Foundation
 import CoreBluetooth
 import MSVoiceChatSdk
 
-/// 主服务
-let kserviceUUID: String = "FFF1"
-let kVoiceUUID: String = "0783B03E-8535-B5A0-7140-A304D2194CB8"
-let kDeviceInfoUUID: String = "0783B63E-8535-B5A0-7140-A304D2495CB6"
+let kserviceUUID: String = "FE01"
+let kWriteUUID: String = "0xFF01"
+let kNotifyUUID: String = "FF02"
 
 public typealias IBDiscoverHandler = (_ peripheral: CBPeripheral) -> Void
 public typealias IBDidConectedHandler = (_ peripheral: CBPeripheral) -> Void
@@ -21,8 +20,7 @@ public typealias IBDisConectedHandler = (_ peripheral: CBPeripheral) -> Void
 class BluetoothManager: NSObject {
     static let shared = BluetoothManager()
 
-    /// 2AE6
-    private var writeFileCharacteristic: CBCharacteristic!
+    private var writeCharacteristic: CBCharacteristic!
     /// 中央管理类,管理蓝牙的扫描连接
     var centralManager: CBCentralManager!
     /// 当前连接设备
@@ -34,23 +32,12 @@ class BluetoothManager: NSObject {
     var didConnectedCallBack:IBDidConectedHandler?
     /// 设备断开连接
     var disConnectedCallBack:IBDisConectedHandler?
+    /// 收到数据
+    var didReceiveDataCallback: ((Data) -> Void)?
     
     private override init() {
         super.init()
         centralManager = CBCentralManager(delegate: self, queue: nil)
-        setupFileSdk()
-    }
-
-    func setupFileSdk(){
-        //初始化
-        MSVoiceChatSdk.shared.initSDK()
-        //isDebug为true则打印日志,false则不打印日志
-        MSVoiceChatSdk.shared.isDebug = true
-        //设置sdk数据回调
-        MSVoiceChatSdk.shared.ble.sdkToDeviceCallback = {[unowned self] data in
-            //这里将回调的数据发给蓝牙设备
-            self.send(data)
-        }
     }
 }
 
@@ -59,7 +46,7 @@ extension BluetoothManager{
     func startScan() {
         print("开始扫描...")
         centralManager.scanForPeripherals(withServices: nil)
-//        centralManager.scanForPeripherals(withServices: [CBUUID(string: kserviceUUID)], options: nil)
+        //        centralManager.scanForPeripherals(withServices: [CBUUID(string: kserviceUUID)], options: nil)
         if let peripheral = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kserviceUUID)]).first{
             discoverCallBack?(peripheral)
         }
@@ -88,7 +75,7 @@ extension BluetoothManager{
             print("手机未连上蓝牙设备!")
             return
         }
-        peripheral.writeValue(data, for: writeFileCharacteristic, type: .withoutResponse)
+        peripheral.writeValue(data, for: writeCharacteristic, type: .withoutResponse)
     }
 }
 
@@ -112,9 +99,8 @@ extension BluetoothManager: CBCentralManagerDelegate {
             break
         }
     }
-
+    
     func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
-//        IBManager.discoverHandler?(device)
         discoverCallBack?(peripheral)
     }
     
@@ -139,43 +125,33 @@ extension BluetoothManager: CBCentralManagerDelegate {
 
 extension BluetoothManager: CBPeripheralDelegate {
     func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
-       peripheral
-            .services?
-            .forEach {
-                peripheral.discoverCharacteristics(nil, for: $0)
-            }
+        peripheral.services?.forEach {
+            peripheral.discoverCharacteristics(nil, for: $0)
+        }
     }
     func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
-        service
-            .characteristics?
-            .forEach {
-                if $0.uuid.uuidString == kVoiceUUID {
-                    peripheral.setNotifyValue(true, for: $0)
-                    return
-                }
-                if $0.uuid.uuidString == kDeviceInfoUUID {
-                    writeFileCharacteristic = $0
-                    peripheral.setNotifyValue(true, for: $0)
-                    return
-                }
+        service.characteristics?.forEach {
+            if $0.uuid.uuidString == kNotifyUUID {
+                peripheral.setNotifyValue(true, for: $0)
+                return
+            }
+            if $0.uuid.uuidString == kWriteUUID {
+                writeCharacteristic = $0
+                return
             }
+        }
     }
     func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
         peripheral.readValue(for: characteristic)
     }
     
     func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
-        // 收到蓝牙设备的数据,转发给sdk处理
-        if characteristic.uuid.uuidString == kVoiceUUID {
-            MSVoiceChatSdk.shared.ble.sendToSdk(voiceData: characteristic.value)
-        }
-        else if characteristic.uuid.uuidString == kDeviceInfoUUID{
-            MSVoiceChatSdk.shared.ble.sendToSdk(infoData: characteristic.value)
+        if let data = characteristic.value{
+            didReceiveDataCallback?(data)
         }
     }
     
     func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
-        // sdk将回调的数据传给ble设备后,告知sdk写入的情况
-//        MSVoiceChatSdk.shared.ble.didWriteToDevice(characteristic: characteristic, error: error)
+
     }
 }
index 7baba3d..5ff0561 100644 (file)
@@ -10,6 +10,8 @@ import MSVoiceChatSdk
 
 class ViewController: UIViewController {
     
+
+    
     let tableView = UITableView(frame:.zero, style: .plain)
     var dataArray = [CBPeripheral]()
         
@@ -18,6 +20,7 @@ class ViewController: UIViewController {
         title = "扫描"
         setupViews()
         setupBle()
+        setupVoiceChatSdk()
     }
     
     override func viewDidAppear(_ animated: Bool) {
@@ -48,6 +51,18 @@ class ViewController: UIViewController {
         }
     }
     
+    func setupVoiceChatSdk(){
+        //初始化
+        MSVoiceChatSdk.shared.initSDK()
+        //isDebug为true则打印日志,false则不打印日志
+        MSVoiceChatSdk.shared.isDebug = true
+        //设置sdk数据回调
+        MSVoiceChatSdk.shared.ble.sdkToDeviceCallback = {data in
+            //这里将回调的数据发给蓝牙设备
+            BluetoothManager.shared.send(data)
+        }
+    }
+    
     func setupBle() {
         BluetoothManager.shared.discoverCallBack = { [unowned self] peripheral in
             if dataArray.contains(peripheral){
@@ -63,12 +78,18 @@ class ViewController: UIViewController {
         BluetoothManager.shared.didConnectedCallBack = {[unowned self] peripheral in
             self.view.hideToastActivity()
 //            let vc = PhoneChatVC()
-            let vc = BleChatVC()
-            self.navigationController?.pushViewController(vc, animated: true)
+//            let vc = BleChatVC()
+//            self.navigationController?.pushViewController(vc, animated: true)
+            MSVoiceChatSdk.shared.ble.didConnectBle()
         }
         BluetoothManager.shared.disConnectedCallBack = { [unowned self] peripheral in
             print("蓝牙已经断开!!!!!!!!!!!")
             self.view.makeToast("蓝牙已经断开!")
+            MSVoiceChatSdk.shared.ble.didDisconnectBle()
+        }
+        BluetoothManager.shared.didReceiveDataCallback = {data in
+            // 收到蓝牙设备的数据,转发给sdk处理
+            MSVoiceChatSdk.shared.ble.sendToSdk(data)
         }
     }
     
@@ -102,6 +123,11 @@ extension ViewController: UITableViewDelegate, UITableViewDataSource {
 }
 extension ViewController{
     @objc func registerAction() {
+//        let data = MSTool.hexStringToData("000000000000000000000000000064")
+//        let data = MSTool.hexStringToData("000000000000000000000000000141333832302d5635382d323032343132303431343038333432")
+//        let data = MSTool.hexStringToData("0000000000000000000000000002303045303831444335333141")
+//        let data = MSTool.hexStringToData("00000000000000000000000002000400003e80")
+//        MSVoiceChatSdk.shared.ble.sendToSdk(data)
         view.makeToastActivity(.center)
         MSVoiceChatSdk.shared.auth.register(productId: productId, productKey: productKey, deviceId: deviceId){[weak self] password,error in
             self?.view.hideToastActivity()
index 946b501..b01d804 100644 (file)
@@ -39,7 +39,6 @@
                18314AA32C3D37EE0028CE50 /* AudioTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = 18314A9F2C3D37ED0028CE50 /* AudioTransform.h */; };
                18314AA42C3D37EE0028CE50 /* AudioTransform.m in Sources */ = {isa = PBXBuildFile; fileRef = 18314AA02C3D37ED0028CE50 /* AudioTransform.m */; };
                186BFD492C57915500673D8C /* MSVoiceChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 186BFD482C57915500673D8C /* MSVoiceChat.swift */; };
-               187C54642C6B7C4B0022C3D4 /* MSCompress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 187C54632C6B7C4B0022C3D4 /* MSCompress.swift */; };
                188695A22C59DA5700B9B89F /* MSVoiceChatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 188695A12C59DA5700B9B89F /* MSVoiceChatModel.swift */; };
                18A2DCC92C40D94800A8731B /* AES.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A2DC4F2C40D94700A8731B /* AES.swift */; };
                18A2DCCA2C40D94800A8731B /* ASN1Scanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A2DC512C40D94700A8731B /* ASN1Scanner.swift */; };
                18AA04692CE444D40008A345 /* MSBleSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18AA04682CE444D40008A345 /* MSBleSender.swift */; };
                18AA046C2CE45E800008A345 /* MSBleInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18AA046B2CE45E800008A345 /* MSBleInfo.swift */; };
                18B1A38C2CE3547F00DD4A7C /* MSBle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B1A38B2CE3547F00DD4A7C /* MSBle.swift */; };
+               18C21AA42D0005AF00F718A7 /* MSBleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C21AA32D0005AF00F718A7 /* MSBleManager.swift */; };
+               18C21AA92D000C2700F718A7 /* NSBleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C21AA82D000C2700F718A7 /* NSBleManager.swift */; };
                18C42B4B2C23DA29000D8860 /* SbcToPcm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C42B4A2C23DA29000D8860 /* SbcToPcm.swift */; };
                18C42BE72C242202000D8860 /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C42B5E2C242202000D8860 /* version.h */; };
                18C42BE82C242202000D8860 /* buffersrc.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C42B5F2C242202000D8860 /* buffersrc.h */; };
                18314A9F2C3D37ED0028CE50 /* AudioTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioTransform.h; sourceTree = "<group>"; };
                18314AA02C3D37ED0028CE50 /* AudioTransform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioTransform.m; sourceTree = "<group>"; };
                186BFD482C57915500673D8C /* MSVoiceChat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSVoiceChat.swift; sourceTree = "<group>"; };
-               187C54632C6B7C4B0022C3D4 /* MSCompress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSCompress.swift; sourceTree = "<group>"; };
                188695A12C59DA5700B9B89F /* MSVoiceChatModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSVoiceChatModel.swift; sourceTree = "<group>"; };
                18A2DC4F2C40D94700A8731B /* AES.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AES.swift; sourceTree = "<group>"; };
                18A2DC512C40D94700A8731B /* ASN1Scanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1Scanner.swift; sourceTree = "<group>"; };
                18AA04682CE444D40008A345 /* MSBleSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSBleSender.swift; sourceTree = "<group>"; };
                18AA046B2CE45E800008A345 /* MSBleInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSBleInfo.swift; sourceTree = "<group>"; };
                18B1A38B2CE3547F00DD4A7C /* MSBle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSBle.swift; sourceTree = "<group>"; };
+               18C21AA32D0005AF00F718A7 /* MSBleManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSBleManager.swift; sourceTree = "<group>"; };
+               18C21AA82D000C2700F718A7 /* NSBleManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSBleManager.swift; sourceTree = "<group>"; };
                18C42B4A2C23DA29000D8860 /* SbcToPcm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SbcToPcm.swift; sourceTree = "<group>"; };
                18C42B5E2C242202000D8860 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
                18C42B5F2C242202000D8860 /* buffersrc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = buffersrc.h; sourceTree = "<group>"; };
                                18204BBE2C193E3D00F94E69 /* MSVoiceChatSdk.h */,
                                18C42C762C24241A000D8860 /* MSVoiceChatSdk-Bridging-Header.h */,
                                1811882E2C1A89E600C23FAB /* MSVoiceChatSdk.swift */,
-                               18B1A38B2CE3547F00DD4A7C /* MSBle.swift */,
-                               18AA046B2CE45E800008A345 /* MSBleInfo.swift */,
-                               18AA04682CE444D40008A345 /* MSBleSender.swift */,
-                               18204BC52C193E4B00F94E69 /* MSAuth.swift */,
-                               18314A882C3CD55E0028CE50 /* MSAuthModel.swift */,
-                               186BFD482C57915500673D8C /* MSVoiceChat.swift */,
-                               188695A12C59DA5700B9B89F /* MSVoiceChatModel.swift */,
                                18204BEF2C19457600F94E69 /* MSHttpManager.swift */,
                                181188442C1AC35F00C23FAB /* MSError.swift */,
-                               187C54632C6B7C4B0022C3D4 /* MSCompress.swift */,
+                               18C21AA52D000ADD00F718A7 /* ble */,
+                               18C21AA62D000AEE00F718A7 /* auth */,
+                               18C21AA72D000AFD00F718A7 /* chat */,
                        );
                        path = MixSdk;
                        sourceTree = "<group>";
                        path = CS_BigInt;
                        sourceTree = "<group>";
                };
+               18C21AA52D000ADD00F718A7 /* ble */ = {
+                       isa = PBXGroup;
+                       children = (
+                               18B1A38B2CE3547F00DD4A7C /* MSBle.swift */,
+                               18C21AA82D000C2700F718A7 /* NSBleManager.swift */,
+                               18C21AA32D0005AF00F718A7 /* MSBleManager.swift */,
+                               18AA046B2CE45E800008A345 /* MSBleInfo.swift */,
+                               18AA04682CE444D40008A345 /* MSBleSender.swift */,
+                       );
+                       path = ble;
+                       sourceTree = "<group>";
+               };
+               18C21AA62D000AEE00F718A7 /* auth */ = {
+                       isa = PBXGroup;
+                       children = (
+                               18204BC52C193E4B00F94E69 /* MSAuth.swift */,
+                               18314A882C3CD55E0028CE50 /* MSAuthModel.swift */,
+                       );
+                       path = auth;
+                       sourceTree = "<group>";
+               };
+               18C21AA72D000AFD00F718A7 /* chat */ = {
+                       isa = PBXGroup;
+                       children = (
+                               186BFD482C57915500673D8C /* MSVoiceChat.swift */,
+                               188695A12C59DA5700B9B89F /* MSVoiceChatModel.swift */,
+                       );
+                       path = chat;
+                       sourceTree = "<group>";
+               };
                18C42B5B2C242202000D8860 /* FFmpeg-iOS */ = {
                        isa = PBXGroup;
                        children = (
                                18A2DD1B2C40D94900A8731B /* CCM.swift in Sources */,
                                18A2DD2E2C40D94900A8731B /* PrimeTest.swift in Sources */,
                                18A2DCDF2C40D94800A8731B /* UInt16+Extension.swift in Sources */,
-                               187C54642C6B7C4B0022C3D4 /* MSCompress.swift in Sources */,
                                18A2DD162C40D94900A8731B /* BlockModeOptions.swift in Sources */,
                                18314A912C3D13A60028CE50 /* AudioConvert.m in Sources */,
                                18A2DCF42C40D94800A8731B /* UInt8+Extension.swift in Sources */,
                                18204BFB2C19488900F94E69 /* Upload.swift in Sources */,
                                18A2DD2B2C40D94900A8731B /* WordsAndBits.swift in Sources */,
                                18204BFA2C19488900F94E69 /* Request.swift in Sources */,
+                               18C21AA92D000C2700F718A7 /* NSBleManager.swift in Sources */,
                                18314A862C3CD24E0028CE50 /* MSUtils.m in Sources */,
                                1811882F2C1A89E600C23FAB /* MSVoiceChatSdk.swift in Sources */,
                                18A2DCD32C40D94800A8731B /* HKDF.swift in Sources */,
                                18A2DD1F2C40D94900A8731B /* CipherModeWorker.swift in Sources */,
                                18A2DD122C40D94900A8731B /* PKCS7.swift in Sources */,
                                18314AA42C3D37EE0028CE50 /* AudioTransform.m in Sources */,
+                               18C21AA42D0005AF00F718A7 /* MSBleManager.swift in Sources */,
                                18A2DCE42C40D94800A8731B /* UInt128.swift in Sources */,
                                18A2DD052C40D94800A8731B /* Updatable.swift in Sources */,
                                18A2DD182C40D94900A8731B /* CFB.swift in Sources */,
diff --git a/MixSdk/MixSdk/MixSdk/MSCompress.swift b/MixSdk/MixSdk/MixSdk/MSCompress.swift
deleted file mode 100644 (file)
index e868e10..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-////
-////  MSCompress.swift
-////  Example
-////
-////  Created by incar on 2024/8/13.
-////
-//
-//import UIKit
-//import SCompressLib
-//
-///// 压缩回调
-//public typealias MSCompressCallBack = (_ retData: [UInt8]) -> Void
-///// 解压回调
-//public typealias MSDeCompressCallBack = (_ image: UIImage?) -> Void
-//
-//public class MSCompress{
-//    fileprivate static var compressCallBack:MSCompressCallBack?
-//    fileprivate static var decompressCallBack:MSDeCompressCallBack?
-//    
-//    public static func compress(image:UIImage,finished: @escaping MSCompressCallBack){
-//        compressCallBack = finished
-//        
-//        print("start = ",Date().timeIntervalSince1970)
-//        let width = Int(image.size.width)
-//        let height = Int(image.size.height)
-//        print("width = \(width), height = \(height)")
-//        let pixelFormat = image.cgImage?.pixelFormatInfo
-//        print("pixelFormat = \(pixelFormat.debugDescription)")
-//        var sParam = SCompressParam()
-//        sParam.id = 15
-//        sParam.width = Int32(width)
-//        sParam.height = Int32(height)
-//        sParam.stride = Int32(width)
-//        sParam.modeRgb = 1
-//        sParam.modeAlpha = 1
-//        sParam.cmpMode = 0
-//        sParam.tileWidth = 4
-//        sParam.pixelFormat = 1
-//        
-//        let provider = image.cgImage!.dataProvider
-//        let providerData = provider!.data
-//        let data = CFDataGetBytePtr(providerData)
-//        
-//        for hei in  0...(height - 1) {
-//            for wid in 0...(width - 1) {
-//                let color = image[data!,providerData!,wid, hei]
-//                sParam.redChannel.append(color.r)
-//                sParam.greenChannel.append(color.g)
-//                sParam.blueChannel.append(color.b)
-//                sParam.alphaChannel.append(color.a)
-//            }
-//        }
-//        print("red channel len = \(sParam.redChannel.count)")
-//        let picApi = SPicZipApi()
-//        SetZipEvent(picEvent: MyZipRets())
-//        picApi.Compress(compressParam: sParam)
-//        print("end = ",Date().timeIntervalSince1970)
-//    }
-//
-//    public static func deCompress(data:Data,finished: @escaping MSDeCompressCallBack){
-//        decompressCallBack = finished
-//        print("start = ",Date().timeIntervalSince1970)
-//        let picApi = SPicZipApi()
-//        var compressedFile : [UInt8] = []
-//        for i in 0...data.count - 1 {
-//            compressedFile.append(data[i])
-//        }
-//        picApi.Decompress(id: 39, fileBuffer: compressedFile)
-//        print("end = ",Date().timeIntervalSince1970)
-//    }
-//    
-//}
-//
-//fileprivate func drawRect(decomRets: SCompressLib.SDecompressRets) ->CGImage?{
-//    let width  = decomRets.width
-//    let height = decomRets.height
-//    let boundingBox = CGRectMake(0, 0, CGFloat(width), CGFloat(height))
-//    let context = createBitmapContext(pixelsWide: Int(width), Int(height))
-//    let data = context!.data
-//    var pixelIdx = 0
-//    var chanIdx = 0
-//    for i in 0...height - 1 {
-//        for j in 0...width - 1 {
-//            chanIdx = Int(i * width + j)
-//            data?.storeBytes(of:decomRets.alphaChannel[chanIdx], toByteOffset: pixelIdx, as: UInt8.self)
-//            pixelIdx += 1
-//            data?.storeBytes(of:decomRets.redChannel[chanIdx], toByteOffset: pixelIdx, as: UInt8.self)
-//            pixelIdx += 1
-//            data?.storeBytes(of:decomRets.greenChannel[chanIdx], toByteOffset: pixelIdx, as: UInt8.self)
-//            pixelIdx += 1
-//            data?.storeBytes(of:decomRets.blueChannel[chanIdx], toByteOffset: pixelIdx, as: UInt8.self)
-//            pixelIdx += 1
-//        }
-//    }
-//    let decompressPic = context!.makeImage()
-//    return decompressPic
-//}
-//
-//fileprivate func createBitmapContext(pixelsWide: Int, _ pixelsHigh: Int) -> CGContext? {
-//    let bytesPerPixel = 4 // 生成包括ARGB四个通道的像素点,每个像素点需要4个字节
-//    let bytesPerRow = bytesPerPixel * pixelsWide
-//    let bitsPerComponent = 8
-//    let byteCount = (bytesPerRow * pixelsHigh)
-//    let colorSpace = CGColorSpaceCreateDeviceRGB()
-//    let pixels = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity:byteCount)
-//    let bitmapInfo = CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Big.rawValue
-//    let context = CGContext(data: pixels, width: pixelsWide, height: pixelsHigh, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)
-//    return context
-//}
-//
-//fileprivate struct MyZipRets : PicZipEvent {
-//    func DecompressRets(id: Int, state: Int, decomRets: SCompressLib.SDecompressRets) {
-//        let imageWidth = Int(decomRets.width)
-//        let imageHeight = Int(decomRets.height)
-//        var cgImg =  drawRect(decomRets: decomRets)
-//        var img = (cgImg != nil) ? UIImage(cgImage: cgImg!):nil
-//        MSCompress.decompressCallBack?(img)
-//        print("decompress finish id ====== \(id)")
-//    }
-//    
-//    func CompressRets(id: Int, state: Int, tileWidth: Int, retData: [UInt8]) {
-//        MSCompress.compressCallBack?(retData)
-//    }
-//}
-//
-//
-//fileprivate extension UIImage {
-//    subscript (data:UnsafePointer<UInt8>,providerData:CFData,x: Int, y: Int) -> (r : UInt8, g : UInt8, b : UInt8, a : UInt8) {
-//        if x < 0 || x > Int(size.width) || y < 0 || y > Int(size.height) {
-//            return (0, 0, 0, 0)
-//        }
-//        let numberOfComponents = 4
-//        let pixelData = ((Int(size.width) * y) + x) * numberOfComponents
-//        let r = UInt8(data[pixelData])
-//        let g = UInt8(data[pixelData + 1])
-//        let b = UInt8(data[pixelData + 2])
-//        let a = UInt8(data[pixelData + 3])
-//        return (r, g, b, a)
-//    }
-//}
index 9e1e6f1..defcfe6 100644 (file)
@@ -16,7 +16,6 @@ class MSConfig{
 //    static let authBaseURL = "http://dmp.raisound.com/bz-api/"
 //    static let wsHeartBeatTime = 5.0
     
-    
     static func authUrl(api:String)->String{
         return authBaseURL + api
      }
@@ -47,7 +46,7 @@ public class MSVoiceChatSdk:NSObject {
     public var logs: [String] { Logger.logs }
     
     /// SDK 版本号
-    public let version: String = "1.0.0"
+    public let version: String = "v2024120401"
     /// 默认为 false
     public var isDebug: Bool = false {
         didSet { Logger.isDebug = isDebug }
@@ -56,15 +55,12 @@ public class MSVoiceChatSdk:NSObject {
     /// 鉴权
     public let auth = MSAuth()
     
-    /// 蓝牙管理
+    /// 蓝牙
     public let ble = MSBle()
     
     /// 语音聊天
     public let voiceChat = MSVoiceChat()
 
-    func setupWebsoket(){
-    }
-    
     /// 清空日志
     public func cleanLog(){
         Logger.logs.removeAll()
index 995dba2..8fff7ff 100644 (file)
@@ -8,7 +8,7 @@
 import UIKit
 import CommonCrypto
 
-class MSTool{
+public class MSTool{
     static func dataToUtf8String(_ data:Data) ->String{
         let text = String(data: data, encoding: .utf8)
         return text ?? ""
@@ -97,4 +97,26 @@ class MSTool{
         }
         return output
     }
+    
+    public static func hexStringToData(_ hexStr: String) -> Data {
+        let hexStrWithoutSpaces = hexStr.replacingOccurrences(of: " ", with: "")
+        let lowercasedHexStr = hexStrWithoutSpaces.lowercased()
+        let len = lowercasedHexStr.count
+        if len == 0 {
+            return Data()
+        }
+
+        let utf16Chars = lowercasedHexStr.utf16
+
+        var result = Data()
+        var bytes: UInt8
+        var str = [CChar](repeating: 0, count: 3)
+        for i in 0..<len / 2 {
+            str[0] = CChar(utf16Chars[utf16Chars.index(utf16Chars.startIndex, offsetBy: 2 * i)])
+            str[1] = CChar(utf16Chars[utf16Chars.index(utf16Chars.startIndex, offsetBy: 2 * i + 1)])
+            bytes = UInt8(strtoul(str, nil, 16))
+            result.append(&bytes, count: 1)
+        }
+        return result
+    }
 }
similarity index 98%
rename from MixSdk/MixSdk/MixSdk/MSAuth.swift
rename to MixSdk/MixSdk/MixSdk/auth/MSAuth.swift
index cd39993..75b8d51 100644 (file)
@@ -16,6 +16,9 @@ public typealias MSLoginCallBack = (_ token: String?,_ error:MSError?) -> Void
 
 /// 鉴权管理类
 public class MSAuth {
+    /// 鉴权回调
+    public var authCallBack:(()->Void)?
+
     /// 是否已经鉴权
     public private(set) var authorized = false
     
@@ -117,7 +120,6 @@ public class MSAuth {
                     self.authorized = true
                     self.deviceToken = dataDict["token"] as? String ?? ""
                     
-                    MSVoiceChatSdk.shared.setupWebsoket()
                     completeHandler(self.deviceToken,nil)
                 }
                 else{
similarity index 65%
rename from MixSdk/MixSdk/MixSdk/MSBle.swift
rename to MixSdk/MixSdk/MixSdk/ble/MSBle.swift
index 23f19dc..15f45b4 100644 (file)
 //  Created by incar on 2024/11/12.
 //
 
-import Foundation
-
+//    0xFF01 写通讯特征值
+//    0xFF02 读/通知特征值
 
-
-/// SDK 管理类
+import Foundation
 public class MSBle {
-    public var authCallBack:(()->Void)?
-    public var didAuth:Bool{
-        return MSVoiceChatSdk.shared.auth.authorized
-    }//是否正在鉴权
-    
     var lastSender:MSBleSender?
     var deviceInfo:MSBleInfo?
     var isAuthing = false//是否正在鉴权
     
-    
     init() {
 
     }
-
-    /// sdk发送数据回调,app将此数据转发给蓝牙设备,写入设备成功后,需要调didWriteToDevice(characteristic:, error:)告知sdk是否写入成功
+    
+    /// 连上蓝牙设备后必须调此方法通知sdk
+    public func didConnectBle(){
+        Logger.log("蓝牙连接" )
+        startAuth()
+    }
+    /// 断开蓝牙设备后必须调此方法通知sdk
+    public func didDisconnectBle(){
+        Logger.log("蓝牙已断开" )
+    }
+    
+    /// sdk发送数据回调,app将此数据转发给蓝牙设备
     public var sdkToDeviceCallback:((_ data: Data) -> Void)?
     
     /// 收到蓝牙设备传过来的数据,转发给sdk处理
-    public func sendToSdk(voiceData data: Data?){
+    public func sendToSdk(_ data: Data?){
         guard let data = data else{
-            Logger.log("[recv][voice]")
             return
         }
-//        Logger.log("[recv][voice] \(data)")
-//        if self.didAuth == false{
-//            DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
-//                self.startAuth()
-//            }
-//            return
-//        }
-        if(data.count > 16){
-            MSAudioConvert.sbcTopcm(data){ pcm in
-                MSVoiceChatSdk.shared.voiceChat.sendVoice(pcmData: pcm)
-            }
+        Logger.log("[recv]" + data.joined(""))
+        
+        if data.count < 12{
+            Logger.log("接收到的蓝牙数据异常")
+            return
         }
+//        receive(data)
+        
+        //        if let sender = lastSender{
+        //            lastSender = nil
+        //            sender.completion?(.response.code(.success).value(data))
+        //            sender.remove()
+        //
+        //            deinitTimer()
+        //        }
     }
-    /// 收到蓝牙设备传过来的数据,转发给sdk处理
-    public func sendToSdk(infoData data: Data?){
-        guard let data = data else{
-            Logger.log("[recv][info]")
-            return
+}
+
+extension MSBle{
+    func receive(_ data:Data){
+        let payload = data.suffix(from: 12).map({ $0 })
+        let cmd = payload[0].int
+        let type = payload[1].int
+        Logger.log("cmd = \(cmd) type = \(type)")
+        switch cmd {
+        case 0x00:
+            Logger.log("获取设备信息")
+            receiveDeviceInfo(payload)
+        case 0x01:
+            Logger.log("设置设备数据")
+            receiveSetDeviceInfo(payload)
+        case 0x02:
+            Logger.log("AI语音对话")
+            receiveVoice(payload)
+        default:
+            Logger.log("未定义指令")
         }
-        Logger.log("[recv][info] " + data.joined("") + MSTool.dataToUtf8String(data))
-        if data.joined("") == "7b2272737369223a2230227d"{
-            return
+    }
+    func receiveDeviceInfo(_ list:[UInt8]){
+        let type = list[1].int
+        switch type {
+        case 0x00:
+            let value = list[2].int
+            Logger.log("电池电量 \(value)")
+            
+        case 0x01:
+            let value = String(data: Data(list.suffix(from: 2)), encoding: .utf8)  ?? ""
+            Logger.log("软件版本 \(value)")
+        case 0x02:
+            let value = String(data: Data(list.suffix(from: 2)), encoding: .utf8) ?? ""
+            Logger.log("MAC地址 \(value)")
+        case 0x03:
+            let value = String(data: Data(list.suffix(from: 2)), encoding: .utf8) ?? ""
+            Logger.log("产品密钥 \(value)")
+            
+        case 0x04:
+            let value = String(data: Data(list.suffix(from: 2)), encoding: .utf8) ?? ""
+            Logger.log("产品密码 \(value)")
+        case 0x05:
+            let value = String(data: Data(list.suffix(from: 2)), encoding: .utf8) ?? ""
+            Logger.log("设备密码 \(value)")
+        default:
+            Logger.log("未定义指令")
         }
-        if let sender = lastSender{
-            lastSender = nil
-            sender.completion?(.response.code(.success).value(data))
-            sender.remove()
+    }
+    func receiveSetDeviceInfo(_ list:[UInt8]){
+        let type = list[1].int
+        switch type {
+        case 0x00:
+            let value = list[2].int
+            Logger.log("密码设置 \(value)")
             
-            deinitTimer()
+        case 0x01:
+            let value = list[2].int
+            Logger.log("品牌名称设置 \(value)")
+        default:
+            Logger.log("未定义指令")
+        }
+    }
+    func receiveVoice(_ list:[UInt8]){
+        let type = list[1].int
+        switch type {
+        case 0x00:
+            let value = list[2].int
+            Logger.log("开始录音 \(value)")
+            
+        case 0x01:
+            let value = list[2].int
+            Logger.log("停止录音 \(value)")
+        case 0x02:
+            Logger.log("音频流 \(Data(list.suffix(from: 2)))")
+        default:
+            Logger.log("未定义指令")
         }
     }
-    /// sdk传给ble设备后,告知sdk写入的情况
-//    public func didWriteToDevice(characteristic: CBCharacteristic, error: Error?){
-//        print(characteristic.uuid.uuidString, "write success")
-//        if let error = error {
-//            print("发送失败 ",characteristic.uuid.uuidString,error.localizedDescription)
-//        }
-//        else{
-//            if characteristic.uuid.uuidString == writeFileCharacteristicUUID{
-//                IBBluetooth.shared.didWriteToDevice()
-//            }
-//        }
-//    }
 }
 
-
 extension MSBle{
     public func startAuth(){
         if isAuthing {
@@ -103,12 +156,6 @@ extension MSBle{
             
             self.startLogin {[weak self] token, error in
                 guard let self = self else {return}
-                if let _ = token {
-                    self.authCallBack?()
-                }
-                else{
-//                    self.authCallBack?(false)
-                }
                 isAuthing = false
             }
         }
@@ -156,7 +203,11 @@ extension MSBle{
     }
     
     func requestDeviceId(finished: @escaping (String?) -> Void){
-        let sender = dictionaryToSender(["cmd":"get_MAC"])
+        let cmd = [0.byte]
+        let type = [2.byte]
+        let data = Data(cmd + type)
+        let sender = MSBleSender()
+        sender.list.append(data)
         sender.completion = { result in
             Logger.log("\(result.description)")
             if result.isSuccess,let dict = MSTool.dataToJson(result.data) ,let value = dict["MAC"] as? String{
@@ -169,7 +220,11 @@ extension MSBle{
         sendToBle(sender)
     }
     func requestProductKey(finished: @escaping (String?) -> Void){
-        let sender = dictionaryToSender(["cmd":"get_productKey"])
+        let cmd = [0.byte]
+        let type = [3.byte]
+        let data = Data(cmd + type)
+        let sender = MSBleSender()
+        sender.list.append(data)
         sender.completion = { result in
             Logger.log("\(result.description)")
             if result.isSuccess,let dict = MSTool.dataToJson(result.data) ,let value = dict["productKey"] as? String{
@@ -182,7 +237,11 @@ extension MSBle{
         sendToBle(sender)
     }
     func requestSecretKey(finished: @escaping (String?) -> Void){
-        let sender = dictionaryToSender(["cmd":"get_secretKey"])
+        let cmd = [0.byte]
+        let type = [4.byte]
+        let data = Data(cmd + type)
+        let sender = MSBleSender()
+        sender.list.append(data)
         sender.completion = { result in
             Logger.log("\(result.description)")
             if result.isSuccess,let dict = MSTool.dataToJson(result.data) ,let value = dict["secretKey"] as? String{
@@ -195,7 +254,11 @@ extension MSBle{
         sendToBle(sender)
     }
     func requestDeviceSecret(finished: @escaping (String?) -> Void){
-        let sender = dictionaryToSender(["cmd":"get_deviceSecret"])
+        let cmd = [0.byte]
+        let type = [5.byte]
+        let data = Data(cmd + type)
+        let sender = MSBleSender()
+        sender.list.append(data)
         sender.completion = { result in
             Logger.log("\(result.description)")
             if result.isSuccess,let dict = MSTool.dataToJson(result.data) ,let value = dict["deviceSecret"] as? String{
@@ -224,7 +287,8 @@ extension MSBle{
         startTimer()
         for data in sender.list{
             if let sendToBleBlock = self.sdkToDeviceCallback {
-                sendToBleBlock(data)
+                Logger.log("[send]" + data.joined())
+//                sendToBleBlock(data)
             }
         }
     }
@@ -255,53 +319,6 @@ extension MSBle{
     }
 }
 
-
-extension MSBle{
-    func dictionaryToSender(_ dict: [String: Any]) ->MSBleSender{
-        let sender = MSBleSender()
-        let str = MSTool.dataToUtf8String(MSTool.jsonToData(dict)!)
-        let list = splitCMD(str: str)
-        Logger.log("[send][info][all][string] \(str)")
-        if list.count > 1 {
-            // 开始标志
-            sender.list.append(stringToData(cmd: "-$$\0"))
-            // 指令
-            for i in 0..<list.count {
-                sender.list.append(stringToData(cmd: "\(list[i])\0"))
-            }
-            // 结束标志
-            sender.list.append(stringToData(cmd: "$$-\0"))
-        } else {
-            let data = stringToData(cmd: "-$$\(str)$$-\n")
-            sender.list.append(data)
-        }
-        
-        return sender
-    }
-
-    func stringToData(cmd: String) ->Data{
-        let data = cmd.data(using:.utf8)!
-        return data
-    }
-
-    func splitCMD(str: String) -> [String] {
-        var list = [String]()
-        var str = str
-        let len = 30
-        while str.count > 0 {
-            if str.count > len {
-                let sub = String(str.prefix(len))
-                list.append(sub)
-                str = String(str.suffix(str.count - len))
-            } else {
-                list.append(str)
-                break
-            }
-        }
-        return list
-    }
-}
-
 extension MSBle{
     func registerAction(completeHandler: @escaping MSLoginCallBack) {
         MSVoiceChatSdk.shared.auth.register(productId: deviceInfo!.productId, productKey: deviceInfo!.productKey, deviceId: deviceInfo!.deviceId){[weak self] password,error in
diff --git a/MixSdk/MixSdk/MixSdk/ble/MSBleManager.swift b/MixSdk/MixSdk/MixSdk/ble/MSBleManager.swift
new file mode 100644 (file)
index 0000000..79754ad
--- /dev/null
@@ -0,0 +1,15 @@
+//
+//  MSBleManager.swift
+//  MSVoiceChatSdk
+//
+//  Created by incar on 2024/12/4.
+//
+
+import Foundation
+
+class MSBleManager{
+    
+    
+    
+    
+}
diff --git a/MixSdk/MixSdk/MixSdk/ble/NSBleManager.swift b/MixSdk/MixSdk/MixSdk/ble/NSBleManager.swift
new file mode 100644 (file)
index 0000000..02343c2
--- /dev/null
@@ -0,0 +1,324 @@
+////
+////  MSBle.swift
+////  MSVoiceChatSdk
+////
+////  Created by incar on 2024/11/12.
+////
+//
+//import Foundation
+//public class MSBle {
+//    var lastSender:MSBleSender?
+//    var deviceInfo:MSBleInfo?
+//    var isAuthing = false//是否正在鉴权
+//    
+//    
+//    init() {
+//
+//    }
+//
+//    /// sdk发送数据回调,app将此数据转发给蓝牙设备,写入设备成功后,需要调didWriteToDevice(characteristic:, error:)告知sdk是否写入成功
+//    public var sdkToDeviceCallback:((_ data: Data) -> Void)?
+//    
+//    /// 收到蓝牙设备传过来的数据,转发给sdk处理
+//    public func sendToSdk(voiceData data: Data?){
+//        guard let data = data else{
+//            Logger.log("[recv][voice]")
+//            return
+//        }
+////        Logger.log("[recv][voice] \(data)")
+////        if self.didAuth == false{
+////            DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
+////                self.startAuth()
+////            }
+////            return
+////        }
+//        if(data.count > 16){
+//            MSAudioConvert.sbcTopcm(data){ pcm in
+//                MSVoiceChatSdk.shared.voiceChat.sendVoice(pcmData: pcm)
+//            }
+//        }
+//    }
+//    /// 收到蓝牙设备传过来的数据,转发给sdk处理
+//    public func sendToSdk(infoData data: Data?){
+//        guard let data = data else{
+//            Logger.log("[recv][info]")
+//            return
+//        }
+//        Logger.log("[recv][info] " + data.joined("") + MSTool.dataToUtf8String(data))
+//        if data.joined("") == "7b2272737369223a2230227d"{
+//            return
+//        }
+//        if let sender = lastSender{
+//            lastSender = nil
+//            sender.completion?(.response.code(.success).value(data))
+//            sender.remove()
+//            
+//            deinitTimer()
+//        }
+//    }
+//    /// sdk传给ble设备后,告知sdk写入的情况
+////    public func didWriteToDevice(characteristic: CBCharacteristic, error: Error?){
+////        print(characteristic.uuid.uuidString, "write success")
+////        if let error = error {
+////            print("发送失败 ",characteristic.uuid.uuidString,error.localizedDescription)
+////        }
+////        else{
+////            if characteristic.uuid.uuidString == writeFileCharacteristicUUID{
+////                IBBluetooth.shared.didWriteToDevice()
+////            }
+////        }
+////    }
+//}
+//
+//
+//extension MSBle{
+//    public func startAuth(){
+//        if isAuthing {
+//            return
+//        }
+//        isAuthing = true
+//        requestDeviceInfo {[weak self] info in
+//            guard let self = self else {return}
+//            guard let info = info else {
+//                Logger.log("获取设备信息失败!!!")
+//                isAuthing = false
+//                return
+//            }
+//            Logger.log("设备信息 = \(info.description)")
+//            deviceInfo = info
+//            
+//            deviceInfo!.deviceId = "28110687C456"
+//            deviceInfo!.productId = "WTxAKo2qD2pXOZZLW3zz"
+//            deviceInfo!.productKey = "YqggeKCxfEOVQGjUYrpQQdEstGpvojzn"
+//            deviceInfo!.password = ""
+//            
+//            self.startLogin {[weak self] token, error in
+//                guard let self = self else {return}
+//                isAuthing = false
+//            }
+//        }
+//    }
+//    func requestDeviceInfo(finished: @escaping (MSBleInfo?) -> Void){
+//        let deviceInfo = MSBleInfo()
+//        self.requestDeviceId {[weak self] value in
+//            guard let self = self else {return}
+//            if let value = value{
+//                deviceInfo.deviceId = value
+//                
+//                self.requestProductKey { value in
+//                    if let value = value{
+//                        deviceInfo.productKey = value
+//                        
+//                        self.requestSecretKey { value in
+//                            if let value = value{
+//                                deviceInfo.productId = value
+//                                
+//                                self.requestDeviceSecret { value in
+//                                    if let value = value{
+//                                        deviceInfo.password = value
+//                                        finished(deviceInfo)
+//                                        return
+//                                    }
+//                                    else{
+//                                        finished(nil)
+//                                    }
+//                                }
+//                            }
+//                            else{
+//                                finished(nil)
+//                            }
+//                        }
+//                    }
+//                    else{
+//                        finished(nil)
+//                    }
+//                }
+//            }
+//            else{
+//                finished(nil)
+//            }
+//        }
+//    }
+//    
+//    func requestDeviceId(finished: @escaping (String?) -> Void){
+//        let sender = dictionaryToSender(["cmd":"get_MAC"])
+//        sender.completion = { result in
+//            Logger.log("\(result.description)")
+//            if result.isSuccess,let dict = MSTool.dataToJson(result.data) ,let value = dict["MAC"] as? String{
+//                finished(value)
+//            }
+//            else{
+//                finished(nil)
+//            }
+//        }
+//        sendToBle(sender)
+//    }
+//    func requestProductKey(finished: @escaping (String?) -> Void){
+//        let sender = dictionaryToSender(["cmd":"get_productKey"])
+//        sender.completion = { result in
+//            Logger.log("\(result.description)")
+//            if result.isSuccess,let dict = MSTool.dataToJson(result.data) ,let value = dict["productKey"] as? String{
+//                finished(value)
+//            }
+//            else{
+//                finished(nil)
+//            }
+//        }
+//        sendToBle(sender)
+//    }
+//    func requestSecretKey(finished: @escaping (String?) -> Void){
+//        let sender = dictionaryToSender(["cmd":"get_secretKey"])
+//        sender.completion = { result in
+//            Logger.log("\(result.description)")
+//            if result.isSuccess,let dict = MSTool.dataToJson(result.data) ,let value = dict["secretKey"] as? String{
+//                finished(value)
+//            }
+//            else{
+//                finished(nil)
+//            }
+//        }
+//        sendToBle(sender)
+//    }
+//    func requestDeviceSecret(finished: @escaping (String?) -> Void){
+//        let sender = dictionaryToSender(["cmd":"get_deviceSecret"])
+//        sender.completion = { result in
+//            Logger.log("\(result.description)")
+//            if result.isSuccess,let dict = MSTool.dataToJson(result.data) ,let value = dict["deviceSecret"] as? String{
+//                finished(value)
+//            }
+//            else{
+//                finished(nil)
+//            }
+//        }
+//        sendToBle(sender)
+//    }
+//    
+//    
+//    func sendToBle(_ sender:MSBleSender){
+//        if let _ = lastSender {
+//            sender.completion(.response.code(.failure))
+//            sender.remove()
+//            Logger.log("有命令正在执行中...")
+//            if Self.timer == nil{
+//                startTimer()
+//            }
+//            return
+//        }
+//        Thread.sleep(forTimeInterval:0.02)
+//        lastSender = sender
+//        startTimer()
+//        for data in sender.list{
+//            if let sendToBleBlock = self.sdkToDeviceCallback {
+//                sendToBleBlock(data)
+//            }
+//        }
+//    }
+//}
+//
+//
+//extension MSBle{
+//    static var timer: Timer?
+//    func startTimer() {
+//        deinitTimer()
+//        
+//        Self.timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: false, block: { [unowned self] _ in
+//            deinitTimer()
+//            if let sender = lastSender{
+//                lastSender = nil
+//                sender.completion?(.response.code(.timeout))
+//                sender.remove()
+//            }
+//        })
+////        Logger.log("创建定时器")
+//    }
+//    
+//    func deinitTimer() {
+//        guard let _ = Self.timer else { return }
+//        Self.timer?.invalidate()
+//        Self.timer = nil
+////        Logger.log("销毁定时器")
+//    }
+//}
+//
+//
+//extension MSBle{
+//    func dictionaryToSender(_ dict: [String: Any]) ->MSBleSender{
+//        let sender = MSBleSender()
+//        let str = MSTool.dataToUtf8String(MSTool.jsonToData(dict)!)
+//        let list = splitCMD(str: str)
+//        Logger.log("[send][info][all][string] \(str)")
+//        if list.count > 1 {
+//            // 开始标志
+//            sender.list.append(stringToData(cmd: "-$$\0"))
+//            // 指令
+//            for i in 0..<list.count {
+//                sender.list.append(stringToData(cmd: "\(list[i])\0"))
+//            }
+//            // 结束标志
+//            sender.list.append(stringToData(cmd: "$$-\0"))
+//        } else {
+//            let data = stringToData(cmd: "-$$\(str)$$-\n")
+//            sender.list.append(data)
+//        }
+//        
+//        return sender
+//    }
+//
+//    func stringToData(cmd: String) ->Data{
+//        let data = cmd.data(using:.utf8)!
+//        return data
+//    }
+//
+//    func splitCMD(str: String) -> [String] {
+//        var list = [String]()
+//        var str = str
+//        let len = 30
+//        while str.count > 0 {
+//            if str.count > len {
+//                let sub = String(str.prefix(len))
+//                list.append(sub)
+//                str = String(str.suffix(str.count - len))
+//            } else {
+//                list.append(str)
+//                break
+//            }
+//        }
+//        return list
+//    }
+//}
+//
+//extension MSBle{
+//    func registerAction(completeHandler: @escaping MSLoginCallBack) {
+//        MSVoiceChatSdk.shared.auth.register(productId: deviceInfo!.productId, productKey: deviceInfo!.productKey, deviceId: deviceInfo!.deviceId){[weak self] password,error in
+//            if let password = password{
+//                self?.deviceInfo?.password = password
+//                self?.startLogin(completeHandler: completeHandler)
+//            }
+//            else{
+//                completeHandler(nil,error)
+//            }
+//        }
+//    }
+//
+//    func startLogin(completeHandler: @escaping MSLoginCallBack){
+//        if let info = deviceInfo,info.password.isEmpty{
+//            registerAction(completeHandler: completeHandler)
+//            return
+//        }
+//        
+//        MSVoiceChatSdk.shared.auth.login(productKey:deviceInfo!.productKey,deviceId: deviceInfo!.deviceId, password: deviceInfo!.password){[weak self]  token,error in
+//            if let err = error{
+//                if case  .reponseError(let code,_) = err,code == 50021{
+//                    //50021是账号或密码错误.可以在这里调用注册,重新注册后,之前的密码会被覆盖,APP更新保存的新密码
+//                    self?.registerAction(completeHandler: completeHandler)
+//                }
+//                else{
+//                    completeHandler(nil,err)
+//                }
+//            }
+//            else{
+//                completeHandler(token,nil)
+//            }
+//        }
+//    }
+//}