骨传导sdk迁移
authormemory <496663675@qq.com>
Sun, 4 Jan 2026 09:44:06 +0000 (17:44 +0800)
committermemory <496663675@qq.com>
Sun, 4 Jan 2026 09:44:06 +0000 (17:44 +0800)
57 files changed:
ShenYin/DeepChordsSdk/Any.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/BleSender.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DCBleManager.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DCBleRecord.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DCCallRecord.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DCChat.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DCChinse2En.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DCDevice.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DCLogger.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DCMusic.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DCPhoneRecord.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/Data.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/Date.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DeepChordsAiSdk.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/DeepChordsSdk.docc/DeepChordsSdk.md [new file with mode: 0644]
ShenYin/DeepChordsSdk/DeepChordsSdk.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/ReceiveManager.swift [new file with mode: 0644]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/AIGCErrorCode.h [moved from ShenYin/StarburstSdk.framework/Headers/AIGCErrorCode.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarbaustVoiceChatModel.h [moved from ShenYin/StarburstSdk.framework/Headers/StarbaustVoiceChatModel.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarburstAsrConfig.h [moved from ShenYin/StarburstSdk.framework/Headers/StarburstAsrConfig.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarburstAsrModel.h [moved from ShenYin/StarburstSdk.framework/Headers/StarburstAsrModel.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarburstConfig.h [moved from ShenYin/StarburstSdk.framework/Headers/StarburstConfig.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarburstFileAsrModel.h [moved from ShenYin/StarburstSdk.framework/Headers/StarburstFileAsrModel.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarburstOffLineFile.h [moved from ShenYin/StarburstSdk.framework/Headers/StarburstOffLineFile.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarburstPhoneSdk.h [moved from ShenYin/StarburstSdk.framework/Headers/StarburstPhoneSdk.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarburstSdk.h [moved from ShenYin/StarburstSdk.framework/Headers/StarburstSdk.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarburstSdkManager.h [moved from ShenYin/StarburstSdk.framework/Headers/StarburstSdkManager.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarburstStreamModel.h [moved from ShenYin/StarburstSdk.framework/Headers/StarburstStreamModel.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StarbusrtSpeaker.h [moved from ShenYin/StarburstSdk.framework/Headers/StarbusrtSpeaker.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StartburstDecoderConfig.h [moved from ShenYin/StarburstSdk.framework/Headers/StartburstDecoderConfig.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StartburstGlassChat.h [moved from ShenYin/StarburstSdk.framework/Headers/StartburstGlassChat.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StartburstGlassesSdk.h [moved from ShenYin/StarburstSdk.framework/Headers/StartburstGlassesSdk.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/StartburstMixSdk.h [moved from ShenYin/StarburstSdk.framework/Headers/StartburstMixSdk.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/TextToImageCallback.h [moved from ShenYin/StarburstSdk.framework/Headers/TextToImageCallback.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/TextToImageManager.h [moved from ShenYin/StarburstSdk.framework/Headers/TextToImageManager.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/TextToSpeechCallback.h [moved from ShenYin/StarburstSdk.framework/Headers/TextToSpeechCallback.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Headers/TextToSpeechManager.h [moved from ShenYin/StarburstSdk.framework/Headers/TextToSpeechManager.h with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Info.plist [moved from ShenYin/StarburstSdk.framework/Info.plist with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/Modules/module.modulemap [moved from ShenYin/StarburstSdk.framework/Modules/module.modulemap with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/PrivacyInfo.xcprivacy [moved from ShenYin/StarburstSdk.framework/PrivacyInfo.xcprivacy with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/StarburstSdk [moved from ShenYin/StarburstSdk.framework/StarburstSdk with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/_CodeSignature/CodeDirectory [moved from ShenYin/StarburstSdk.framework/_CodeSignature/CodeDirectory with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/_CodeSignature/CodeRequirements [moved from ShenYin/StarburstSdk.framework/_CodeSignature/CodeRequirements with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/_CodeSignature/CodeRequirements-1 [moved from ShenYin/StarburstSdk.framework/_CodeSignature/CodeRequirements-1 with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/_CodeSignature/CodeResources [moved from ShenYin/StarburstSdk.framework/_CodeSignature/CodeResources with 100% similarity]
ShenYin/DeepChordsSdk/StarburstSdk.framework/_CodeSignature/CodeSignature [moved from ShenYin/StarburstSdk.framework/_CodeSignature/CodeSignature with 100% similarity]
ShenYin/DeepChordsSdk/Untitled.swift [new file with mode: 0644]
ShenYin/DeepChordsSdkTests/DeepChordsSdkTests.swift [new file with mode: 0644]
ShenYin/Podfile.lock
ShenYin/Pods/Kingfisher/PrivacyInfo.xcprivacy
ShenYin/Pods/MBProgressHUD/PrivacyInfo.xcprivacy
ShenYin/ShenYin.xcodeproj/project.pbxproj
ShenYin/ShenYin.xcodeproj/xcshareddata/xcschemes/DeepChordsSdk.xcscheme [new file with mode: 0644]
ShenYin/ShenYin.xcodeproj/xcshareddata/xcschemes/ShenYin.xcscheme
ShenYin/ShenYin.xcworkspace/contents.xcworkspacedata
ShenYin/ShenYin/UI/Mine/Root/MineBannerView.swift
ShenYin/podfile

diff --git a/ShenYin/DeepChordsSdk/Any.swift b/ShenYin/DeepChordsSdk/Any.swift
new file mode 100644 (file)
index 0000000..9ecfd13
--- /dev/null
@@ -0,0 +1,194 @@
+//
+//  Untitled.swift
+//  DeepChordsSdk
+//
+//  Created by liangshi on 2025/11/25.
+//
+
+import Foundation
+
+/// 判断可选类型是否为 nil
+func isNil(_ any: Any?) -> Bool {
+    switch any {
+    case .none: return true
+    case .some: return false
+    }
+}
+
+/// 判断可选类型是否有值
+func isValue(_ any: Any?) -> Bool {
+    return isNil(any) == false
+}
+
+/// for Array
+func isEmpty(_ value: [Any]?) -> Bool {
+    return isNil(value) || value!.count == 0
+}
+
+/// for Array
+func isNotEmpty(_ value: [Any]?) -> Bool {
+    return isEmpty(value) == false
+}
+
+/// for Dictionary
+func isEmpty(_ value: [AnyHashable: Any]?) -> Bool {
+    return isNil(value) || value!.count == 0
+}
+
+/// for Dictionary
+func isNotEmpty(_ value: [AnyHashable: Any]?) -> Bool {
+    return isEmpty(value) == false
+}
+
+/// for String
+func isEmpty(_ value: String?) -> Bool {
+    return isNil(value) || value!.count == 0
+}
+
+/// for String
+func isNotEmpty(_ value: String?) -> Bool {
+    return isEmpty(value) == false
+}
+
+public extension String {
+    
+    /// 补足8位(长度为8的整数倍)
+    var binary: String {
+        let bytes = (Double(count) / 8.0).upInt
+        let offset = bytes * 8 - count
+        let prefix = Array(repeating: "0", count: offset).joined()
+        return prefix + self
+    }
+}
+
+public extension Double {
+    var upInt: Int { Int(ceil(self)) }
+}
+
+public extension Int {
+    private static let binaryPack = 0b11111111
+    
+    /// convert to data with byte (max is 4294967295)
+    ///
+    /// 低位 --> 高位
+    var bytes: [UInt8] {
+        var mutatingSelf = self
+        var bytes = [UInt8(mutatingSelf & Self.binaryPack)]
+        
+        var count = 1
+        mutatingSelf = mutatingSelf >> (count * 8)
+        while mutatingSelf > 0 {
+            bytes.append(UInt8(mutatingSelf & Self.binaryPack))
+            mutatingSelf = mutatingSelf >> (count * 8)
+            count = count + 1
+        }
+        return bytes
+    }
+    
+    /// convert to data with 1 byte
+    var byte: UInt8 {
+        UInt8(self & Self.binaryPack)
+    }
+    
+    /// convert to data with 2 byte
+    ///
+    /// 低位 --> 高位
+    var byte2: [UInt8] {
+        [
+            UInt8(self & Self.binaryPack),
+            UInt8(self >> 8 & Self.binaryPack)
+        ]
+    }
+    
+    /// convert to data with 3 byte
+    ///
+    /// 低位 --> 高位
+    var byte3: [UInt8] {
+        [
+            UInt8(self & Self.binaryPack),
+            UInt8(self >> 8 & Self.binaryPack),
+            UInt8(self >> 16 & Self.binaryPack)
+        ]
+    }
+    
+    /// convert to data with 4 byte
+    ///
+    /// 低位 --> 高位
+    var byte4: [UInt8] {
+        [
+            UInt8(self & Self.binaryPack),
+            UInt8(self >> 8 & Self.binaryPack),
+            UInt8(self >> 16 & Self.binaryPack),
+            UInt8(self >> 24 & Self.binaryPack)
+        ]
+    }
+}
+
+public extension BinaryInteger {
+    
+    /// e.g. 0000100110010101
+    var binaryString: String {
+        .init(self, radix: 2).binary
+    }
+}
+
+public extension Array where Element == UInt8 {
+    
+    var int: Int {
+        self
+            .map { Int($0) }
+            .enumerated()
+            .map { $1 << ($0 * 8) }
+            .reduce(0, { partialResult, value in
+                partialResult | value
+            })
+    }
+    
+    var data: Data { Data(self) }
+}
+
+public extension Data {
+    
+    func joined(format: String = "%02x", _ separator: String = "") -> String {
+        self
+            .map { String(format: format, $0) }
+            .joined(separator: separator)
+    }
+    
+    func reversedJoined(format: String = "%02x", _ separator: String = "") -> String {
+        self
+            .map { String(format: format, $0) }
+            .reversed()
+            .joined(separator: separator)
+    }
+    
+    var int: Int {
+        self
+            .map { Int($0) }
+            .enumerated()
+            .map { $1 << ($0 * 8) }
+            .reduce(0, { partialResult, value in
+                partialResult | value
+            })
+    }
+    
+}
+
+public extension UInt8 {
+    var int: Int { Int(self) }
+}
+
+
+extension Data{
+    var float: Float {
+        var floatValue: Float = 0.0
+        let size = MemoryLayout<Float>.size
+        guard self.count >= size else { return 0 }
+        
+        self.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> Void in
+            _ = memcpy(&floatValue, buffer.baseAddress!, size)
+        }
+        
+        return floatValue
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/BleSender.swift b/ShenYin/DeepChordsSdk/BleSender.swift
new file mode 100644 (file)
index 0000000..fbf60a6
--- /dev/null
@@ -0,0 +1,125 @@
+//
+//  BleSender.swift
+//  DeepChordsSdk
+//
+//  Created by liangshi on 2025/11/25.
+//
+
+import Foundation
+
+class BleSender{
+    var completion: DCCompletionHandler!
+    var data = Data()
+    
+    static var all: [BleSender] = []
+    
+    init() {
+        Self.all.append(self)
+        startTimer()
+    }
+    var timer: Timer?
+    func startTimer() {
+        deinitTimer()
+        
+        self.timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: false, block: { [unowned self] _ in
+            deinitTimer()
+            self.completion?(.response.code(.timeout))
+            self.remove()
+        })
+    }
+    
+    @discardableResult
+    func deinitTimer() ->Self{
+        guard let _ = self.timer else { return self}
+        self.timer?.invalidate()
+        self.timer = nil
+        //        DCLogger.log("销毁定时器")
+        return self
+    }
+    
+    /// 从缓存实例集合中移除该实例
+    func remove() {
+        Self.all.removeAll { $0 === self }
+    }
+    
+    func isAnswer(_ receiveData:Data)->Bool{
+        if data.count < 3{
+            return false
+        }
+        if receiveData[1] == data[1] {
+            return true
+        }
+        return false
+    }
+    
+    static func answer(_ data: Data) -> BleSender? {
+        if data.count < 3{
+            return nil
+        }
+        for item in Self.all {
+            if item.isAnswer(data) {
+                return item
+            }
+        }
+        return nil
+    }
+}
+
+public typealias DCCompletionHandler = (_ result: DCResponse) -> Void
+
+/// 状态码
+public enum DCCode: Int,CustomStringConvertible {
+    
+    public var description: String{
+        return "MSCode(rawValue:\(rawValue), message:\(message))"
+    }
+    
+    /// 操作成功
+    case success = 1000
+    /// 操作失败
+    case failure = 1001
+    /// 请求超时
+    case timeout = 1004
+    /// 未知错误
+    case unknow = 1005
+    
+    var message:String{
+        switch self {
+        case .failure:
+            return "失败"
+        case .success:
+            return "成功"
+        case .timeout:
+            return "超时"
+        default:
+            return "未知错误"
+        }
+    }
+}
+
+public class DCResponse {
+    public private(set) var code: DCCode = .success
+    public private(set) var data: Data = Data()
+    static var response: DCResponse { DCResponse() }
+    
+    
+    var isSuccess:Bool{
+        return code == .success
+    }
+    
+    public var description: String{
+        return code.description + "data = " +  data.joined()
+    }
+    
+    @discardableResult
+    func code(_ value: DCCode) -> Self {
+        code = value
+        return self
+    }
+    
+    @discardableResult
+    func value(_ value: Data) -> Self {
+        self.data = value
+        return self
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/DCBleManager.swift b/ShenYin/DeepChordsSdk/DCBleManager.swift
new file mode 100644 (file)
index 0000000..21420f4
--- /dev/null
@@ -0,0 +1,148 @@
+//
+//  Untitled.swift
+//  DeepChordsSdk
+//
+//  Created by liangshi on 2025/11/25.
+//
+
+import Foundation
+import CoreBluetooth
+import StarburstSdk
+
+public class DCBleManager{
+    public static let serviceUUID = "AE30"
+    public static let writeUUID = "AE03"
+    public static let notifyUUID = "AE04"
+    
+    
+    public static let shared = DCBleManager()
+    private var connectPeripheral: CBPeripheral?
+    private var writeCha: CBCharacteristic?
+
+    func send(_ sender:BleSender){
+        if let connectPeripheral = connectPeripheral, let writeCha = writeCha {
+            DCLogger.debug("发",writeCha.uuid.uuidString,sender.data.joined())
+            
+            
+//            if sender.data[1] == 0x10,sender.data[2] == 0x01 {
+//                let text1 = "ba100101025b7b226964223a302c226e616d65223a22e69da8e5ae97e7baac2de4b880e6aca1e5b0b1e5a5bd20284c697665292e6d7033222c2273697a65223a343233323632342c22647572223a307d2c7b226964223a312c226e616d65223a22e5bca0e7b4abe8b1aa2de58fafe4b88de58fafe4bba52e6d7033222c2273697a65223a393635383835322c22647572223a307d2c7b226964223a322c226e616d65223a224245594f4e442de79c9fe79a84e788b1e4bda02e6d7033222c2273697a65223a31313031363533372c22647572223a307d2c7b226964223a332c226e616d65223a22472e452e4d2e20e98293e7b4abe6a38b2de69c89e5bf83e4baba2e6d7033222c2273697a65223a393630333832392c22647572223a307d2c7b226964223a342c226e616d65223a2248414e41e88f8ae6a293e4b9942de68891e4b88de698afe5a5b92e6d7033222c2273697a65223a373932343138312c22647572223a307d2c7b226964223a352c226e616d65223a2248414e412de5bf98e8aeb0e68891e887aae5b7b12e6d7033222c2273697a65223a393330343938342c22647572223a307d5da701d9"
+//                sender.completion?(.response.code(.success).value(Data.dataWithHexString(text1)))
+//                let text2 = "ba100102025b7b226964223a362c226e616d65223a224d722e3136e7bd97e99abde6b0b82de5a484e5a484e590bb2e6d7033222c2273697a65223a383533333836302c22647572223a307d2c7b226964223a372c226e616d65223a22536f6c65722de9a2a8e79a84e5ada3e7af802e6d7033222c2273697a65223a31303031333432352c22647572223a307d2c7b226964223a382c226e616d65223a225477696e732de6818be788b1e5a4a7e8bf87e5a4a92e6d7033222c2273697a65223a393039383039362c22647572223a307d2c7b226964223a392c226e616d65223a225477696e732de6a3aee5b7b4e79a87e5908e2e6d7033222c2273697a65223a373436323832322c22647572223a307d5d0e012c"
+//                sender.completion?(.response.code(.success).value(Data.dataWithHexString(text2)))
+//            }
+//            else{
+                connectPeripheral.writeValue(sender.data, for: writeCha, type:.withoutResponse)
+//            }
+        }
+    }
+    func sendToStarburst(_ data:Data){
+        var full = Data.dataWithHexString("BA0D")
+        full.append(data)
+        full.addCrc()
+        if let connectPeripheral = connectPeripheral, let writeCha = writeCha {
+//            DCLogger.debug("发",writeCha.uuid.uuidString,full.joined())
+            connectPeripheral.writeValue(full, for: writeCha, type:.withoutResponse)
+        }
+    }
+}
+
+public extension DCBleManager{
+    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
+        DCLogger.debug("蓝牙已连接 \(peripheral)")
+        connectPeripheral = peripheral
+    }
+
+    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
+        DCLogger.debug("蓝牙已断开 \(peripheral)")
+        StarburstSdk.shared().bleDisConnected()
+    }
+//    
+//    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
+//        DCLogger.debug("发现服务成功")
+//        for service in peripheral.services! {
+//            DCLogger.debug("peripheral service: %@", service)
+//            peripheral.discoverCharacteristics(nil, for: service)
+//        }
+//
+//    }
+    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
+        if let list = service.characteristics{
+            DCLogger.debug("发现特征",list)
+            for char in  list{
+                DCLogger.debug(char)
+                if char.uuid.uuidString == DCBleManager.notifyUUID {
+                    peripheral.setNotifyValue(true, for: char)
+                }
+                if char.uuid.uuidString == DCBleManager.writeUUID {
+                    writeCha = char
+                    
+                    DCDevice.shared.handShake { success in
+                        StarburstSdk.shared().bleConnected()
+                    }
+                }
+            }
+        }
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
+//        DCLogger.debug("收 ",characteristic.uuid,characteristic.value?.joined() ?? "")
+        guard let data = characteristic.value else { return  }
+        if data.count > 4 && data[0] == 0xBA {
+            if let sender = BleSender.answer(data) {
+                sender.completion?(.response.code(.success).value(data))
+                if data[1] == 0x10,data[2] == 0x01{
+                    //音乐列表分包,解析的时候处理
+                }
+                else{
+                    sender.deinitTimer()
+                    sender.remove()
+                }
+                return
+            }
+            else if data[1] == 0x0D{
+                let subData = data.subdata(in: 2..<data.count - 3)
+                //DCLogger.debug("传给字节sdk",subData.joined())
+                StarburstSdk.shared().receiveBleData(subData)
+            }else{
+                receiveNoticeData(data)
+            }
+        }
+        else{
+            DCLogger.debug("收到异常数据!!!!!!!!!!!")
+        }
+    }
+}
+
+extension DCBleManager{
+    func receiveNoticeData(_ data:Data){
+        if data[1] == 0x10,data[2] == 0x06{
+            DCDevice.shared.receiveNotice(data)
+        }
+        else if data[1] == 0x0F,data[2] == 0x0B{
+            let type = data[3]
+            switch type{
+            case 0x01:
+                DCLogger.debug("打开AI对话")
+            case 0x02:
+                DCLogger.debug("关闭AI对话")
+//                DCChat.shared.stopChat()
+            case 0x03:
+                DCLogger.debug("打开耳机录音")
+//                DCBleRecord.shared.start(type: 0x00)
+            case 0x04:
+                DCLogger.debug("关闭耳机录音")
+//                DCBleRecord.shared.stop()
+            default:
+                break
+            }
+            DCDevice.shared.eventCallback?(type)
+            DCDevice.shared.sendAiEventResponse(type)
+        }
+    }
+    static func contentData(_ data:Data)->Data{
+        if data.count > 4 && data[0] == 0xBA {
+            return data.subdata(in: 2..<data.count - 3)
+        }
+        return data
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/DCBleRecord.swift b/ShenYin/DeepChordsSdk/DCBleRecord.swift
new file mode 100644 (file)
index 0000000..d2eae43
--- /dev/null
@@ -0,0 +1,135 @@
+//
+//  DCBleRecord.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/9.
+//
+
+import StarburstSdk
+
+public class DCBleRecord {
+    public static let shared = DCBleRecord()
+    /// 语⾔编码,默认为普通话(zh-CN),auto_lang自动识别
+    public var fromLanguage:String = "zh-CN"
+    /// ⽬标语⾔编码,默认为英语(en-US),auto_lang自动识别
+    public var toLanguage:String = "en-US"
+    /// 是否翻译,默认false。如果为true翻译源语言和目标语言不能是同一种语言
+    public var isTranslate = false
+    /// 是否进⾏Tts,默认false
+    public var isTTs = false
+    /// 默认pcm ⽀持pcm / ogg_opus / mp3
+    public var ttsFormat = "mp3"
+    /// 识别回调
+    public var asrCallback:((String)->Void)?
+    /// 识别回调
+    public var translateCallback:((String)->Void)?
+    /// 识别回调
+    public var asrSplitCallback:((DCResponseModel)->Void)?
+    /// 识别回调
+    public var translateSplitCallback:((DCResponseModel)->Void)?
+    /// 翻译语音回调
+    public var translateDataCallback:((Data)->Void)?
+    /// 状态码回调
+    public var codeCallback:((Int)->Void)?
+    /// 录音文件回调
+    public var filePathCallBack:((String?)->Void)?
+    /// 设置录音文件路径
+    public var filePath:String?
+    
+    var asrList : [(String,Int)] = []
+    var asrText = ""
+    
+    var translateList : [(String,Int)] = []
+    var translateText = ""
+    
+    
+    init() {
+        setupRecord()
+    }
+    
+    func setupRecord(){
+        // 通话录音声道数。1:单声道 ;2:⽴体声;默认单声道
+        StarburstConfig.shared().callRecordChannel = 1
+        
+        let config = StarburstAsrConfig()
+        config.isTranslate = isTranslate
+        config.fromLanguage = fromLanguage
+        config.toLanguage = toLanguage
+        config.isTTs = isTTs
+        config.ttsFormat = ttsFormat
+        
+        StarburstSdk.shared().setupDeviceRecord(with: filePath, asrConfig: config) { config in
+            DCLogger.debug("录音类型 \(config!.type == 0x00 ? "实时录音" : "通话录音")")
+        } recognizeText: { [weak self]  model in
+            guard let self = self else {return}
+            guard let model = model else {return}
+            
+            if let text = model.textResult,!text.isEmpty{
+                DCLogger.debug("asr = \(text)")
+                asrSplitCallback?(DCResponseModel(text: text, index: model.definiteIndex, definite: model.definite))
+                let msg = asrList.firstIndex (where: { (str,idx) in
+                    return idx == model.definiteIndex;
+                })
+                if (msg == nil) {
+                    asrList.append((text,model.definiteIndex))
+                } else {
+                    asrList[msg!] = (text,model.definiteIndex)
+                }
+                asrText = asrList.compactMap({ (str,idx) in
+                    return str
+                }).joined(separator: "\n")
+                
+                asrCallback?(asrText)
+            }
+            if let translate = model.translateResult,let text = translate.text,!text.isEmpty{
+                DCLogger.debug("translate = \(text)")
+                translateSplitCallback?(DCResponseModel(text: text, index: Int(translate.definiteIndex), definite: translate.definite))
+                let msg = translateList.firstIndex (where: { (str,idx) in
+                    return idx == translate.definiteIndex;
+                })
+                if (msg == nil) {
+                    translateList.append((text,Int(translate.definiteIndex)))
+                } else {
+                    translateList[msg!] = (text,Int(translate.definiteIndex))
+                }
+                translateText = translateList.compactMap({ (str,idx) in
+                    return str
+                }).joined(separator: "\n")
+                
+                translateCallback?(translateText)
+            }
+            if let ttsData = model.ttsResult?.streamPiece {
+                if let data = Data(base64Encoded: ttsData){
+                    translateDataCallback?(data)
+                }
+            }
+        } stateChange: { [weak self]  code in
+            DCLogger.debug("状态改变",code)
+            self?.codeCallback?(code.rawValue)
+        } finished: {[weak self]  filePath in
+            DCLogger.debug("文件录音保存路径 \(filePath ?? "")")
+            self?.filePathCallBack?(filePath)
+        }
+    }
+    
+    /// 0x00实时录音,0x0c通话录音
+    public func start(type:Int,recordPath:String?){
+        
+            asrList = []
+            asrText = ""
+            
+            translateList = []
+            translateText = ""
+            filePath = recordPath
+        DCLogger.debug("设置地址 \(filePath ?? "")")
+        
+        setupRecord()
+        let config = StarburstBleAsrConfig()
+        config.type = type
+        StarburstSdk.shared().startDeviceRecord(config)
+        
+    }
+    public func stop(){
+        StarburstSdk.shared().stopDeviceRecord()
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/DCCallRecord.swift b/ShenYin/DeepChordsSdk/DCCallRecord.swift
new file mode 100644 (file)
index 0000000..b293dd0
--- /dev/null
@@ -0,0 +1,138 @@
+//
+//  DCCallRecord.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/30.
+//
+
+import StarburstSdk
+
+public class DCCallRecord {
+    public static let shared = DCCallRecord()
+    /// 语⾔编码,默认为普通话(zh-CN),auto_lang自动识别
+    public var fromLanguage:String = "auto_lang"
+    /// ⽬标语⾔编码,默认为英语(en-US),auto_lang自动识别
+    public var toLanguage:String = "auto_lang"
+    /// 是否翻译,默认false。如果为true翻译源语言和目标语言不能是同一种语言
+    public var isTranslate = false
+    /// 是否进⾏Tts,默认false
+    public var isTTs = false
+    /// 默认pcm ⽀持pcm / ogg_opus / mp3
+    public var ttsFormat = "mp3"
+    /// 识别回调
+    public var asrCallback:((String)->Void)?
+    /// 对方识别回调
+    public var asrOtherCallback:((String)->Void)?
+
+    /// 状态码回调
+    public var codeCallback:((Int)->Void)?
+    /// 录音文件回调
+    public var filePathCallBack:((String?)->Void)?
+    /// opus回调
+    public var opusCallBack:((Data)->Void)?
+    
+    var asrList : [(String,Int)] = []
+    var asrText = ""
+
+    var asrOtherList : [(String,Int)] = []
+    var asrOtherText = ""
+    
+    init() {
+        setupRecord()
+    }
+    
+    func setupRecord(){
+        // 通话录音声道数。1:单声道 ;2:⽴体声;默认单声道
+        StarburstConfig.shared().callRecordChannel = 2
+        
+        let config = StarburstAsrConfig()
+        config.isTranslate = isTranslate
+        config.fromLanguage = fromLanguage
+        config.toLanguage = toLanguage
+        config.isTTs = isTTs
+        config.ttsFormat = ttsFormat
+        
+        StarburstSdk.shared().setupDeviceRecord(with: nil, asrConfig: config) { config in
+            DCLogger.debug("录音类型 \(config!.type == 0x00 ? "实时录音" : "通话录音")")
+        } recognizeText: { [weak self]  model in
+            guard let self = self else {return}
+            guard let model = model else {return}
+            DCLogger.debug(model.channel,"asr =",model.definiteIndex,model.textResult)
+            if let text = model.textResult,!text.isEmpty{
+                
+                if model.channel == 1 {
+                    //左耳
+                    let msg = asrList.firstIndex (where: { (str,idx) in
+                        return idx == model.definiteIndex;
+                    })
+                    if (msg == nil) {
+                        asrList.append((text,model.definiteIndex))
+                    } else {
+                        asrList[msg!] = (text,model.definiteIndex)
+                    }
+                    asrText = asrList.compactMap({ (str,idx) in
+                        return str
+                    }).joined(separator: "\n")
+                    
+                    asrCallback?(asrText)
+                }
+                else if  model.channel == 2{
+                    //右耳
+                    let msg = asrOtherList.firstIndex (where: { (str,idx) in
+                        return idx == model.definiteIndex;
+                    })
+                    if (msg == nil) {
+                        asrOtherList.append((text,model.definiteIndex))
+                    } else {
+                        asrOtherList[msg!] = (text,model.definiteIndex)
+                    }
+                    asrOtherText = asrOtherList.compactMap({ (str,idx) in
+                        return str
+                    }).joined(separator: "\n")
+                    
+                    asrOtherCallback?(asrOtherText)
+                }
+
+            }
+        } stateChange: { [weak self]  code in
+            DCLogger.debug("状态改变",code)
+            self?.codeCallback?(code.rawValue)
+        } finished: {[weak self]  filePath in
+            DCLogger.debug("文件录音保存路径 \(filePath ?? "")")
+            self?.filePathCallBack?(filePath)
+        }
+        
+        //通话录音声道数。1:单声道 ;2:⽴体声;默认单声道
+        StarburstConfig.shared().callRecordChannel = 2
+        //收到sdk传过来的opus音频数据,传到OpusManager解码。解码过程是异步
+        StarburstSdk.shared().outputOpusData {[weak self] (config, opusData) in
+            DispatchQueue.global().async {
+                self?.opusCallBack?(opusData!)
+            }
+        }
+    }
+    
+    public func inputPcm(data:Data){
+        StarburstSdk.shared().inputPcmData(data)
+    }
+    
+    /// 0x00实时录音,0x0c通话录音
+    public func start(){
+        
+        asrList = []
+        asrText = ""
+        
+        
+        asrOtherList = []
+        asrOtherText = ""
+        
+        setupRecord()
+        let config = StarburstBleAsrConfig()
+        config.type = 0x0c
+        StarburstSdk.shared().startDeviceRecord(config)
+        
+    }
+    public func stop(){
+        StarburstSdk.shared().stopDeviceRecord()
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/DCChat.swift b/ShenYin/DeepChordsSdk/DCChat.swift
new file mode 100644 (file)
index 0000000..44db924
--- /dev/null
@@ -0,0 +1,137 @@
+//
+//  DCChat.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/15.
+//
+
+import StarburstSdk
+
+public class DCRole{
+    /// 音色id
+    public var sid:String = ""
+    /// 名称
+    public var name:String = ""
+    /// 类型
+    public var type:String = ""
+    /// 角色
+    public var role:String = ""
+    
+    public init(){
+        
+    }
+    
+    public init(sid: String, name: String, type: String, role: String) {
+        self.sid = sid
+        self.name = name
+        self.type = type
+        self.role = role
+    }
+}
+
+public class DCChat{
+    public static let shared = DCChat()
+    var speakerList = [DCRole]()
+    public var dialogId = 0
+    /// 识别回调
+    public var asrCallback:((String,Int)->Void)?
+    /// 回复回调
+    public var responseCallback:((String,Int)->Void)?
+    /// 对话语音回调
+    public var dataCallback:((Int,Data?,Bool,Int)->Void)?
+    /// 状态码回调
+    public var codeCallback:((Int)->Void)?
+    /// 结束对话回调
+    public var finishCallback:((String?)->Void)?
+    
+    /// 智能体
+    public var role:DCRole?
+    /// 是否进⾏Tts,默认false
+    public var tts:Bool = true
+    /// 默认pcm。⽀持pcm / ogg_opus / mp3
+    public var ttsAudioFormat:String = "pcm"
+    /// 语⾔编码,默认为普通话(zh-CN)
+    public var language:String = "zh-CN"
+    
+    init() {
+        setupChat()
+    }
+}
+extension DCChat{
+    public func getVcSpeekerList(finished:@escaping ([DCRole]?,Bool)->Void){
+        StarburstSdk.shared().getVcSpeekerList { (list, success) in
+            if success,let list = list {
+                var temp = [DCRole]()
+                for item in list {
+                    let role = DCRole()
+                    role.sid = item.sid
+                    role.name = item.name
+                    role.type = item.type
+                    role.role = item.role
+                    temp.append(role)
+                }
+                finished(temp,success)
+            }
+            else{
+                finished(nil,success)
+            }
+            
+        }
+    }
+    
+    func setupChat(){
+        let config = StarburstVoiceChatConfig()
+        config.tts = tts
+        config.ttsAudioFormat = ttsAudioFormat
+        if let speaker = role {
+            //            config.role = "spongebob"
+            //            config.ttsSpeakerType = "default"
+            //            config.ttsSpeakerId = "BV063_streaming"
+            config.role = speaker.role
+            config.ttsSpeakerType = speaker.type
+            config.ttsSpeakerId = speaker.sid
+        }
+        
+        StarburstSdk.shared().setupVoiceChat(with: config) { dialogId in
+            DCLogger.debug("开始对话 = \(dialogId)")
+        } textCallback: {[weak self] model in
+            guard let self = self else { return }
+            guard let textModel = model else { return }
+            self.dialogId = textModel.dialogId
+            DCLogger.debug("[recv] = \(textModel.dialogId),\(textModel.conversationFinish),\(textModel.sequence),\(textModel.textResult),\(textModel.responseText)")
+            if let text = textModel.textResult{
+                //DCLogger.debug("[send] = \(textModel.sequence),\(text)")
+                asrCallback?(text,self.dialogId)
+            }
+            else if let text = textModel.responseText{
+                //DCLogger.debug("[recv] = \(textModel.sequence),\(text)")
+                responseCallback?(text,self.dialogId)
+            }
+            
+        } responseVoice: { [weak self] (dialogId,data, finish,sampleRate)  in
+            guard let self = self else { return }
+            self.dialogId = dialogId
+            dataCallback?(dialogId,data,finish,sampleRate)
+        } stateChange: {[weak self] code in
+            DCLogger.debug("状态改变 \(code)")
+            self?.codeCallback?(code.rawValue)
+        } finished: {[weak self] filePath in
+            DCLogger.debug("结束对话")
+            self?.finishCallback?(filePath)
+        }
+    }
+
+    public func startChat(){
+        setupChat()
+        DCDevice.shared.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/ShenYin/DeepChordsSdk/DCChinse2En.swift b/ShenYin/DeepChordsSdk/DCChinse2En.swift
new file mode 100644 (file)
index 0000000..c6b114b
--- /dev/null
@@ -0,0 +1,100 @@
+//
+//  Untitled.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/29.
+//
+
+import StarburstSdk
+
+
+public class DCResponseModel {
+    public var text:String = ""
+    public var index:Int = 0
+    public var definite:Bool = false
+    
+    init(text: String, index: Int, definite: Bool) {
+        self.text = text
+        self.index = index
+        self.definite = definite
+    }
+}
+
+public class DCChinse2En {
+    public static let shared = DCChinse2En()
+    /// 语⾔编码,默认为普通话(zh-CN),auto_lang自动识别
+    public var fromLanguage:String = "zh-CN"
+    /// ⽬标语⾔编码,默认为英语(en-US),auto_lang自动识别
+    public var toLanguage:String = "en-US"
+    /// 是否翻译,默认false。如果为true翻译源语言和目标语言不能是同一种语言
+    public var isTranslate = false
+    /// 是否进⾏Tts,默认false
+    public var isTTs = false
+    /// 默认pcm ⽀持pcm / ogg_opus / mp3
+    public var ttsFormat = "pcm"
+    /// 识别回调
+    public var asrCallback:((DCResponseModel)->Void)?
+    /// 翻译回调
+    public var translateCallback:((DCResponseModel)->Void)?
+    /// 翻译语音回调
+    public var translateDataCallback:((Data)->Void)?
+    /// 状态码回调
+    public var codeCallback:((Int)->Void)?
+    /// 打断
+    public var interruptionCallBack:(()->Void)?
+    /// 录音文件回调
+    public var filePathCallBack:((String?)->Void)?
+    
+    var asrList : [(String,Int)] = []
+    var asrText = ""
+    
+    var translateList : [(String,Int)] = []
+    var translateText = ""
+    
+    public func start(){
+        let config = StarburstAsrConfig()
+        config.isTranslate = isTranslate
+        config.fromLanguage = fromLanguage
+        config.toLanguage = toLanguage
+        config.isTTs = isTTs
+        config.ttsFormat = ttsFormat
+        asrList = []
+        asrText = ""
+        
+        translateList = []
+        translateText = ""
+        
+        StarburstSdk.shared().startRecordAsr(config) {voiceData in
+            //DCLogger.debug("录音的音频流 = \(voiceData!)")
+        } recognizeText: {[weak self] model in
+            guard let self = self else {return}
+            guard let model = model else {return}
+            
+            if let text = model.textResult,!text.isEmpty{
+//                DCLogger.debug("asr = \(text)")
+                asrCallback?(DCResponseModel(text: text, index: model.definiteIndex, definite: model.definite))
+            }
+            if let translate = model.translateResult,let text = translate.text,!text.isEmpty{
+//                DCLogger.debug("translate = \(text)")
+                translateCallback?(DCResponseModel(text: text, index: Int(translate.definiteIndex), definite: translate.definite))
+            }
+            if let ttsData = model.ttsResult?.streamPiece {
+                if let data = Data(base64Encoded: ttsData){
+                    translateDataCallback?(data)
+                }
+            }
+        } stateChange: {[weak self] code in
+            DCLogger.debug("状态改变",code)
+            self?.codeCallback?(code.rawValue)
+        } interruption: { [weak self]  in
+            self?.interruptionCallBack?()
+        }
+    }
+    public func stop(){
+        StarburstSdk.shared().stopRecordAsr {[weak self] filePath in
+            DCLogger.debug("文件录音保存路径 \(filePath ?? "")")
+            self?.filePathCallBack?(filePath)
+        }
+        
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/DCDevice.swift b/ShenYin/DeepChordsSdk/DCDevice.swift
new file mode 100644 (file)
index 0000000..9b557ed
--- /dev/null
@@ -0,0 +1,343 @@
+//
+//  DCDevice.swift
+//  DeepChordsSdk
+//
+//  Created by liangshi on 2025/11/25.
+//
+
+import Foundation
+
+public class DCDevice{
+    public static let shared = DCDevice()
+    
+    /// ai事件回调
+    /// 0x01(打开AI对话)
+//    0x02(关闭AI对话)
+//    0x03(打开耳机录音)
+//    0x04(关闭耳机录音)
+    public var eventCallback:((UInt8)->Void)?
+    
+    public var muiscPlayCallback:((UInt16,UInt16,UInt16)->Void)?
+
+    ///
+    func receiveNotice(_ data:Data){
+        if data[1] == 0x10,data[2] == 0x06{
+            let index = UInt16(data[3...4].int)
+            let pro = UInt16(data[5...6].int)
+            let total = UInt16(data[7...8].int)
+            DCLogger.debug("播放进度index = \(index),total = \(total),pro = \(pro)")
+            muiscPlayCallback?(index,total,pro)
+        }
+    }
+}
+ extension DCDevice{
+     public func handShake(finished:@escaping ((Bool)?)->Void){
+         var head: UInt8 = 0xBA
+         var cmd: UInt8 = 0x11
+         var data:UInt8 = 0x00
+         var total = Data()
+         total.append(&head, count: 1)
+         total.append(&cmd, count: 1)
+         total.append(&data, count: 1)
+         total.addCrc()
+         
+         let sender = BleSender()
+         sender.data = total
+         sender.completion = {[weak self] result in
+             DCLogger.debug("\(result.description)")
+             if result.isSuccess{
+                 finished(true)
+             }
+             else{
+                 DCLogger.debug("握手失败")
+                 finished(false)
+                 self?.handShake(finished: finished)
+             }
+         }
+         DCBleManager.shared.send(sender)
+     }
+     ///
+     ///
+    public func getBatery(finished:@escaping ((Int,Int)?)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x09
+        var data:UInt8 = 0x00
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let leftValue = result.data[3].int
+                let rightValue = result.data[5].int
+                DCLogger.debug(leftValue,rightValue)
+                finished((leftValue,rightValue))
+            }
+            else{
+                finished(nil)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    public func getSoftVersion(finished:@escaping (String?)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x0A
+        var data:UInt8 = 0x00
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let data = result.data[2...6]
+                let text = String(data: data, encoding:.utf8)
+                DCLogger.debug(text ?? "")
+                finished((text))
+            }
+            else{
+                finished(nil)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    public func getHardVersion(finished:@escaping (String?)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x0A
+        var data:UInt8 = 0x01
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let data = result.data[2...6]
+                let text = String(data: data, encoding:.utf8)
+                DCLogger.debug(text ?? "")
+                finished((text))
+            }
+            else{
+                finished(nil)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    
+    /// state 0关闭,1打开
+    public func findDevice(state:UInt8,finished:@escaping (Bool)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x0B
+        var data:UInt8 = state
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let value = result.data[2].int
+                DCLogger.debug(value)
+                finished(true)
+            }
+            else{
+                finished(false)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    
+    /// type, 0x00(正常模式)
+    //    0x01(流行)
+    //    0x02(经典)
+    //    0x03(爵士)
+    //    0x04(摇滚)
+    //    0x05(自定义)
+    public func setEQ(type:UInt8,finished:@escaping (Bool)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x0C
+        var data:UInt8 = type
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let value = result.data[2].int
+                DCLogger.debug(value)
+                finished(value == 0)
+            }
+            else{
+                finished(false)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+     ///  vaue,只有自定义才有,索引 0-9(对应10段EQ调节)(-12~12)
+     public func setCustomEQ(index:UInt8,value:Int,finished:@escaping (Bool)->Void){
+         var head: UInt8 = 0xBA
+         var cmd: UInt8 = 0x0C
+         var data:UInt8 = 0x06
+         var index:UInt8 = UInt8(index)
+         let int8Value: Int8 = Int8(value)
+         let valueData = withUnsafeBytes(of: int8Value) { Data($0) }
+         
+         var total = Data()
+         total.append(&head, count: 1)
+         total.append(&cmd, count: 1)
+         total.append(&data, count: 1)
+         total.append(&index, count: 1)
+         total.append(valueData)
+         total.addCrc()
+         
+         let sender = BleSender()
+         sender.data = total
+         sender.completion = { result in
+             DCLogger.debug("\(result.description)")
+             if result.isSuccess{
+                 let value = result.data[2].int
+                 DCLogger.debug(value)
+                 finished(value == 0)
+             }
+             else{
+                 finished(false)
+             }
+         }
+         DCBleManager.shared.send(sender)
+     }
+    public func getEQ(finished:@escaping ((type:UInt8,value:[Int])?,Bool)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x0E
+        var data:UInt8 = 0x00
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let type = UInt8(result.data[2].int)
+                DCLogger.debug(type)
+                if type == 5 {
+                    let data = result.data[3...12]
+                    let int8Array = data.map { byte in
+                        return Data([byte]).toInt8()
+                    }
+                    print(int8Array)
+                    let list = int8Array.map{Int($0)}
+                    finished((type,list),true)
+                    
+ 
+                }
+                else{
+                    finished((type,[]),true)
+                }
+            }
+            else{
+                finished(nil,false)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+}
+extension Data {
+    func toInt8() -> Int8 {
+        var int8Result: Int8 = 0
+        self.withUnsafeBytes {
+            int8Result = $0.load(as: Int8.self)
+        }
+       return int8Result
+    }
+}
+
+extension DCDevice{
+    //0x01(打开AI对话)
+//    0x02(关闭AI对话)
+//    0x03(打开耳机录音)
+//    0x04(关闭耳机录音)
+    func sendAiEventResponse(_ event:UInt8){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x0F
+        var data:UInt8 = 0x0B
+        var content:UInt8 = event
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.append(&content, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+        }
+        DCBleManager.shared.send(sender)
+        sender.deinitTimer()//不需要回执
+        sender.remove()
+    }
+    func startChat(){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x0F
+        var data:UInt8 = 0x0A
+        var content:UInt8 = 0x01
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.append(&content, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+        }
+        DCBleManager.shared.send(sender)
+    }
+    func stopChat(){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x0F
+        var data:UInt8 = 0x0A
+        var content:UInt8 = 0x00
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.append(&content, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+        }
+        DCBleManager.shared.send(sender)
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/DCLogger.swift b/ShenYin/DeepChordsSdk/DCLogger.swift
new file mode 100644 (file)
index 0000000..c605936
--- /dev/null
@@ -0,0 +1,64 @@
+//
+//  LogManager.swift
+//  Example
+//
+//  Created by liangshi on 2025/11/24.
+//
+
+import Foundation
+
+/// 日记管理
+public class DCLogger {
+    static var isDebug: Bool = true
+    
+    fileprivate static let shared = DCLogger()
+    private var fileHandle:FileHandle?
+    private init() {
+        let path = getPath()
+        fileHandle = FileHandle(forWritingAtPath: path)!
+        //fileHandle?.seekToEndOfFile()
+    }
+    
+    fileprivate var dateString: String { Date().format(.full) }
+    
+    public static var logs: [String] = []
+    
+    
+    private func getPath()->String{
+        let foldPath = NSHomeDirectory() + "/Documents/"
+        let fileManager = FileManager.default
+        if !fileManager.fileExists(atPath: foldPath) {
+            do {
+                try FileManager.default.createDirectory(atPath: foldPath, withIntermediateDirectories: true, attributes: nil)
+            } catch {
+                return ""
+            }
+        }
+        let path = foldPath + "Example_\(Date().format(.middle)).log"
+        if !FileManager.default.fileExists(atPath: path) {
+            FileManager.default.createFile(atPath: path, contents: nil, attributes: nil)
+            
+        }
+        return path
+    }
+}
+
+extension DCLogger {
+    public static func debug(_ logs: Any..., line: Int = #line, separator: String = " ", terminator: String = "\n") {
+        objc_sync_enter(DCLogger.shared)
+        if DCLogger.isDebug {
+            print(DCLogger.shared.dateString, terminator: " [DeepChordsSdk-\(String(format: "%03d", line))]: ")
+            print(logs, separator: separator, terminator: terminator)
+            let logString = DCLogger.shared.dateString + " [DeepChordsSdk-\(String(format: "%03d", line))]: " + logs.map({ "\($0)" }).joined(separator: separator) + terminator
+            Self.logs.append(logString)
+            DCLogger.shared.saveLog(log: logString)
+        }
+        objc_sync_exit(DCLogger.shared)
+        
+        
+    }
+    
+    private func saveLog(log:String){
+        fileHandle?.write(log.data(using: .utf8)!)
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/DCMusic.swift b/ShenYin/DeepChordsSdk/DCMusic.swift
new file mode 100644 (file)
index 0000000..afc82d2
--- /dev/null
@@ -0,0 +1,272 @@
+//
+//  DCMusic.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/17.
+//
+import Foundation
+
+public class DCMusic:Codable{
+    /// id
+    public var id:UInt16 = 0
+    /// 名字
+    public var name:String = ""
+    /// 大小
+    public var size:Int = 0
+    /// 时长
+    public var dur:Int = 0
+}
+
+extension DCDevice{
+    
+    public func getTotalMusic(finished:@escaping (Int?)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x10
+        var data:UInt8 = 0x08
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let value = result.data[3...4].int
+                DCLogger.debug(value)
+                finished(value)
+            }
+            else{
+                finished(nil)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    public func getMusicList(size:UInt8,index:UInt16,finished:@escaping ([DCMusic]?,Bool)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x10
+        var data:UInt8 = 0x01
+        var pageSize = size
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.append(&pageSize, count: 1)
+        total.appendInt16(index)
+        total.addCrc()
+        
+        var totalList = [DCMusic]()
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                //let data = DCBleManager.contentData(result.data)
+                if result.data.count <= 8{
+                    sender.deinitTimer()
+                    sender.remove()
+                    finished(nil,false)
+                    return
+                }
+                
+                let index = result.data[3].int
+                let total = result.data[4].int
+                DCLogger.debug(total,index)
+                let data = result.data.subdata(in: 5..<result.data.count - 3)
+                let str = String(data: data, encoding: .utf8)
+                DCLogger.debug(str ?? "")
+                guard let list = JSON.decode([DCMusic].self, from: data) else {
+                    sender.deinitTimer()
+                    sender.remove()
+                    finished(nil,false)
+                    return
+                }
+                totalList += list
+                
+                if index == total {
+                    sender.deinitTimer()
+                    sender.remove()
+                    finished(totalList,true)
+                }
+            }
+            else{
+                finished(nil,false)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    
+    //    0x00:顺序循环
+    //    0x01:随机
+    //    0x02:单曲
+    public func setMusicPlayMode(mode:UInt8,finished:@escaping (Bool)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x10
+        var data:UInt8 = 0x02
+        var mode:UInt8 = mode
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.append(&mode, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let value = result.data[2].int
+                DCLogger.debug(value)
+                finished(value == 0)
+            }
+            else{
+                finished(false)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    public func getMusicPlayMode(finished:@escaping (UInt8?,Bool)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x10
+        var data:UInt8 = 0x03
+        var content:UInt8 = 0x00
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.append(&content, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let value = UInt8(result.data[3].int)
+                DCLogger.debug(value)
+                finished(value,true)
+            }
+            else{
+                finished(nil,false)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    
+    public func musicPlay(index:UInt16?,finished:@escaping (UInt16?,Bool)->Void){
+        if let index = index {
+            var head: UInt8 = 0xBA
+            var cmd: UInt8 = 0x10
+            var data:UInt8 = 0x05
+            
+            var total = Data()
+            total.append(&head, count: 1)
+            total.append(&cmd, count: 1)
+            total.append(&data, count: 1)
+            total.appendInt16(index)
+            total.addCrc()
+            
+            let sender = BleSender()
+            sender.data = total
+            sender.completion = { result in
+                DCLogger.debug("\(result.description)")
+                if result.isSuccess{
+                    let value = UInt16(result.data[3...4].int)
+                    DCLogger.debug(value)
+                    finished(value,true)
+                }
+                else{
+                    finished(nil,false)
+                }
+            }
+            DCBleManager.shared.send(sender)
+        }
+        else{
+            var head: UInt8 = 0xBA
+            var cmd: UInt8 = 0x10
+            var data:UInt8 = 0x04
+            var content:UInt8 = 0x00
+            
+            var total = Data()
+            total.append(&head, count: 1)
+            total.append(&cmd, count: 1)
+            total.append(&data, count: 1)
+            total.append(&content, count: 1)
+            total.addCrc()
+            
+            let sender = BleSender()
+            sender.data = total
+            sender.completion = { result in
+                DCLogger.debug("\(result.description)")
+                if result.isSuccess{
+                    let value = UInt16(result.data[3...4].int)
+                    DCLogger.debug(value)
+                    finished(value,true)
+                }
+                else{
+                    finished(nil,false)
+                }
+            }
+            DCBleManager.shared.send(sender)
+        }
+    }
+    public func musicPause(finished:@escaping (Bool)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x10
+        var data:UInt8 = 0x04
+        var content:UInt8 = 0x01
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.append(&content, count: 1)
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                finished(true)
+            }
+            else{
+                finished(false)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    public func musicDelete(list:[UInt16],finished:@escaping (Bool)->Void){
+        var head: UInt8 = 0xBA
+        var cmd: UInt8 = 0x10
+        var data:UInt8 = 0x07
+        var content:UInt8 = UInt8(list.count)
+        var total = Data()
+        total.append(&head, count: 1)
+        total.append(&cmd, count: 1)
+        total.append(&data, count: 1)
+        total.append(&content, count: 1)
+        for item in list {
+            total.appendInt16(item)
+        }
+        total.addCrc()
+        
+        let sender = BleSender()
+        sender.data = total
+        sender.completion = { result in
+            DCLogger.debug("\(result.description)")
+            if result.isSuccess{
+                let value = UInt16(result.data[3].int)
+                DCLogger.debug(value)
+                finished(value == 0)
+            }
+            else{
+                finished(false)
+            }
+        }
+        DCBleManager.shared.send(sender)
+    }
+    
+}
diff --git a/ShenYin/DeepChordsSdk/DCPhoneRecord.swift b/ShenYin/DeepChordsSdk/DCPhoneRecord.swift
new file mode 100644 (file)
index 0000000..4046440
--- /dev/null
@@ -0,0 +1,110 @@
+//
+//  DC.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/9.
+//
+import StarburstSdk
+
+public class DCPhoneRecord {
+    public static let shared = DCPhoneRecord()
+    /// 语⾔编码,默认为普通话(zh-CN),auto_lang自动识别
+    public var fromLanguage:String = "zh-CN"
+    /// ⽬标语⾔编码,默认为英语(en-US),auto_lang自动识别
+    public var toLanguage:String = "en-US"
+    /// 是否翻译,默认false。如果为true翻译源语言和目标语言不能是同一种语言
+    public var isTranslate = false
+    /// 是否进⾏Tts,默认false
+    public var isTTs = false
+    /// 默认pcm ⽀持pcm / ogg_opus / mp3
+    public var ttsFormat = "pcm"
+    /// 识别回调
+    public var asrCallback:((String)->Void)?
+    /// 翻译回调
+    public var translateCallback:((String)->Void)?
+    /// 翻译语音回调
+    public var translateDataCallback:((Data)->Void)?
+    /// 状态码回调
+    public var codeCallback:((Int)->Void)?
+    /// 打断
+    public var interruptionCallBack:(()->Void)?
+    /// 录音文件回调
+    public var filePathCallBack:((String?)->Void)?
+    
+    var asrList : [(String,Int)] = []
+    var asrText = ""
+    
+    var translateList : [(String,Int)] = []
+    var translateText = ""
+    
+    public func start(){
+        let config = StarburstAsrConfig()
+        config.isTranslate = isTranslate
+        config.fromLanguage = fromLanguage
+        config.toLanguage = toLanguage
+        config.isTTs = isTTs
+        config.ttsFormat = ttsFormat
+        asrList = []
+        asrText = ""
+        
+        translateList = []
+        translateText = ""
+        
+        StarburstSdk.shared().startRecordAsr(config) {voiceData in
+            //DCLogger.debug("录音的音频流 = \(voiceData!)")
+        } recognizeText: {[weak self] model in
+            guard let self = self else {return}
+            guard let model = model else {return}
+            
+            if let text = model.textResult,!text.isEmpty{
+                DCLogger.debug("asr = \(text)")
+                let msg = asrList.firstIndex (where: { (str,idx) in
+                    return idx == model.definiteIndex;
+                })
+                if (msg == nil) {
+                    asrList.append((text,model.definiteIndex))
+                } else {
+                    asrList[msg!] = (text,model.definiteIndex)
+                }
+                asrText = asrList.compactMap({ (str,idx) in
+                    return str
+                }).joined(separator: "\n")
+                
+                asrCallback?(asrText)
+            }
+            if let translate = model.translateResult,let text = translate.text,!text.isEmpty{
+                DCLogger.debug("translate = \(text)")
+                let msg = translateList.firstIndex (where: { (str,idx) in
+                    return idx == translate.definiteIndex;
+                })
+                if (msg == nil) {
+                    translateList.append((text,Int(translate.definiteIndex)))
+                } else {
+                    translateList[msg!] = (text,Int(translate.definiteIndex))
+                }
+                translateText = translateList.compactMap({ (str,idx) in
+                    return str
+                }).joined(separator: "\n")
+                
+                translateCallback?(translateText)
+            }
+            if let ttsData = model.ttsResult?.streamPiece {
+                if let data = Data(base64Encoded: ttsData){
+                    translateDataCallback?(data)
+                }
+            }
+        } stateChange: {[weak self] code in
+            DCLogger.debug("状态改变",code)
+            self?.codeCallback?(code.rawValue)
+        } interruption: { [weak self]  in
+            self?.interruptionCallBack?()
+        }
+    }
+    public func stop(){
+        StarburstSdk.shared().stopRecordAsr {[weak self] filePath in
+            DCLogger.debug("文件录音保存路径 \(filePath ?? "")")
+            self?.filePathCallBack?(filePath)
+        }
+
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/Data.swift b/ShenYin/DeepChordsSdk/Data.swift
new file mode 100644 (file)
index 0000000..d59dcb4
--- /dev/null
@@ -0,0 +1,105 @@
+//
+//  Data.swift
+//  Example
+//
+//  Created by liangshi on 2025/11/24.
+//
+import Foundation
+
+extension Data {
+    static func dataWithHexString(_ 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
+    }
+    
+    static func crc8(_ data: Data) -> UInt8 {
+        var crc: UInt8 = 0
+        for byte in data {
+            crc ^= byte
+            for _ in 0..<8 {
+                if crc & 0x01 != 0 {
+                    crc = (crc >> 1) ^ 0x8C
+                } else {
+                    crc >>= 1
+                }
+            }
+        }
+        return crc
+    }
+    
+    mutating func addCrc(){
+        var len = UInt16(self.count - 2)
+        self.appendInt16(len)
+        var crc = Data.crc8(self)
+        self.append(&crc, count: 1)
+    }
+    
+//    mutating func addCrc(){
+//       var  list = self.map({ $0 })
+//       var crc = chargestore_crc8(list, len: list.count)
+//        self.append(&crc, count: 1)
+//    }
+    
+    mutating func appendInt16(_ value:UInt16){
+        var byte1 = UInt8(value & 0xFF)
+        var byte2 = UInt8((value >> 8) & 0xFF)
+        self.append(&byte1, count: 1)
+        self.append(&byte2, count: 1)
+        
+    }
+}
+
+
+func chargestore_crc8(_ ptr: UnsafePointer<UInt8>, len: Int) -> UInt8 {
+    var crc: UInt8 = 0
+    var length = len
+    var currentPtr = ptr
+    
+    while length > 0 {
+        crc ^= currentPtr.pointee
+        currentPtr = currentPtr.advanced(by: 1)
+        length -= 1
+        
+        for _ in 0..<8 {
+            if crc & 0x01 != 0 {
+                crc = (crc >> 1) ^ 0x8C
+            } else {
+                crc >>= 1
+            }
+        }
+    }
+    return crc
+}
+
+class JSON {
+    /// JSON decode
+    static func decode<T: Decodable>(_ decodable: T.Type, from data: Data) -> T? {
+        do {
+            return try JSONDecoder().decode(decodable.self, from: data)
+        } catch { }
+        return nil
+    }
+    
+    /// JSON decode
+    static func decode<T: Decodable>(_ decodable: T.Type, from jsonString: String) -> T? {
+        guard let data = jsonString.data(using: .utf8) else { return nil }
+        return decode(decodable, from: data)
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/Date.swift b/ShenYin/DeepChordsSdk/Date.swift
new file mode 100644 (file)
index 0000000..3fd88f0
--- /dev/null
@@ -0,0 +1,152 @@
+//
+//  Date.swift
+//  Example
+//
+//  Created by liangshi on 2025/11/24.
+//
+
+
+import Foundation
+
+// MARK: - Extension Date
+extension Date {
+    
+    static let formatter = DateFormatter()
+    
+    struct Format {
+        
+        let rawValue: String
+        init(_ rawValue: String) {
+            self.rawValue = rawValue
+        }
+        
+        /// e.g. 01:01:01
+        static let time: Format = .init("HH:mm:ss")
+        
+        /// e.g. 01:01
+        static let shortTime: Format = .init("HH:mm")
+        
+        /// e.g. 01-01
+        static let date: Format = .init("MM-dd")
+        
+        /// e.g. 01月01日
+        static let date1: Format = .init("MM月dd日")
+        
+        /// e.g. 2020-01-01
+        static let short: Format = .init("yyyy-MM-dd")
+        
+        
+        /// e.g. 2020年01月01日
+        static let short1: Format = .init("yyy年MM月dd日")
+        
+        /// e.g. 2020-01-01 01:01
+        static let middle: Format = .init("yyyy-MM-dd HH:mm")
+        
+        /// e.g. 2020年01月01日 01:01
+        static let middle1: Format = .init("yyy年MM月dd日 HH:mm")
+        
+        /// e.g. 2020-01-01 01:01:01
+        static let long: Format = .init("yyyy-MM-dd HH:mm:ss")
+        
+        /// e.g. 2020年01月01日 01:01:01
+        static let long1: Format = .init("yyyy年MM月dd日 HH:mm:ss")
+        
+        /// e.g. 2020-01-01 01:01:01.088
+        static let full: Format = .init("yyyy-MM-dd HH:mm:ss.SSS")
+        
+        /// e.g. 2020年01月01日 01:01:01.088
+        static let full1: Format = .init("yyyy年MM月dd日 HH:mm:ss.SSS")
+        static let full2: Format = .init("yyyy-MM-ddTHH:mm")
+        static let full3: Format = .init("yyyy-MM-dd HH:mm")
+        static let full4: Format = .init("yyyyMMdd00000000")
+        static let full5: Format = .init("yyyyMMddHHmmss")
+        static let full6: Format = .init("yyyyMMddHHmmssSSS")
+    }
+    
+    /// 格式化成本地时间
+    func format(_ format: Date.Format = .middle) -> String {
+        Self.formatter.dateFormat = format.rawValue
+        return Self.formatter.string(from: self)
+    }
+    
+    enum Unit {
+        case minute(Int)
+        case hour(Int)
+        case day(Int)
+        
+        /// 转换成秒
+        var second: TimeInterval {
+            switch self {
+            case .minute(let minute): return 60.0 * Double(minute)
+            case .hour(let hour): return 60.0 * 60.0 * Double(hour)
+            case .day(let day): return 60.0 * 60.0 * 24.0 * Double(day)
+            }
+        }
+    }
+}
+
+let today: Date = .init()
+
+/// 本地化
+extension Date {
+    /// 星期几
+    enum Week: Int {
+        /// 星期日
+        case sun = 1
+        /// 星期一
+        case mon
+        /// 星期二
+        case tue
+        /// 星期三
+        case wed
+        /// 星期四
+        case thur
+        /// 星期五
+        case fri
+        /// 星期六
+        case sat
+    }
+    
+    //    /// 当天的第一秒
+    //    var fromTimeInterval: TimeInterval {
+    //        let today = format(.short)
+    //        return today.timeIntervalSince1970(.short)
+    //    }
+    //
+    //    /// 当天最后一秒
+    //    var toTimeInterval: TimeInterval { fromTimeInterval + Unit.day(1).second }
+    
+    /// 哪一年
+    var year: Int { component(.year) }
+    
+    /// 哪个月
+    var month: Int { component(.month) }
+    
+    /// 当月的第几天
+    var day: Int { component(.day) }
+    
+    /// 当月的第几天
+    var hour: Int { component(.hour)}
+    
+    /// 当月的第几天
+    var minute: Int { component(.minute)}
+    
+    /// 当月的第几天
+    var second: Int { component(.second)}
+    
+    /// 当月的第几周
+    var  weekOfMonth: Int { component(.weekOfMonth) }
+    
+    /// 今年的第几周
+    var  weekOfYear: Int { component(.weekOfYear) }
+    
+    /// 星期几
+    var weekDay: Week { Week(rawValue: component(.weekday))! }
+    
+    /// 假设当天是周五,表示本月的第几个周五
+    var weekdayOrdinal: Int { component(.weekdayOrdinal) }
+    
+    private func component(_ component: Calendar.Component) -> Int {
+        return Calendar.autoupdatingCurrent.component(component, from: self)
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/DeepChordsAiSdk.swift b/ShenYin/DeepChordsSdk/DeepChordsAiSdk.swift
new file mode 100644 (file)
index 0000000..9aa91fc
--- /dev/null
@@ -0,0 +1,102 @@
+//
+//  DeepChords.swift
+//  DeepChordsSdk
+//
+//  Created by liangshi on 2025/11/25.
+//
+import Foundation
+import StarburstSdk
+public class DeepChordsAiSdk{
+    public static let shared = DeepChordsAiSdk()
+    public var authCallback: ((Int,String) -> Void)?
+    public var sdkLog:String{
+        return StarburstConfig.shared().logPath
+    }
+    public var isDebug:Bool = false{
+        didSet{
+            StarburstConfig.shared().isDebug = false
+            DCLogger.isDebug = isDebug
+        }
+    }
+    
+    
+    public func initSDK(){
+
+        StarburstConfig.shared().switch(to: .ble)
+        StarburstConfig.shared().appId = "prjzVnOEpKL1N"
+        StarburstConfig.shared().isDebug = false
+        //MARK: 配置缓存路径
+        StarburstConfig.shared().sdkFolder = NSTemporaryDirectory()
+//        StarburstConfig.shared().sdkFolder = NSHomeDirectory() + "/Documents/DeepChordsSdk"
+        // 日志路径
+//        StarburstConfig.shared().logPath = logPath()
+        StarburstConfig.shared().logPath = nil
+        //是否下发文字到耳机仓
+        StarburstConfig.shared().enableTextSyncToDevice = false
+        //主从耳机切换是否同步sdk信息到耳机
+        StarburstConfig.shared().enableEarbudsSwitchSync = true
+        //耳机仓表情下发开关
+        StarburstConfig.shared().enableEmotionSyncToDevice = false
+        //添加调试信息
+//        StarburstConfig.shared().debugInfo = [
+//            "x-use-ppe":"1",
+//            "x-tt-env": "ppe_tischarge_test",
+//        ]
+        // voicechat配置
+//        StarburstConfig.shared().user_custom_prompt_init = "1.用户位置在上海市杨浦区。2.用户名称叫小明。"
+        
+        StarburstSdk.shared().authCallback = {[weak self] (code,msg) in
+            self?.authCallback?(Int(code),msg ?? "")
+        }
+        //sdk发给蓝牙设备
+        StarburstSdk.shared().sendToBleCallback = {data in
+            guard let data = data else {return}
+            DCBleManager.shared.sendToStarburst(data)
+        }
+        StarburstSdk.shared().bleRecordStateCallback = {[weak self] state in
+            
+        }
+    }
+    
+    func logPath()->String{
+        let format = DateFormatter()
+        format.dateFormat = "yyyyMMddHHmmss"
+        let text = format.string(from: Date())
+        return NSHomeDirectory() + "/Documents/StarburstSdk_\(text).log"
+    }
+}
+
+extension DeepChordsAiSdk{
+    public func translate(text:String,from:String,to:String,finished:@escaping ((stream:String,finish:Bool)?)->Void){
+        let con = StarburstTslConfig()
+        con.fromLanguage = from
+        con.toLanguage = to
+        
+        StarburstSdk.shared().translateByText(withSplit: text, config: con) { model in
+            guard let model = model else{return}
+            finished((model.llmResponse,model.complete))
+        } error: { error in
+            finished(nil)
+        }
+
+    }
+    public func sumary(text:String,finished:@escaping ((stream:String,finish:Bool)?)->Void){
+        
+        StarburstSdk.shared().summaryByText(withSplit: text) { model in
+            guard let model = model else{return}
+            finished((model.llmResponse,model.complete))
+        } error: { error in
+            finished(nil)
+        }
+    }
+    public func cancelTranslateByTextWithSplit(){
+        StarburstSdk.shared().cancelTranslateByTextWithSplit()
+    }
+    public func cancelSummaryByTextWithSplit(){
+        StarburstSdk.shared().cancelSummaryByTextWithSplit()
+    }
+    public func getDeviceName()->String?{
+        let dn = StarburstSdk.shared().getDeviceName()
+        return dn
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/DeepChordsSdk.docc/DeepChordsSdk.md b/ShenYin/DeepChordsSdk/DeepChordsSdk.docc/DeepChordsSdk.md
new file mode 100644 (file)
index 0000000..c4554ad
--- /dev/null
@@ -0,0 +1,13 @@
+# ``DeepChordsSdk``
+
+<!--@START_MENU_TOKEN@-->Summary<!--@END_MENU_TOKEN@-->
+
+## Overview
+
+<!--@START_MENU_TOKEN@-->Text<!--@END_MENU_TOKEN@-->
+
+## Topics
+
+### <!--@START_MENU_TOKEN@-->Group<!--@END_MENU_TOKEN@-->
+
+- <!--@START_MENU_TOKEN@-->``Symbol``<!--@END_MENU_TOKEN@-->
\ No newline at end of file
diff --git a/ShenYin/DeepChordsSdk/DeepChordsSdk.swift b/ShenYin/DeepChordsSdk/DeepChordsSdk.swift
new file mode 100644 (file)
index 0000000..1f8cd1f
--- /dev/null
@@ -0,0 +1,9 @@
+//
+//  DeepChordsSdk.swift
+//  DeepChordsSdk
+//
+//  Created by lianzi on 2026/1/4.
+//
+
+import Foundation
+
diff --git a/ShenYin/DeepChordsSdk/ReceiveManager.swift b/ShenYin/DeepChordsSdk/ReceiveManager.swift
new file mode 100644 (file)
index 0000000..e482cd6
--- /dev/null
@@ -0,0 +1,15 @@
+//
+//  ReceiveManager.swift
+//  DeepChordsSdk
+//
+//  Created by liangshi on 2025/11/25.
+//
+import Foundation
+
+class ReceiveManager{
+    
+    
+    static func receiveData(_ data:Data){
+        
+    }
+}
diff --git a/ShenYin/DeepChordsSdk/Untitled.swift b/ShenYin/DeepChordsSdk/Untitled.swift
new file mode 100644 (file)
index 0000000..b0ff59a
--- /dev/null
@@ -0,0 +1,7 @@
+//
+//  Untitled.swift
+//  Example
+//
+//  Created by liangshi on 2025/12/29.
+//
+
diff --git a/ShenYin/DeepChordsSdkTests/DeepChordsSdkTests.swift b/ShenYin/DeepChordsSdkTests/DeepChordsSdkTests.swift
new file mode 100644 (file)
index 0000000..6ec3507
--- /dev/null
@@ -0,0 +1,17 @@
+//
+//  DeepChordsSdkTests.swift
+//  DeepChordsSdkTests
+//
+//  Created by lianzi on 2026/1/4.
+//
+
+import Testing
+@testable import DeepChordsSdk
+
+struct DeepChordsSdkTests {
+
+    @Test func example() async throws {
+        // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+    }
+
+}
index 4142efd..acd287b 100644 (file)
@@ -3,6 +3,7 @@ PODS:
   - DeviceKit (5.4.0)
   - DGActivityIndicatorView (2.1.1)
   - FDFullscreenPopGesture (1.1)
+  - FSPagerView (0.8.3)
   - HandyJSON (5.0.2)
   - HorizonCalendar (2.0.0)
   - IQKeyboardCore (1.0.5)
@@ -73,6 +74,7 @@ DEPENDENCIES:
   - DeviceKit (~> 5.4.0)
   - DGActivityIndicatorView
   - FDFullscreenPopGesture
+  - FSPagerView
   - HandyJSON
   - HorizonCalendar
   - IQKeyboardManagerSwift
@@ -99,6 +101,7 @@ SPEC REPOS:
     - DeviceKit
     - DGActivityIndicatorView
     - FDFullscreenPopGesture
+    - FSPagerView
     - HandyJSON
     - HorizonCalendar
     - IQKeyboardCore
@@ -131,6 +134,7 @@ SPEC CHECKSUMS:
   DeviceKit: bd34bb1766d926c3cc5a5f6e3e9a6dd10148b805
   DGActivityIndicatorView: ff2c76073d79692f724863c8dd38685866a03cb6
   FDFullscreenPopGesture: a8a620179e3d9c40e8e00256dcee1c1a27c6d0f0
+  FSPagerView: 670405b2f18e2a87fa37f20b00de783e562c25a8
   HandyJSON: 9e4e236f5d2dbefad5155a77417bbea438201c03
   HorizonCalendar: 21e600058a8f4d407c79ef7848beda692c53a484
   IQKeyboardCore: 28c8bf3bcd8ba5aa1570b318cbc4da94b861711e
@@ -158,6 +162,6 @@ SPEC CHECKSUMS:
   YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
   ZipArchive: e25a4373192673e3229ac8d6e9f64a3e5713c966
 
-PODFILE CHECKSUM: 170365f9acea11a62fa72e8f7904f6acb237a166
+PODFILE CHECKSUM: 8f9cd07b8bd8a2a7a6ddbfd0af6732a71e3766ec
 
 COCOAPODS: 1.16.2
index 148b97e..b951586 100644 (file)
@@ -2,22 +2,13 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-       <key>NSPrivacyTracking</key>
-       <false/>
+       <key>NSPrivacyCollectedDataTypes</key>
+       <array/>
        <key>NSPrivacyTrackingDomains</key>
        <array/>
        <key>NSPrivacyAccessedAPITypes</key>
-       <array>
-               <dict>
-                       <key>NSPrivacyAccessedAPIType</key>
-                       <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
-                       <key>NSPrivacyAccessedAPITypeReasons</key>
-                       <array>
-                               <string>E174.1</string>
-                       </array>
-               </dict>
-       </array>
-       <key>NSPrivacyCollectedDataTypes</key>
        <array/>
+       <key>NSPrivacyTracking</key>
+       <false/>
 </dict>
 </plist>
index 148b97e..b951586 100644 (file)
@@ -2,22 +2,13 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-       <key>NSPrivacyTracking</key>
-       <false/>
+       <key>NSPrivacyCollectedDataTypes</key>
+       <array/>
        <key>NSPrivacyTrackingDomains</key>
        <array/>
        <key>NSPrivacyAccessedAPITypes</key>
-       <array>
-               <dict>
-                       <key>NSPrivacyAccessedAPIType</key>
-                       <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
-                       <key>NSPrivacyAccessedAPITypeReasons</key>
-                       <array>
-                               <string>E174.1</string>
-                       </array>
-               </dict>
-       </array>
-       <key>NSPrivacyCollectedDataTypes</key>
        <array/>
+       <key>NSPrivacyTracking</key>
+       <false/>
 </dict>
 </plist>
index 17f2faf..67f4f6d 100644 (file)
@@ -7,21 +7,29 @@
        objects = {
 
 /* Begin PBXBuildFile section */
-               0D54E0612F0A5FDD00A80EE7 /* StarburstSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D54E0602F0A5FDD00A80EE7 /* StarburstSdk.framework */; };
-               3F7602F12EFA8BAB00588C18 /* DeepChordsSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */; };
-               3F7602F22EFA8BAB00588C18 /* DeepChordsSdk.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+               0D54E4482F0A62F700A80EE7 /* DeepChordsSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D54E0EF2F0A61E600A80EE7 /* DeepChordsSdk.framework */; };
                3F8F58292EBCA2B800FFC00B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */; };
+               644D1BB5EDD3EA1D77C57786 /* Pods_DeepChordsSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 248D8B53B5A178ACA5867275 /* Pods_DeepChordsSdk.framework */; };
                F2E449CAD5874BE652A69B50 /* Pods_ShenYin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3862D5561144E20721225B96 /* Pods_ShenYin.framework */; };
 /* End PBXBuildFile section */
 
+/* Begin PBXContainerItemProxy section */
+               0D54E1022F0A61E600A80EE7 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 3F887B942E38D8DC00C98658 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 0D54E0EE2F0A61E600A80EE7;
+                       remoteInfo = DeepChordsSdk;
+               };
+/* End PBXContainerItemProxy section */
+
 /* Begin PBXCopyFilesBuildPhase section */
-               3F79C6162E6055E500EC38B9 /* Embed Frameworks */ = {
+               0D54E4462F0A62D900A80EE7 /* Embed Frameworks */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 2147483647;
                        dstPath = "";
                        dstSubfolderSpec = 10;
                        files = (
-                               3F7602F22EFA8BAB00588C18 /* DeepChordsSdk.framework in Embed Frameworks */,
                        );
                        name = "Embed Frameworks";
                        runOnlyForDeploymentPostprocessing = 0;
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
-               0D54E0602F0A5FDD00A80EE7 /* StarburstSdk.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = StarburstSdk.framework; sourceTree = "<group>"; };
+               0D54E0EF2F0A61E600A80EE7 /* DeepChordsSdk.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DeepChordsSdk.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+               248D8B53B5A178ACA5867275 /* Pods_DeepChordsSdk.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DeepChordsSdk.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                3862D5561144E20721225B96 /* Pods_ShenYin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShenYin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DeepChordsSdk.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                3F887B9C2E38D8DC00C98658 /* ShenYin.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShenYin.app; sourceTree = BUILT_PRODUCTS_DIR; };
                3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
+               5A92F7DC2CB6E6E69D2AB23E /* Pods-DeepChordsSdk.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DeepChordsSdk.debug.xcconfig"; path = "Target Support Files/Pods-DeepChordsSdk/Pods-DeepChordsSdk.debug.xcconfig"; sourceTree = "<group>"; };
                5F5DE5910965D53C2B3405B0 /* Pods-ShenYin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShenYin.debug.xcconfig"; path = "Target Support Files/Pods-ShenYin/Pods-ShenYin.debug.xcconfig"; sourceTree = "<group>"; };
                CB933A7969ADF81D59503790 /* Pods-LingQi.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LingQi.debug.xcconfig"; path = "Target Support Files/Pods-LingQi/Pods-LingQi.debug.xcconfig"; sourceTree = "<group>"; };
                CE98543C79FAAB6CEF4CBFCA /* Pods-LingQi.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LingQi.release.xcconfig"; path = "Target Support Files/Pods-LingQi/Pods-LingQi.release.xcconfig"; sourceTree = "<group>"; };
+               E7D3DF51BED56E93E4ED8102 /* Pods-DeepChordsSdk.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DeepChordsSdk.release.xcconfig"; path = "Target Support Files/Pods-DeepChordsSdk/Pods-DeepChordsSdk.release.xcconfig"; sourceTree = "<group>"; };
                FBA7C30445BB0602D6B92F11 /* Pods-ShenYin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShenYin.release.xcconfig"; path = "Target Support Files/Pods-ShenYin/Pods-ShenYin.release.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
                };
 /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
 
+/* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */
+               0D54E4472F0A62D900A80EE7 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" build phase */ = {
+                       isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
+                       buildPhase = 0D54E4462F0A62D900A80EE7 /* Embed Frameworks */;
+                       membershipExceptions = (
+                               StarburstSdk.framework,
+                       );
+               };
+/* End PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */
+
 /* Begin PBXFileSystemSynchronizedRootGroup section */
+               0D54E0F02F0A61E600A80EE7 /* DeepChordsSdk */ = {
+                       isa = PBXFileSystemSynchronizedRootGroup;
+                       exceptions = (
+                               0D54E4472F0A62D900A80EE7 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" build phase */,
+                       );
+                       path = DeepChordsSdk;
+                       sourceTree = "<group>";
+               };
+               0D54E0FF2F0A61E600A80EE7 /* DeepChordsSdkTests */ = {
+                       isa = PBXFileSystemSynchronizedRootGroup;
+                       exceptions = (
+                       );
+                       path = DeepChordsSdkTests;
+                       sourceTree = "<group>";
+               };
                3F887B9E2E38D8DC00C98658 /* ShenYin */ = {
                        isa = PBXFileSystemSynchronizedRootGroup;
                        exceptions = (
 /* End PBXFileSystemSynchronizedRootGroup section */
 
 /* Begin PBXFrameworksBuildPhase section */
+               0D54E0EC2F0A61E600A80EE7 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               644D1BB5EDD3EA1D77C57786 /* Pods_DeepChordsSdk.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                3F887B992E38D8DC00C98658 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               0D54E4482F0A62F700A80EE7 /* DeepChordsSdk.framework in Frameworks */,
                                F2E449CAD5874BE652A69B50 /* Pods_ShenYin.framework in Frameworks */,
-                               3F7602F12EFA8BAB00588C18 /* DeepChordsSdk.framework in Frameworks */,
-                               0D54E0612F0A5FDD00A80EE7 /* StarburstSdk.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                CE98543C79FAAB6CEF4CBFCA /* Pods-LingQi.release.xcconfig */,
                                5F5DE5910965D53C2B3405B0 /* Pods-ShenYin.debug.xcconfig */,
                                FBA7C30445BB0602D6B92F11 /* Pods-ShenYin.release.xcconfig */,
+                               5A92F7DC2CB6E6E69D2AB23E /* Pods-DeepChordsSdk.debug.xcconfig */,
+                               E7D3DF51BED56E93E4ED8102 /* Pods-DeepChordsSdk.release.xcconfig */,
                        );
                        path = Pods;
                        sourceTree = "<group>";
                                3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */,
                                3F887B9E2E38D8DC00C98658 /* ShenYin */,
                                3F8F68802EC1F25700FFC00B /* New Group */,
+                               0D54E0F02F0A61E600A80EE7 /* DeepChordsSdk */,
+                               0D54E0FF2F0A61E600A80EE7 /* DeepChordsSdkTests */,
                                3F887B9D2E38D8DC00C98658 /* Products */,
                                34A14A83ECF09370871C891F /* Pods */,
                                676B86A4BA2639E8694D56B4 /* Frameworks */,
-                               0D54E0602F0A5FDD00A80EE7 /* StarburstSdk.framework */,
                        );
                        sourceTree = "<group>";
                };
                        isa = PBXGroup;
                        children = (
                                3F887B9C2E38D8DC00C98658 /* ShenYin.app */,
+                               0D54E0EF2F0A61E600A80EE7 /* DeepChordsSdk.framework */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                        children = (
                                3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */,
                                3862D5561144E20721225B96 /* Pods_ShenYin.framework */,
+                               248D8B53B5A178ACA5867275 /* Pods_DeepChordsSdk.framework */,
                        );
                        name = Frameworks;
                        sourceTree = "<group>";
                };
 /* End PBXGroup section */
 
+/* Begin PBXHeadersBuildPhase section */
+               0D54E0EA2F0A61E600A80EE7 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXHeadersBuildPhase section */
+
 /* Begin PBXNativeTarget section */
+               0D54E0EE2F0A61E600A80EE7 /* DeepChordsSdk */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 0D54E1042F0A61E600A80EE7 /* Build configuration list for PBXNativeTarget "DeepChordsSdk" */;
+                       buildPhases = (
+                               4EDB33B100AD294830EAE06A /* [CP] Check Pods Manifest.lock */,
+                               0D54E0EA2F0A61E600A80EE7 /* Headers */,
+                               0D54E0EB2F0A61E600A80EE7 /* Sources */,
+                               0D54E0EC2F0A61E600A80EE7 /* Frameworks */,
+                               0D54E0ED2F0A61E600A80EE7 /* Resources */,
+                               0D54E4462F0A62D900A80EE7 /* Embed Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       fileSystemSynchronizedGroups = (
+                               0D54E0F02F0A61E600A80EE7 /* DeepChordsSdk */,
+                       );
+                       name = DeepChordsSdk;
+                       productName = DeepChordsSdk;
+                       productReference = 0D54E0EF2F0A61E600A80EE7 /* DeepChordsSdk.framework */;
+                       productType = "com.apple.product-type.framework";
+               };
                3F887B9B2E38D8DC00C98658 /* ShenYin */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 3F887BAF2E38D8DD00C98658 /* Build configuration list for PBXNativeTarget "ShenYin" */;
                                3F887B992E38D8DC00C98658 /* Frameworks */,
                                3F887B9A2E38D8DC00C98658 /* Resources */,
                                5A934A35F54A5620CFD3C08A /* [CP] Embed Pods Frameworks */,
-                               3F79C6162E6055E500EC38B9 /* Embed Frameworks */,
                        );
                        buildRules = (
                        );
                        dependencies = (
+                               0D54E1032F0A61E600A80EE7 /* PBXTargetDependency */,
                        );
                        fileSystemSynchronizedGroups = (
                                3F887B9E2E38D8DC00C98658 /* ShenYin */,
                                LastSwiftUpdateCheck = 1640;
                                LastUpgradeCheck = 1640;
                                TargetAttributes = {
+                                       0D54E0EE2F0A61E600A80EE7 = {
+                                               CreatedOnToolsVersion = 16.4;
+                                       };
                                        3F887B9B2E38D8DC00C98658 = {
                                                CreatedOnToolsVersion = 16.4;
                                        };
                        projectRoot = "";
                        targets = (
                                3F887B9B2E38D8DC00C98658 /* ShenYin */,
+                               0D54E0EE2F0A61E600A80EE7 /* DeepChordsSdk */,
                        );
                };
 /* End PBXProject section */
 
 /* Begin PBXResourcesBuildPhase section */
+               0D54E0ED2F0A61E600A80EE7 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                3F887B9A2E38D8DC00C98658 /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-               5A934A35F54A5620CFD3C08A /* [CP] Embed Pods Frameworks */ = {
+               4EDB33B100AD294830EAE06A /* [CP] Check Pods Manifest.lock */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        );
                        inputFileListPaths = (
-                               "${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-input-files.xcfilelist",
                        );
                        inputPaths = (
+                               "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+                               "${PODS_ROOT}/Manifest.lock",
                        );
-                       name = "[CP] Embed Pods Frameworks";
+                       name = "[CP] Check Pods Manifest.lock";
                        outputFileListPaths = (
-                               "${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-output-files.xcfilelist",
                        );
                        outputPaths = (
+                               "$(DERIVED_FILE_DIR)/Pods-DeepChordsSdk-checkManifestLockResult.txt",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+                       showEnvVarsInLog = 0;
+               };
+               5A934A35F54A5620CFD3C08A /* [CP] Embed Pods Frameworks */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputFileListPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+                       );
+                       name = "[CP] Embed Pods Frameworks";
+                       outputFileListPaths = (
+                               "${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-output-files.xcfilelist",
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
+               0D54E0EB2F0A61E600A80EE7 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                3F887B982E38D8DC00C98658 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                };
 /* End PBXSourcesBuildPhase section */
 
+/* Begin PBXTargetDependency section */
+               0D54E1032F0A61E600A80EE7 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 0D54E0EE2F0A61E600A80EE7 /* DeepChordsSdk */;
+                       targetProxy = 0D54E1022F0A61E600A80EE7 /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
 /* Begin XCBuildConfiguration section */
+               0D54E1052F0A61E600A80EE7 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = 5A92F7DC2CB6E6E69D2AB23E /* Pods-DeepChordsSdk.debug.xcconfig */;
+                       buildSettings = {
+                               BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
+                               CODE_SIGN_IDENTITY = "Apple Development";
+                               CODE_SIGN_STYLE = Automatic;
+                               CURRENT_PROJECT_VERSION = 1;
+                               DEVELOPMENT_TEAM = G23X75CJ67;
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               DYLIB_INSTALL_NAME_BASE = "@rpath";
+                               ENABLE_MODULE_VERIFIER = YES;
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "$(PROJECT_DIR)/DeepChordsSdk",
+                               );
+                               GENERATE_INFOPLIST_FILE = YES;
+                               INFOPLIST_KEY_NSHumanReadableCopyright = "";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+                               LD_RUNPATH_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "@executable_path/Frameworks",
+                                       "@loader_path/Frameworks",
+                               );
+                               MACH_O_TYPE = staticlib;
+                               MARKETING_VERSION = 1.0;
+                               MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+                               MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+                               OTHER_LDFLAGS = (
+                                       "$(inherited)",
+                                       "-l\"icucore\"",
+                                       "-framework",
+                                       "\"CFNetwork\"",
+                                       "-framework",
+                                       "\"Security\"",
+                                       "-framework",
+                                       "\"SocketRocket\"",
+                                       "-ObjC",
+                               );
+                               PRODUCT_BUNDLE_IDENTIFIER = lianzi.DeepChordsSdk;
+                               PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+                               SKIP_INSTALL = YES;
+                               SWIFT_EMIT_LOC_STRINGS = YES;
+                               SWIFT_INSTALL_MODULE = YES;
+                               SWIFT_INSTALL_OBJC_HEADER = NO;
+                               SWIFT_VERSION = 5.0;
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                               VERSIONING_SYSTEM = "apple-generic";
+                               VERSION_INFO_PREFIX = "";
+                       };
+                       name = Debug;
+               };
+               0D54E1062F0A61E600A80EE7 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = E7D3DF51BED56E93E4ED8102 /* Pods-DeepChordsSdk.release.xcconfig */;
+                       buildSettings = {
+                               BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
+                               CODE_SIGN_IDENTITY = "Apple Development";
+                               CODE_SIGN_STYLE = Automatic;
+                               CURRENT_PROJECT_VERSION = 1;
+                               DEVELOPMENT_TEAM = G23X75CJ67;
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               DYLIB_INSTALL_NAME_BASE = "@rpath";
+                               ENABLE_MODULE_VERIFIER = YES;
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "$(PROJECT_DIR)/DeepChordsSdk",
+                               );
+                               GENERATE_INFOPLIST_FILE = YES;
+                               INFOPLIST_KEY_NSHumanReadableCopyright = "";
+                               INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                               IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+                               LD_RUNPATH_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "@executable_path/Frameworks",
+                                       "@loader_path/Frameworks",
+                               );
+                               MACH_O_TYPE = staticlib;
+                               MARKETING_VERSION = 1.0;
+                               MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+                               MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+                               OTHER_LDFLAGS = (
+                                       "$(inherited)",
+                                       "-l\"icucore\"",
+                                       "-framework",
+                                       "\"CFNetwork\"",
+                                       "-framework",
+                                       "\"Security\"",
+                                       "-framework",
+                                       "\"SocketRocket\"",
+                                       "-ObjC",
+                               );
+                               PRODUCT_BUNDLE_IDENTIFIER = lianzi.DeepChordsSdk;
+                               PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+                               SKIP_INSTALL = YES;
+                               SWIFT_EMIT_LOC_STRINGS = YES;
+                               SWIFT_INSTALL_MODULE = YES;
+                               SWIFT_INSTALL_OBJC_HEADER = NO;
+                               SWIFT_VERSION = 5.0;
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                               VERSIONING_SYSTEM = "apple-generic";
+                               VERSION_INFO_PREFIX = "";
+                       };
+                       name = Release;
+               };
                3F887BB02E38D8DD00C98658 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = 5F5DE5910965D53C2B3405B0 /* Pods-ShenYin.debug.xcconfig */;
                                        "$(PROJECT_DIR)/ShenYin/SDKBleManager",
                                        "$(PROJECT_DIR)/ShenYin/Ota",
                                        "$(PROJECT_DIR)/ShenYin/Sdk/DcSdk/opus",
+                                       "$(PROJECT_DIR)/DeepChordsSdk",
                                );
                                GENERATE_INFOPLIST_FILE = YES;
                                INFOPLIST_FILE = ShenYin/Info.plist;
                                        "$(PROJECT_DIR)/ShenYin/SDKBleManager",
                                        "$(PROJECT_DIR)/ShenYin/Ota",
                                        "$(PROJECT_DIR)/ShenYin/Sdk/DcSdk/opus",
+                                       "$(PROJECT_DIR)/DeepChordsSdk",
                                );
                                GENERATE_INFOPLIST_FILE = YES;
                                INFOPLIST_FILE = ShenYin/Info.plist;
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
+               0D54E1042F0A61E600A80EE7 /* Build configuration list for PBXNativeTarget "DeepChordsSdk" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               0D54E1052F0A61E600A80EE7 /* Debug */,
+                               0D54E1062F0A61E600A80EE7 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                3F887B972E38D8DC00C98658 /* Build configuration list for PBXProject "ShenYin" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
diff --git a/ShenYin/ShenYin.xcodeproj/xcshareddata/xcschemes/DeepChordsSdk.xcscheme b/ShenYin/ShenYin.xcodeproj/xcshareddata/xcschemes/DeepChordsSdk.xcscheme
new file mode 100644 (file)
index 0000000..c27ba03
--- /dev/null
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1640"
+   version = "1.7">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES"
+      buildArchitectures = "Automatic">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "0D54E0EE2F0A61E600A80EE7"
+               BuildableName = "DeepChordsSdk.framework"
+               BlueprintName = "DeepChordsSdk"
+               ReferencedContainer = "container:ShenYin.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      shouldAutocreateTestPlan = "YES">
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Release"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "0D54E0EE2F0A61E600A80EE7"
+            BuildableName = "DeepChordsSdk.framework"
+            BlueprintName = "DeepChordsSdk"
+            ReferencedContainer = "container:ShenYin.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
index 7b6a0f6..f5114f2 100644 (file)
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES"
       shouldAutocreateTestPlan = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO"
+            parallelizable = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "0D54E0F82F0A61E600A80EE7"
+               BuildableName = "DeepChordsSdkTests.xctest"
+               BlueprintName = "DeepChordsSdkTests"
+               ReferencedContainer = "container:ShenYin.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
    </TestAction>
    <LaunchAction
       buildConfiguration = "Debug"
index 44c3dc7..b1846c8 100644 (file)
@@ -7,7 +7,4 @@
    <FileRef
       location = "group:Pods/Pods.xcodeproj">
    </FileRef>
-   <FileRef
-      location = "container:../DeepChordsSdk_iOS/DeepChordsSdk/Example/Example.xcodeproj">
-   </FileRef>
 </Workspace>
index 90e1243..7f5eeff 100644 (file)
 
 import Foundation
 import UIKit
-//import FSPagerView
+import FSPagerView
 
 
 final class MineBannerView: BaseView {
     private var dataArray = [BannerModel]()
-    //    private let pagerView = FSPagerView()
-    //    private let pageControl = FSPageControl()
+        private let pagerView = FSPagerView()
+        private let pageControl = FSPageControl()
     
     public func config(list:[BannerModel]) {
         self.dataArray = list
-//        self.pageControl.numberOfPages = dataArray.count
-//        self.pagerView.reloadData()
+        self.pageControl.numberOfPages = dataArray.count
+        self.pagerView.reloadData()
+    }
+
+    override func setupLayout() {
+        addSubview(pagerView)
+        addSubview(pageControl)
+
+        pagerView.snp.makeConstraints { (m) in
+            m.top.bottom.equalToSuperview()
+            m.left.right.equalToSuperview()
+        }
+        pageControl.snp.makeConstraints { (m) in
+            m.width.equalToSuperview()
+            m.height.equalTo(25)
+            m.bottom.equalToSuperview()
+            m.centerX.equalToSuperview()
+        }
+    }
+    override func setupViews() {
+        backgroundColor = .clear
+        clipsToBounds = true
+        pagerView.do { v in
+            v.dataSource = self
+            v.delegate = self
+            v.interitemSpacing = 18
+            v.bounces = false
+            v.isInfinite = true
+            v.automaticSlidingInterval = 4
+            v.itemSize = CGSize(width: kScreenWid - 36 , height: 126)
+            v.register(PictureViewCell.self, forCellWithReuseIdentifier: "PictureViewCell")
+        }
+        
+        pageControl.do { v in
+            v.contentHorizontalAlignment = .center
+            v.hidesForSinglePage = true
+            v.setFillColor(UIColor.white.withAlphaComponent(0.4), for: .normal)
+            v.setFillColor(.white, for: .selected)
+        }
+        config(list: BannerCache.shared.get())
     }
 }
-//    override func setupLayout() {
-//        addSubview(pagerView)
-//        addSubview(pageControl)
-//
-//        pagerView.snp.makeConstraints { (m) in
-//            m.top.bottom.equalToSuperview()
-//            m.left.right.equalToSuperview()
-//        }
-//        pageControl.snp.makeConstraints { (m) in
-//            m.width.equalToSuperview()
-//            m.height.equalTo(25)
-//            m.bottom.equalToSuperview()
-//            m.centerX.equalToSuperview()
-//        }
-//    }
-//    override func setupViews() {
-//        backgroundColor = .clear
-//        clipsToBounds = true
-//        pagerView.do { v in
-//            v.dataSource = self
-//            v.delegate = self
-//            v.interitemSpacing = 18
-//            v.bounces = false
-//            v.isInfinite = true
-//            v.automaticSlidingInterval = 4
-//            v.itemSize = CGSize(width: kScreenWid - 36 , height: 126)
-//            v.register(PictureViewCell.self, forCellWithReuseIdentifier: "PictureViewCell")
-//        }
-//        
-//        pageControl.do { v in
-//            v.contentHorizontalAlignment = .center
-//            v.hidesForSinglePage = true
-//            v.setFillColor(UIColor.white.withAlphaComponent(0.4), for: .normal)
-//            v.setFillColor(.white, for: .selected)
-//        }
-//        config(list: BannerCache.shared.get())
-//    }
-//}
-//
-//extension MineBannerView: FSPagerViewDataSource, FSPagerViewDelegate {
-//    func numberOfItems(in pagerView: FSPagerView) -> Int {
-//        return dataArray.count
-//    }
-//    
-//    func pagerView(_ pagerView: FSPagerView, cellForItemAt index: Int) -> FSPagerViewCell {
-//        let cell = pagerView.dequeueReusableCell(withReuseIdentifier: "PictureViewCell", at: index) as! PictureViewCell
-//        let model = dataArray[index]
-//        cell.picture.kf.setImage(with: model.cover.yc.asUrl)
-//        return cell
-//    }
-//    
-//    func pagerViewWillEndDragging(_ pagerView: FSPagerView, targetIndex: Int) {
-//        self.pageControl.currentPage = targetIndex
-//    }
-//    func pagerViewDidEndScrollAnimation(_ pagerView: FSPagerView) {
-//        self.pageControl.currentPage = pagerView.currentIndex
-//    }
-//    
-//    func pagerView(_ pagerView: FSPagerView, didSelectItemAt index: Int){
-//        let model = dataArray[index]
-////        if model.jumpType == 0 {
-////            if let url = model.jumpValue.fragmentUrl {
-////                let request = URLRequest(url: url)
-////                let params = BaseWebViewParams(request:request)
-////                let vc = BaseWebViewController(initData: params)
-////                UIViewController.yc.currentNav?.pushViewController(vc, animated: true)
-////            } //UIApplication.shared.canOpenURL(URL(string: ))
-////        }
-//        HttpClient.request(.bannerClick(bannerId: model.id)) { (model:BannerModelRoot,res) in
-//        }
-//        
-//        guard let url = model.url.yc.asUrl else{
-//            return
-//        }
-//        UIApplication.shared.open(url)
-//    }
-//}
 
-//
-//fileprivate class PictureViewCell: FSPagerViewCell {
-//    let picture = UIImageView()
-//    
-//    override init(frame: CGRect) {
-//        super.init(frame: frame)
-//        
-//        addSubview(picture)
-//        
-//        picture.snp.makeConstraints { (m) in
-//            m.edges.equalToSuperview()
-//        }
-//        
-//        picture.do { (v) in
-//            v.yc.setCornerRadius(8)
+extension MineBannerView: FSPagerViewDataSource, FSPagerViewDelegate {
+    func numberOfItems(in pagerView: FSPagerView) -> Int {
+        return dataArray.count
+    }
+    
+    func pagerView(_ pagerView: FSPagerView, cellForItemAt index: Int) -> FSPagerViewCell {
+        let cell = pagerView.dequeueReusableCell(withReuseIdentifier: "PictureViewCell", at: index) as! PictureViewCell
+        let model = dataArray[index]
+        cell.picture.kf.setImage(with: model.cover.yc.asUrl)
+        return cell
+    }
+    
+    func pagerViewWillEndDragging(_ pagerView: FSPagerView, targetIndex: Int) {
+        self.pageControl.currentPage = targetIndex
+    }
+    func pagerViewDidEndScrollAnimation(_ pagerView: FSPagerView) {
+        self.pageControl.currentPage = pagerView.currentIndex
+    }
+    
+    func pagerView(_ pagerView: FSPagerView, didSelectItemAt index: Int){
+        let model = dataArray[index]
+//        if model.jumpType == 0 {
+//            if let url = model.jumpValue.fragmentUrl {
+//                let request = URLRequest(url: url)
+//                let params = BaseWebViewParams(request:request)
+//                let vc = BaseWebViewController(initData: params)
+//                UIViewController.yc.currentNav?.pushViewController(vc, animated: true)
+//            } //UIApplication.shared.canOpenURL(URL(string: ))
 //        }
-////        picture.backgroundColor = .lightGray
-//    }
-//    
-//    required init?(coder aDecoder: NSCoder) {
-//        fatalError("init(coder:) has not been implemented")
-//    }
-//}
+        HttpClient.request(.bannerClick(bannerId: model.id)) { (model:BannerModelRoot,res) in
+        }
+        
+        guard let url = model.url.yc.asUrl else{
+            return
+        }
+        UIApplication.shared.open(url)
+    }
+}
+
+
+fileprivate class PictureViewCell: FSPagerViewCell {
+    let picture = UIImageView()
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        addSubview(picture)
+        
+        picture.snp.makeConstraints { (m) in
+            m.edges.equalToSuperview()
+        }
+        
+        picture.do { (v) in
+            v.yc.setCornerRadius(8)
+        }
+//        picture.backgroundColor = .lightGray
+    }
+    
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+}
index 8ffa418..bffe192 100644 (file)
@@ -2,6 +2,10 @@ source "https://gitee.com/mirrors/CocoaPods-Specs.git"
 platform :ios, '13.0'
 use_frameworks!
 
+target 'DeepChordsSdk' do
+  use_frameworks!
+  pod 'SocketRocket'
+end
 
 workspace 'ShenYin'
 project 'ShenYin.xcodeproj'
@@ -20,7 +24,7 @@ target 'ShenYin' do
   pod 'SVProgressHUD'#蒙版
   pod 'MBProgressHUD'#蒙版
   pod 'Kingfisher', '~> 6.0'#图片下载K
-#   pod 'FSPagerView'
+   pod 'FSPagerView'
    pod "TabPageViewController" #tabpage
    pod 'JXSegmentedView'
    pod 'JXPagingView/Paging'