joy playboy兼容性修改
authorliangzhenying <867174124@qq.com>
Sat, 17 Jan 2026 02:32:36 +0000 (10:32 +0800)
committerliangzhenying <867174124@qq.com>
Sat, 17 Jan 2026 02:32:36 +0000 (10:32 +0800)
35 files changed:
ShenYin/ShenYin.xcodeproj/project.pbxproj
ShenYin/ShenYin/Sdk/CCBleManager.swift
ShenYin/ShenYin/Sdk/CCDevice.swift
ShenYin/ShenYin/Sdk/DcSdk/CCBleManager.swift [new file with mode: 0644]
ShenYin/ShenYin/Sdk/DcSdk/CCDevice.swift [new file with mode: 0644]
ShenYin/ShenYin/Sdk/DcSdk/CCPage.swift [new file with mode: 0644]
ShenYin/ShenYin/Sdk/DcSdk/HomeDeviceVC.swift [moved from ShenYin/ShenYin/UI/Home/Device/HomeDeviceVC.swift with 100% similarity]
ShenYin/ShenYin/Sdk/JoySdk/CCBleManager.swift [new file with mode: 0644]
ShenYin/ShenYin/Sdk/JoySdk/CCDevice.swift
ShenYin/ShenYin/Sdk/JoySdk/CCPage.swift [new file with mode: 0644]
ShenYin/ShenYin/Sdk/JoySdk/JoySdkManager.swift
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemAI-Swift.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemAI.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemAIManager.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemCallManager.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemChatManager.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemDeviceManager.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemEnum.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemModel.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemParam.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemRecordManager.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemSIDeviceManager.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemSIManager.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Headers/JoyGemSubtitleManager.h [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Info.plist [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/JoyGemAI [new file with mode: 0755]
ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.abi.json [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.private.swiftinterface [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftinterface [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/Modules/module.modulemap [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/PrivacyInfo.xcprivacy [new file with mode: 0644]
ShenYin/framework/JoyGemAI.framework/_CodeSignature/CodeResources [new file with mode: 0644]

index c75d6f9..f192505 100644 (file)
@@ -8,13 +8,12 @@
 
 /* Begin PBXBuildFile section */
                30B13DEF1AA0E4C54D873276 /* Pods_playboy.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4F1BB919D567C3B6B0EBAA7 /* Pods_playboy.framework */; };
-               3F469CB12F0B539600121DBD /* DeepChordsSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D54E0EF2F0A61E600A80EE7 /* DeepChordsSdk.framework */; };
                3F8F58292EBCA2B800FFC00B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */; };
-               3FD1A2952F0BCACB00A62733 /* JLAudioUnitKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FD1A2912F0BC9D800A62733 /* JLAudioUnitKit.xcframework */; };
-               3FD1A2962F0BCACB00A62733 /* JLAudioUnitKit.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3FD1A2912F0BC9D800A62733 /* JLAudioUnitKit.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
                3FD1DFEB2F0E00BF00A62733 /* JLAudioUnitKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FD1A2912F0BC9D800A62733 /* JLAudioUnitKit.xcframework */; };
                3FD1DFED2F0E00BF00A62733 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */; };
                3FD1DFF02F0E00BF00A62733 /* JLAudioUnitKit.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3FD1A2912F0BC9D800A62733 /* JLAudioUnitKit.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+               3FEFE9072F1B252000D82F17 /* JoyGemAI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FEFE9062F1B252000D82F17 /* JoyGemAI.framework */; };
+               3FEFE9082F1B252000D82F17 /* JoyGemAI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3FEFE9062F1B252000D82F17 /* JoyGemAI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
                3FFB77C12F179F3100EF9A60 /* DeepChordsSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D54E0EF2F0A61E600A80EE7 /* DeepChordsSdk.framework */; };
                3FFB77C22F179F3100EF9A60 /* DeepChordsSdk.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0D54E0EF2F0A61E600A80EE7 /* DeepChordsSdk.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
                644D1BB5EDD3EA1D77C57786 /* Pods_DeepChordsSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 248D8B53B5A178ACA5867275 /* Pods_DeepChordsSdk.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
-               0D54E1022F0A61E600A80EE7 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 3F887B942E38D8DC00C98658 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 0D54E0EE2F0A61E600A80EE7;
-                       remoteInfo = DeepChordsSdk;
-               };
                3FD1DFE52F0E00BF00A62733 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 3F887B942E38D8DC00C98658 /* Project object */;
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
-               3F469CAF2F0B539400121DBD /* Embed Frameworks */ = {
+               3FD1DFEF2F0E00BF00A62733 /* Embed Frameworks */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 2147483647;
                        dstPath = "";
                        dstSubfolderSpec = 10;
                        files = (
-                               3FD1A2962F0BCACB00A62733 /* JLAudioUnitKit.xcframework in Embed Frameworks */,
+                               3FFB77C22F179F3100EF9A60 /* DeepChordsSdk.framework in Embed Frameworks */,
+                               3FD1DFF02F0E00BF00A62733 /* JLAudioUnitKit.xcframework in Embed Frameworks */,
                        );
                        name = "Embed Frameworks";
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               3FD1DFEF2F0E00BF00A62733 /* Embed Frameworks */ = {
+               3FEFE9092F1B252000D82F17 /* Embed Frameworks */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 2147483647;
                        dstPath = "";
                        dstSubfolderSpec = 10;
                        files = (
-                               3FFB77C22F179F3100EF9A60 /* DeepChordsSdk.framework in Embed Frameworks */,
-                               3FD1DFF02F0E00BF00A62733 /* JLAudioUnitKit.xcframework in Embed Frameworks */,
+                               3FEFE9082F1B252000D82F17 /* JoyGemAI.framework in Embed Frameworks */,
                        );
                        name = "Embed Frameworks";
                        runOnlyForDeploymentPostprocessing = 0;
@@ -88,6 +80,7 @@
                3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
                3FD1A2912F0BC9D800A62733 /* JLAudioUnitKit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = JLAudioUnitKit.xcframework; path = framework/JLAudioUnitKit.xcframework; sourceTree = "<group>"; };
                3FD1DFF42F0E00BF00A62733 /* playboy.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = playboy.app; sourceTree = BUILT_PRODUCTS_DIR; };
+               3FEFE9062F1B252000D82F17 /* JoyGemAI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JoyGemAI.framework; path = framework/JoyGemAI.framework; 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>"; };
                90FF0C8B0D4D6AE0933FA672 /* Pods_ShenYin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShenYin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                                Info.plist,
                                playboy.storyboard,
                                playboy.xcassets,
+                               Sdk/CCBleManager.swift,
                                Sdk/CCDevice.swift,
-                               Sdk/JoySdk/JoyCallRecord.swift,
-                               Sdk/JoySdk/JoyChat.swift,
-                               Sdk/JoySdk/JoyChinse2English.swift,
-                               Sdk/JoySdk/JoyDialog.swift,
-                               Sdk/JoySdk/JoyGemAI.framework,
-                               Sdk/JoySdk/JoyRecord.swift,
-                               Sdk/JoySdk/JoySdkManager.swift,
-                               Sdk/JoySdk/JoyTcty.swift,
-                               Sdk/JoySdk/VC/JoyCallingRecordVC.swift,
-                               Sdk/JoySdk/VC/JoyChatVC.swift,
-                               Sdk/JoySdk/VC/JoyChinese2EnglishVC.swift,
-                               Sdk/JoySdk/VC/JoyDialogTranlateVC.swift,
-                               Sdk/JoySdk/VC/JoyStereoCallVC.swift,
-                               Sdk/JoySdk/VC/JoyTctyVC.swift,
-                               Sdk/JoySdk/VC/JoyXclyVC.swift,
+                               Sdk/CCPage.swift,
+                               Sdk/DcSdk/CCBleManager.swift,
+                               Sdk/DcSdk/CCDevice.swift,
+                               Sdk/DcSdk/CCPage.swift,
+                               Sdk/DcSdk/DcBleManager.swift,
+                               Sdk/DcSdk/DcCall.swift,
+                               Sdk/DcSdk/DcChatManager.swift,
+                               Sdk/DcSdk/DcChinese2Enligsh.swift,
+                               Sdk/DcSdk/DcSdkManager.swift,
+                               Sdk/DcSdk/DcStereo.swift,
+                               Sdk/DcSdk/DcTcty.swift,
+                               Sdk/DcSdk/DcThly.swift,
+                               Sdk/DcSdk/DcXcly.swift,
+                               Sdk/DcSdk/HomeDeviceVC.swift,
+                               Sdk/DcSdk/OpusTools.swift,
+                               Sdk/DcSdk/VC/DcCallingRecordVC.swift,
+                               Sdk/DcSdk/VC/DcChatVC.swift,
+                               Sdk/DcSdk/VC/DcChinese2EnglishVC.swift,
+                               Sdk/DcSdk/VC/DcDialogTranslateVC.swift,
+                               Sdk/DcSdk/VC/DcStereoCallVC.swift,
+                               Sdk/DcSdk/VC/DcTctyVC.swift,
+                               Sdk/DcSdk/VC/DcXclyVC.swift,
                                "ShenYin copy-Info.plist",
                        );
                        target = 3F887B9B2E38D8DC00C98658 /* ShenYin */;
                                "/Localized: LaunchScreen.storyboard",
                                Assets.xcassets,
                                Info.plist,
+                               Sdk/CCBleManager.swift,
+                               Sdk/CCDevice.swift,
+                               Sdk/CCPage.swift,
+                               Sdk/JoySdk/CCBleManager.swift,
                                Sdk/JoySdk/CCDevice.swift,
+                               Sdk/JoySdk/CCPage.swift,
                                Sdk/JoySdk/JoyCallRecord.swift,
                                Sdk/JoySdk/JoyChat.swift,
                                Sdk/JoySdk/JoyChinse2English.swift,
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               3F469CB12F0B539600121DBD /* DeepChordsSdk.framework in Frameworks */,
                                F2E449CAD5874BE652A69B50 /* (null) in Frameworks */,
-                               3FD1A2952F0BCACB00A62733 /* JLAudioUnitKit.xcframework in Frameworks */,
+                               3FEFE9072F1B252000D82F17 /* JoyGemAI.framework in Frameworks */,
                                7A6613B4B617D6E71D34944C /* Pods_ShenYin.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                676B86A4BA2639E8694D56B4 /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               3FEFE9062F1B252000D82F17 /* JoyGemAI.framework */,
                                3FD1A2912F0BC9D800A62733 /* JLAudioUnitKit.xcframework */,
                                3F7602EA2EFA891200588C18 /* DeepChordsSdk.framework */,
                                248D8B53B5A178ACA5867275 /* Pods_DeepChordsSdk.framework */,
                                3F887B992E38D8DC00C98658 /* Frameworks */,
                                3F887B9A2E38D8DC00C98658 /* Resources */,
                                5A934A35F54A5620CFD3C08A /* [CP] Embed Pods Frameworks */,
-                               3F469CAF2F0B539400121DBD /* Embed Frameworks */,
+                               3FEFE9092F1B252000D82F17 /* Embed Frameworks */,
                        );
                        buildRules = (
                        );
                        dependencies = (
-                               0D54E1032F0A61E600A80EE7 /* PBXTargetDependency */,
                        );
                        fileSystemSynchronizedGroups = (
                                3F887B9E2E38D8DC00C98658 /* ShenYin */,
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
-               0D54E1032F0A61E600A80EE7 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 0D54E0EE2F0A61E600A80EE7 /* DeepChordsSdk */;
-                       targetProxy = 0D54E1022F0A61E600A80EE7 /* PBXContainerItemProxy */;
-               };
                3FD1DFE42F0E00BF00A62733 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 0D54E0EE2F0A61E600A80EE7 /* DeepChordsSdk */;
                                        "$(PROJECT_DIR)/DeepChordsSdk",
                                        "$(PROJECT_DIR)/ShenYin/Sdk/Ota",
                                        "$(PROJECT_DIR)/ShenYin/Sdk/JoySdk",
+                                       "$(PROJECT_DIR)/framework",
                                );
                                GENERATE_INFOPLIST_FILE = YES;
                                INFOPLIST_FILE = ShenYin/Info.plist;
                                        "$(PROJECT_DIR)/DeepChordsSdk",
                                        "$(PROJECT_DIR)/ShenYin/Sdk/Ota",
                                        "$(PROJECT_DIR)/ShenYin/Sdk/JoySdk",
+                                       "$(PROJECT_DIR)/framework",
                                );
                                GENERATE_INFOPLIST_FILE = YES;
                                INFOPLIST_FILE = ShenYin/Info.plist;
index dc631c2..f12a67b 100644 (file)
+////
+////  CCBleManager.swift
+////  ShenYin
+////
+////  Created by liangshi on 2025/12/25.
+////
 //
-//  CCBleManager.swift
-//  ShenYin
+//import UIKit
+//import CoreBluetooth
+//import AVFAudio
 //
-//  Created by liangshi on 2025/12/25.
+////#if FEATURE_X
+//import DeepChordsSdk
+////#endif
 //
-
-import UIKit
-import CoreBluetooth
-import AVFAudio
-
-//#if FEATURE_X
-import DeepChordsSdk
-//#endif
-
-
-class DCPeripheral{
-    var device:CBPeripheral!
-    var mac = ""
-    init(device: CBPeripheral!, mac: String = "") {
-        self.device = device
-        self.mac = mac
-    }
-}
-
-class CCBleManager: NSObject {
-    var discoverDeviceCallback: (([DCPeripheral]) -> Void)?
-    var didConnectDeviceCallback: ((DCPeripheral) -> Void)?
-    var conetedFailureCallback: ((DCPeripheral) -> Void)?
-    
-    private var centralManager: CBCentralManager!
-    var devices: [DCPeripheral] = []
-    var connectPeripheral: DCPeripheral?
-    static let shared = CCBleManager()
-    var isConnetd:Bool = false
-    
-    private override init() {
-        super.init()
-        centralManager = CBCentralManager(delegate: self, queue: nil)
-    }
-}
-extension CCBleManager:CBCentralManagerDelegate{
-    func centralManagerDidUpdateState(_ central: CBCentralManager) {
-        Logger.debug("蓝牙状态",central.state.rawValue)
-        switch central.state {
-        case.unknown:
-            break
-        case.resetting:
-            break
-        case.unsupported:
-            break
-        case.unauthorized:
-            break
-        case.poweredOff:
-            self.isConnetd = false
-            NotificationManager.post(type: .deviceValidChange, objtect: nil)
-            break
-        case.poweredOn:
-            //            startScanDevice()
-            checkConectState()
-            break
-        @unknown default:
-            break
-        }
-        OtaMananger.shared.otaManager.centralManagerDidUpdateState(central)
-    }
-    
-    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
-        if devices.map({ $0.device }).contains(peripheral) {
-            return
-        }
-        Logger.debug(peripheral)
-        
-        if let name = peripheral.name,name.hasPrefix("AI") {
-            let mac = DcSdkManager.getMac(advertisementData) ?? ""
-            devices.append(DCPeripheral(device: peripheral,mac: mac))
-            discoverDeviceCallback?(devices)
-        }
-        else{
-//            let mac = JoySdkManager.getMac(advertisementData) ?? ""
+//
+//class DCPeripheral{
+//    var device:CBPeripheral!
+//    var mac = ""
+//    init(device: CBPeripheral!, mac: String = "") {
+//        self.device = device
+//        self.mac = mac
+//    }
+//}
+//
+//class CCBleManager: NSObject {
+//    var discoverDeviceCallback: (([DCPeripheral]) -> Void)?
+//    var didConnectDeviceCallback: ((DCPeripheral) -> Void)?
+//    var conetedFailureCallback: ((DCPeripheral) -> Void)?
+//    
+//    private var centralManager: CBCentralManager!
+//    var devices: [DCPeripheral] = []
+//    var connectPeripheral: DCPeripheral?
+//    static let shared = CCBleManager()
+//    var isConnetd:Bool = false
+//    
+//    private override init() {
+//        super.init()
+//        centralManager = CBCentralManager(delegate: self, queue: nil)
+//    }
+//}
+//extension CCBleManager:CBCentralManagerDelegate{
+//    func centralManagerDidUpdateState(_ central: CBCentralManager) {
+//        Logger.debug("蓝牙状态",central.state.rawValue)
+//        switch central.state {
+//        case.unknown:
+//            break
+//        case.resetting:
+//            break
+//        case.unsupported:
+//            break
+//        case.unauthorized:
+//            break
+//        case.poweredOff:
+//            self.isConnetd = false
+//            NotificationManager.post(type: .deviceValidChange, objtect: nil)
+//            break
+//        case.poweredOn:
+//            //            startScanDevice()
+//            checkConectState()
+//            break
+//        @unknown default:
+//            break
+//        }
+//        OtaMananger.shared.otaManager.centralManagerDidUpdateState(central)
+//    }
+//    
+//    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
+//        if devices.map({ $0.device }).contains(peripheral) {
+//            return
+//        }
+//        Logger.debug(peripheral)
+//        
+//        if let name = peripheral.name,name.hasPrefix("AI") {
+//            let mac = DcSdkManager.getMac(advertisementData) ?? ""
 //            devices.append(DCPeripheral(device: peripheral,mac: mac))
 //            discoverDeviceCallback?(devices)
-        }
+//        }
+//        else{
+////            let mac = JoySdkManager.getMac(advertisementData) ?? ""
+////            devices.append(DCPeripheral(device: peripheral,mac: mac))
+////            discoverDeviceCallback?(devices)
+//        }
+////        if CCDevice.isJoy{
+////            let mac = JoySdkManager.getMac(advertisementData) ?? ""
+////            devices.append(DCPeripheral(device: peripheral,mac: mac))
+////            discoverDeviceCallback?(devices)
+////        }
+////        else{
+////            let mac = DcSdkManager.getMac(advertisementData) ?? ""
+////            devices.append(DCPeripheral(device: peripheral,mac: mac))
+////            discoverDeviceCallback?(devices)
+////        }
+//    }
+//    
+//    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
+//        stopScanDevice()
+//        Logger.debug("蓝牙已连接 \(peripheral)")
+//        peripheral.delegate = self
 //        if CCDevice.isJoy{
-//            let mac = JoySdkManager.getMac(advertisementData) ?? ""
-//            devices.append(DCPeripheral(device: peripheral,mac: mac))
-//            discoverDeviceCallback?(devices)
+////            peripheral.discoverServices([CBUUID(string: JoySdkManager.serviceUUID),CBUUID(string: OtaMananger.otaServiceUUId)]);
 //        }
 //        else{
-//            let mac = DcSdkManager.getMac(advertisementData) ?? ""
-//            devices.append(DCPeripheral(device: peripheral,mac: mac))
-//            discoverDeviceCallback?(devices)
+//            DCBleManager.shared.centralManager(central, didConnect: peripheral)
+//            peripheral.discoverServices([CBUUID(string: DCBleManager.serviceUUID),CBUUID(string: OtaMananger.otaServiceUUId)]);
+//        }
+//    }
+//    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
+//        Logger.debug("peripheral: %@ failed to connect", peripheral)
+//        conetedFailureCallback?(connectPeripheral!)
+//    }
+//    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
+//        Logger.debug("蓝牙已断开 \(peripheral)")
+//        YLprogressHUD.showAutoHiden("蓝牙已断开".l10n)
+//        self.isConnetd = false
+//        if CCDevice.isJoy{
 //        }
-    }
-    
-    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
-        stopScanDevice()
-        Logger.debug("蓝牙已连接 \(peripheral)")
-        peripheral.delegate = self
-        if CCDevice.isJoy{
-//            peripheral.discoverServices([CBUUID(string: JoySdkManager.serviceUUID),CBUUID(string: OtaMananger.otaServiceUUId)]);
-        }
-        else{
-            DCBleManager.shared.centralManager(central, didConnect: peripheral)
-            peripheral.discoverServices([CBUUID(string: DCBleManager.serviceUUID),CBUUID(string: OtaMananger.otaServiceUUId)]);
-        }
-    }
-    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
-        Logger.debug("peripheral: %@ failed to connect", peripheral)
-        conetedFailureCallback?(connectPeripheral!)
-    }
-    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
-        Logger.debug("蓝牙已断开 \(peripheral)")
-        YLprogressHUD.showAutoHiden("蓝牙已断开".l10n)
-        self.isConnetd = false
-        if CCDevice.isJoy{
+//        else{
 //            DCBleManager.shared.centralManager(central, didDisconnectPeripheral: peripheral, error: nil)
-        }
-        NotificationManager.post(type: .deviceValidChange, objtect: nil)
-        OtaMananger.shared.otaManager.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
-        checkConectState()
-    }
-}
-
-extension CCBleManager: CBPeripheralDelegate {
-    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
-        Logger.debug("发现服务成功")
-        for service in peripheral.services! {
-            Logger.debug("peripheral service: %@", service)
-            peripheral.discoverCharacteristics(nil, for: service)
-        }
-    }
-    
-    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
-        if CCDevice.isJoy{
-//            if (service.uuid.uuidString == JoySdkManager.serviceUUID) {
-//                JoySdkManager.shared.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
-//            }
-//            else if service.uuid.uuidString == OtaMananger.otaServiceUUId{
-//                OtaMananger.shared.otaManager.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
-//            }
-        }
-        else{
-            DCBleManager.shared.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
-        }
-    }
-    
-    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: (any Error)?) {
-        if CCDevice.isJoy{
-//            if (characteristic.isNotifying == true && characteristic.service?.uuid.uuidString == JoySdkManager.serviceUUID && characteristic.uuid.uuidString == JoySdkManager.notifyUUID) {
-//                Logger.debug("特征使能成功")
-//                JoySdkManager.shared.bleConnected()
-//            }
-//            if OtaMananger.isOtadata(characteristic){
-//                OtaMananger.shared.otaManager.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
+//        }
+//        NotificationManager.post(type: .deviceValidChange, objtect: nil)
+//        OtaMananger.shared.otaManager.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
+//        checkConectState()
+//    }
+//}
+//
+//extension CCBleManager: CBPeripheralDelegate {
+//    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
+//        Logger.debug("发现服务成功")
+//        for service in peripheral.services! {
+//            Logger.debug("peripheral service: %@", service)
+//            peripheral.discoverCharacteristics(nil, for: service)
+//        }
+//    }
+//    
+//    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
+//        if CCDevice.isJoy{
+////            if (service.uuid.uuidString == JoySdkManager.serviceUUID) {
+////                JoySdkManager.shared.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
+////            }
+////            else if service.uuid.uuidString == OtaMananger.otaServiceUUId{
+////                OtaMananger.shared.otaManager.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
+////            }
+//        }
+//        else{
+//            DCBleManager.shared.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
+//        }
+//    }
+//    
+//    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: (any Error)?) {
+//        if CCDevice.isJoy{
+////            if (characteristic.isNotifying == true && characteristic.service?.uuid.uuidString == JoySdkManager.serviceUUID && characteristic.uuid.uuidString == JoySdkManager.notifyUUID) {
+////                Logger.debug("特征使能成功")
+////                JoySdkManager.shared.bleConnected()
+////            }
+////            if OtaMananger.isOtadata(characteristic){
+////                OtaMananger.shared.otaManager.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
+////            }
+//        }
+//    }
+//    
+//    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
+//        //        Logger.debug("收到数据 ===uUId ",characteristic.uuid)
+//        if CCDevice.isJoy{
+////            if OtaMananger.isOtadata(characteristic){
+////                if let _ = characteristic.value,error == nil {
+////                    OtaMananger.shared.otaManager.peripheral(peripheral, didUpdateValueFor: characteristic)
+////                }
+////                else{
+////                    Logger.debug("ota 收到数据 ===\(characteristic.uuid)","无数据")
+////                }
+////            }
+////            else {
+////                //MARK: 需要配置传入数据
+////                JoySdkManager.shared.receiveValue(characteristic)
+////            }
+//        }
+//        else{
+//            DCBleManager.shared.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
+//        }
+//    }
+//    
+//    func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) {
+//        // Accessory's GATT database has updated. Refresh your local cache (if any)
+//    }
+//    
+//    func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: (any Error)?) {
+//        
+//    }
+//}
+//
+//extension CCBleManager{
+//    func startScanDevice() {
+//        //        centralManager.stopScan()
+//        Logger.debug("扫描中...")
+//        Logger.debug("蓝牙状态",centralManager.state.rawValue)
+//        devices = []
+//        //        let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)])
+//        //        Logger.debug("已连接设备",list)
+//        //        for item in list {
+//        //            if let mac = DeviceCache.shared.getMac(item.identifier.uuidString){
+//        //                devices.append(DCPeripheral(device: item,mac: mac))
+//        //            }
+//        //        }
+//        if CCDevice.isJoy{
+////            centralManager.scanForPeripherals(withServices: [CBUUID(string: JoySdkManager.serviceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
+//        }
+//        else{
+//            centralManager.scanForPeripherals(withServices: [CBUUID(string: DCBleManager.serviceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
+//        }
+//        discoverDeviceCallback?(devices)
+//    }
+//    
+//    func stopScanDevice() {
+//        centralManager.stopScan()
+//    }
+//    
+//    func connectPeripheral(_ peripheral: DCPeripheral) {
+//        connectPeripheral = peripheral
+//        if let name = peripheral.device.name,name.hasPrefix("AI") {
+//            CCDevice.isJoy = false
+//        }
+//        else{
+//            CCDevice.isJoy = true
+//        }
+//        CCDevice.initSdk()
+//        Logger.debug(peripheral.device.name ?? "","连接中...")
+//        centralManager.connect(peripheral.device, options: [CBConnectPeripheralOptionEnableTransportBridgingKey:true])
+//    }
+//    
+//    func cancel() {
+//        guard let peripheral = connectPeripheral else { return  }
+//        if self.isConnetd {
+//            self.isConnetd = false
+//            centralManager.cancelPeripheralConnection(peripheral.device)
+//        }
+//        
+//        NotificationManager.post(type: .deviceValidChange, objtect: nil)
+//        connectPeripheral = nil
+//    }
+//    func unbind(_ peripheral: DCPeripheral){
+//        if let mac = connectPeripheral?.mac ,peripheral.mac == mac{
+//            cancel()
+//        }
+//    }
+//}
+//
+//extension CCBleManager{
+//    func joySdkSend(_ data: Data, with characteristic: CBCharacteristic) {
+//        if let connectPeripheral = connectPeripheral{
+//            connectPeripheral.device.writeValue(data, for: characteristic, type:.withoutResponse)
+//        }
+//    }
+//}
+//
+//extension CCBleManager{
+//    func isConected(mac:String)->Bool{
+//        guard let device = connectPeripheral else { return false }
+//        if device.mac == mac {
+//            return isConnetd
+//        }
+//        else{
+//            return false
+//        }
+//    }
+//    
+//    //    #连接有问题,应当获取设置里面已连接的设备
+//    func connect(mac:String, finished:@escaping ((Bool) -> Void)){
+//        CCBleManager.shared.cancel()
+//        CCBleManager.shared.discoverDeviceCallback = { list in
+//            if list.count <= 0 {
+//                return
 //            }
-        }
-    }
-    
-    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
-        //        Logger.debug("收到数据 ===uUId ",characteristic.uuid)
-        if CCDevice.isJoy{
-//            if OtaMananger.isOtadata(characteristic){
-//                if let _ = characteristic.value,error == nil {
-//                    OtaMananger.shared.otaManager.peripheral(peripheral, didUpdateValueFor: characteristic)
+//            for item in list {
+//                if item.mac == mac {
+//                    CCBleManager.shared.connectPeripheral(item)
+//                    break
 //                }
-//                else{
-//                    Logger.debug("ota 收到数据 ===\(characteristic.uuid)","无数据")
-//                }
-//            }
-//            else {
-//                //MARK: 需要配置传入数据
-//                JoySdkManager.shared.receiveValue(characteristic)
 //            }
-        }
-        else{
-            DCBleManager.shared.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
-        }
-    }
-    
-    func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) {
-        // Accessory's GATT database has updated. Refresh your local cache (if any)
-    }
-    
-    func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: (any Error)?) {
-        
-    }
-}
-
-extension CCBleManager{
-    func startScanDevice() {
-        //        centralManager.stopScan()
-        Logger.debug("扫描中...")
-        Logger.debug("蓝牙状态",centralManager.state.rawValue)
-        devices = []
-        //        let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)])
-        //        Logger.debug("已连接设备",list)
-        //        for item in list {
-        //            if let mac = DeviceCache.shared.getMac(item.identifier.uuidString){
-        //                devices.append(DCPeripheral(device: item,mac: mac))
-        //            }
-        //        }
-        if CCDevice.isJoy{
-//            centralManager.scanForPeripherals(withServices: [CBUUID(string: JoySdkManager.serviceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
-        }
-        else{
-            centralManager.scanForPeripherals(withServices: [CBUUID(string: DCBleManager.serviceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
-        }
-        discoverDeviceCallback?(devices)
-    }
-    
-    func stopScanDevice() {
-        centralManager.stopScan()
-    }
-    
-    func connectPeripheral(_ peripheral: DCPeripheral) {
-        connectPeripheral = peripheral
-        if let name = peripheral.device.name,name.hasPrefix("AI") {
-            CCDevice.isJoy = false
-        }
-        else{
-            CCDevice.isJoy = true
-        }
-        CCDevice.initSdk()
-        Logger.debug(peripheral.device.name ?? "","连接中...")
-        centralManager.connect(peripheral.device, options: [CBConnectPeripheralOptionEnableTransportBridgingKey:true])
-    }
-    
-    func cancel() {
-        guard let peripheral = connectPeripheral else { return  }
-        if self.isConnetd {
-            self.isConnetd = false
-            centralManager.cancelPeripheralConnection(peripheral.device)
-        }
-        
-        NotificationManager.post(type: .deviceValidChange, objtect: nil)
-        connectPeripheral = nil
-    }
-    func unbind(_ peripheral: DCPeripheral){
-        if let mac = connectPeripheral?.mac ,peripheral.mac == mac{
-            cancel()
-        }
-    }
-}
-
-extension CCBleManager{
-    func joySdkSend(_ data: Data, with characteristic: CBCharacteristic) {
-        if let connectPeripheral = connectPeripheral{
-            connectPeripheral.device.writeValue(data, for: characteristic, type:.withoutResponse)
-        }
-    }
-}
-
-extension CCBleManager{
-    func isConected(mac:String)->Bool{
-        guard let device = connectPeripheral else { return false }
-        if device.mac == mac {
-            return isConnetd
-        }
-        else{
-            return false
-        }
-    }
-    
-    //    #连接有问题,应当获取设置里面已连接的设备
-    func connect(mac:String, finished:@escaping ((Bool) -> Void)){
-        CCBleManager.shared.cancel()
-        CCBleManager.shared.discoverDeviceCallback = { list in
-            if list.count <= 0 {
-                return
-            }
-            for item in list {
-                if item.mac == mac {
-                    CCBleManager.shared.connectPeripheral(item)
-                    break
-                }
-            }
-        }
-        CCBleManager.shared.didConnectDeviceCallback = { device in
-            finished(true)
-        }
-        CCBleManager.shared.conetedFailureCallback = {  device in
-            finished(false)
-        }
-        CCBleManager.shared.startScanDevice()
-    }
-    
-    func checkSettingsConnected()->[CBPeripheral]{
-        if CCDevice.isJoy {
-//            let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: JoySdkManager.serviceUUID)])
+//        }
+//        CCBleManager.shared.didConnectDeviceCallback = { device in
+//            finished(true)
+//        }
+//        CCBleManager.shared.conetedFailureCallback = {  device in
+//            finished(false)
+//        }
+//        CCBleManager.shared.startScanDevice()
+//    }
+//    
+//    func checkSettingsConnected()->[CBPeripheral]{
+//        if CCDevice.isJoy {
+////            let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: JoySdkManager.serviceUUID)])
+////            Logger.debug("已连接设备",list)
+////            return list
+//            return []
+//        }
+//        else{
+//            let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: DCBleManager.serviceUUID)])
 //            Logger.debug("已连接设备",list)
 //            return list
-            return []
-        }
-        else{
-            let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: DCBleManager.serviceUUID)])
-            Logger.debug("已连接设备",list)
-            return list
-        }
-    }
-}
-
-extension CCBleManager{
-    func checkConectState(){
-        guard let mac = connectPeripheral?.mac else {
-            return
-        }
-        if isConnetd {
-            return
-        }
-        connect(mac: mac) {result in
-        }
-        
-        DispatchQueue.main.asyncAfter(deadline:.now() + 10) {
-            self.checkConectState()
-        }
-    }
-}
+//        }
+//    }
+//}
+//
+//extension CCBleManager{
+//    func checkConectState(){
+//        guard let mac = connectPeripheral?.mac else {
+//            return
+//        }
+//        if isConnetd {
+//            return
+//        }
+//        connect(mac: mac) {result in
+//        }
+//        
+//        DispatchQueue.main.asyncAfter(deadline:.now() + 10) {
+//            self.checkConectState()
+//        }
+//    }
+//}
index 60fd7ea..c008fd7 100644 (file)
@@ -4,13 +4,13 @@
 //
 //  Created by liangshi on 2025/12/25.
 //
-//import JoyGemAI
+import JoyGemAI
 import DeepChordsSdk
 class CCDevice{
-    static var isJoy = false
+    static var isJoy = true
     static func initSdk(){
         if CCDevice.isJoy {
-//            JoySdkManager.shared.setupSdk()
+            JoySdkManager.shared.setupSdk()
         }
         else{
             DcSdkManager.shared.initSdk()
@@ -18,12 +18,12 @@ class CCDevice{
     }
     static func translate(text:String,from:String,to:String,finished:@escaping ((stream:String,finish:Bool)?)->Void){
         if isJoy {
-//            JoyGemAIManager.shared().cancelTranslateRequest()
-//            JoyGemAIManager.shared().translate(text, from: from, to: to) { result, finish in
-//                finished((result,finish))
-//            } error: { error in
-//                finished(nil)
-//            }
+            JoyGemAIManager.shared().cancelTranslateRequest()
+            JoyGemAIManager.shared().translate(text, from: from, to: to) { result, finish in
+                finished((result,finish))
+            } error: { error in
+                finished(nil)
+            }
         }
         else{
             DCText.cancelTranslateByTextWithSplit()
@@ -34,12 +34,12 @@ class CCDevice{
     }
     static func summary(text:String,finished:@escaping ((stream:String,finish:Bool)?)->Void){
         if isJoy {
-//            JoyGemAIManager.shared().cancelSummaryRequest()
-//            JoyGemAIManager.shared().summary(text) { text, finish in
-//                finished((text,finish))
-//            } error: { error in
-//                finished(nil)
-//            }
+            JoyGemAIManager.shared().cancelSummaryRequest()
+            JoyGemAIManager.shared().summary(text) { text, finish in
+                finished((text,finish))
+            } error: { error in
+                finished(nil)
+            }
         }
         else{
             DCText.cancelSummaryByTextWithSplit()
@@ -52,20 +52,20 @@ class CCDevice{
 extension CCDevice{
     static func findHeadphone(_ mode:FindType){
         if CCDevice.isJoy {
-//            var value:JoyGemFindHeadphoneMode = .all
-//            switch mode {
-//            case .left:
-//                value = .left
-//            case .right:
-//                value = .right
-//            case .cancel:
-//                value = .cancel
-//            case .all:
-//                value = .all
-//            }
-//            JoyGemAIManager.shared().device.findHeadphone(value) { err in
-//                Logger.debug("findHeadphone:\(err)");
-//            }
+            var value:JoyGemFindHeadphoneMode = .all
+            switch mode {
+            case .left:
+                value = .left
+            case .right:
+                value = .right
+            case .cancel:
+                value = .cancel
+            case .all:
+                value = .all
+            }
+            JoyGemAIManager.shared().device.findHeadphone(value) { err in
+                Logger.debug("findHeadphone:\(err)");
+            }
         }
         else{
             let value:UInt8 = mode == .cancel ? 0:1
@@ -75,27 +75,27 @@ extension CCDevice{
     }
     static func getEQMode(finished:@escaping (ModeEffectsType?)->Void){
         if CCDevice.isJoy {
-//            JoyGemAIManager.shared().device.getEQMode { mode in
-//                var value:ModeEffectsType = .normal
-//                switch mode {
-//                case .normal:
-//                    value = .normal
-//                case .pop:
-//                    value = .pop
-//                case .classic:
-//                    value = .classic
-//                case .rock:
-//                    value = .rock
-//                case .jazz:
-//                    value = .jazz
-//                case .custom:
-//                    value = .custom
-//                }
-//                finished(value)
-//            } error: { err in
-//                Logger.debug("getEQMode:\(err)");
-//                finished(nil)
-//            }
+            JoyGemAIManager.shared().device.getEQMode { mode in
+                var value:ModeEffectsType = .normal
+                switch mode {
+                case .normal:
+                    value = .normal
+                case .pop:
+                    value = .pop
+                case .classic:
+                    value = .classic
+                case .rock:
+                    value = .rock
+                case .jazz:
+                    value = .jazz
+                case .custom:
+                    value = .custom
+                }
+                finished(value)
+            } error: { err in
+                Logger.debug("getEQMode:\(err)");
+                finished(nil)
+            }
         }
         else{
             /// type, 0x00(正常模式)
@@ -130,25 +130,25 @@ extension CCDevice{
     }
     static func setEQMode(_ type:ModeEffectsType){
         if CCDevice.isJoy {
-//            var value:JoyGemEQMode = .normal
-//            switch type {
-//            case .normal:
-//                value = .normal
-//            case .pop:
-//                value = .pop
-//            case .classic:
-//                value = .classic
-//            case .rock:
-//                value = .rock
-//            case .jazz:
-//                value = .jazz
-//            case .custom:
-//                value = .custom
-//            }
-//            
-//            JoyGemAIManager.shared().device.setEQMode(value) { err in
-//                Logger.debug("setEQMode:\(err)");
-//            }
+            var value:JoyGemEQMode = .normal
+            switch type {
+            case .normal:
+                value = .normal
+            case .pop:
+                value = .pop
+            case .classic:
+                value = .classic
+            case .rock:
+                value = .rock
+            case .jazz:
+                value = .jazz
+            case .custom:
+                value = .custom
+            }
+            
+            JoyGemAIManager.shared().device.setEQMode(value) { err in
+                Logger.debug("setEQMode:\(err)");
+            }
         }else{
             let value:UInt8 = UInt8(type.rawValue)
             DCDevice.shared.setEQ(type: value) { success in
@@ -160,13 +160,13 @@ extension CCDevice{
     
     static func getCustomEQ(finished:@escaping ([NSNumber]?)->Void){
         if CCDevice.isJoy {
-//            JoyGemAIManager.shared().device.getCustomEQ { eq in
-//                Logger.debug("getCustomEQ:\(eq)");
-//                finished(eq.bands)
-//            } error: { err in
-//                Logger.debug("getCustomEQ:\(err)");
-//                finished(nil)
-//            }
+            JoyGemAIManager.shared().device.getCustomEQ { eq in
+                Logger.debug("getCustomEQ:\(eq)");
+                finished(eq.bands)
+            } error: { err in
+                Logger.debug("getCustomEQ:\(err)");
+                finished(nil)
+            }
         }
         else{
             DCDevice.shared.getEQ { (arg0,result) in
@@ -186,9 +186,9 @@ extension CCDevice{
     }
     static func resetCustomEQ(){
         if CCDevice.isJoy {
-//            JoyGemAIManager.shared().device.resetCustomEQ { err in
-//                Logger.debug("resetCustomEQ:\(err)");
-//            }
+            JoyGemAIManager.shared().device.resetCustomEQ { err in
+                Logger.debug("resetCustomEQ:\(err)");
+            }
         }
         else{
             let list = [
@@ -209,9 +209,9 @@ extension CCDevice{
     }
     static func setCustomEQ(index:Int,value:Int){
         if CCDevice.isJoy {
-//            JoyGemAIManager.shared().device.setCustomEQ(UInt(index), withGain: value) { err in
-//                Logger.debug("setCustomEQ:\(err)");
-//            }
+            JoyGemAIManager.shared().device.setCustomEQ(UInt(index), withGain: value) { err in
+                Logger.debug("setCustomEQ:\(err)");
+            }
         }
         else{
             DCDevice.shared.setCustomEQ(index: UInt8(index), value: value) {result in
@@ -238,12 +238,12 @@ extension CCDevice{
 //    }
     static func getDN(finished:@escaping ((_ mac:String?)->Void)) {
         if CCDevice.isJoy {
-//            JoyGemAIManager.shared().device.getDN { deviceName in
-//                finished(deviceName)
-//            } error: { error in
-//                Logger.debug("获取dn失败","\(error!.localizedDescription)")
-//                finished(nil)
-//            }
+            JoyGemAIManager.shared().device.getDN { deviceName in
+                finished(deviceName)
+            } error: { error in
+                Logger.debug("获取dn失败","\(error!.localizedDescription)")
+                finished(nil)
+            }
         }
         else{
             let dn = DCText.getDeviceName()
@@ -252,12 +252,12 @@ extension CCDevice{
     }
     static func getVersion(finished:@escaping ((_ version:String?)->Void)) {
         if CCDevice.isJoy {
-//            JoyGemAIManager.shared().device.software { version in
-//                finished(version)
-//            } error: { error in
-//                Logger.debug("\(error!.localizedDescription)");
-//                finished(nil)
-//            }
+            JoyGemAIManager.shared().device.software { version in
+                finished(version)
+            } error: { error in
+                Logger.debug("\(error!.localizedDescription)");
+                finished(nil)
+            }
         }
         else{
             DCDevice.shared.getSoftVersion {result in
diff --git a/ShenYin/ShenYin/Sdk/DcSdk/CCBleManager.swift b/ShenYin/ShenYin/Sdk/DcSdk/CCBleManager.swift
new file mode 100644 (file)
index 0000000..ee13a92
--- /dev/null
@@ -0,0 +1,321 @@
+//
+//  CCBleManager.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/12/25.
+//
+
+import UIKit
+import CoreBluetooth
+import AVFAudio
+
+//#if FEATURE_X
+import DeepChordsSdk
+//#endif
+
+
+class DCPeripheral{
+    var device:CBPeripheral!
+    var mac = ""
+    init(device: CBPeripheral!, mac: String = "") {
+        self.device = device
+        self.mac = mac
+    }
+}
+
+class CCBleManager: NSObject {
+    var discoverDeviceCallback: (([DCPeripheral]) -> Void)?
+    var didConnectDeviceCallback: ((DCPeripheral) -> Void)?
+    var conetedFailureCallback: ((DCPeripheral) -> Void)?
+    
+    private var centralManager: CBCentralManager!
+    var devices: [DCPeripheral] = []
+    var connectPeripheral: DCPeripheral?
+    static let shared = CCBleManager()
+    var isConnetd:Bool = false
+    
+    private override init() {
+        super.init()
+        centralManager = CBCentralManager(delegate: self, queue: nil)
+    }
+}
+extension CCBleManager:CBCentralManagerDelegate{
+    func centralManagerDidUpdateState(_ central: CBCentralManager) {
+        Logger.debug("蓝牙状态",central.state.rawValue)
+        switch central.state {
+        case.unknown:
+            break
+        case.resetting:
+            break
+        case.unsupported:
+            break
+        case.unauthorized:
+            break
+        case.poweredOff:
+            self.isConnetd = false
+            NotificationManager.post(type: .deviceValidChange, objtect: nil)
+            break
+        case.poweredOn:
+            //            startScanDevice()
+            checkConectState()
+            break
+        @unknown default:
+            break
+        }
+        OtaMananger.shared.otaManager.centralManagerDidUpdateState(central)
+    }
+    
+    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
+        if devices.map({ $0.device }).contains(peripheral) {
+            return
+        }
+        Logger.debug(peripheral)
+        
+        if let name = peripheral.name,name.hasPrefix("AI") {
+            let mac = DcSdkManager.getMac(advertisementData) ?? ""
+            devices.append(DCPeripheral(device: peripheral,mac: mac))
+            discoverDeviceCallback?(devices)
+        }
+        else{
+//            let mac = JoySdkManager.getMac(advertisementData) ?? ""
+//            devices.append(DCPeripheral(device: peripheral,mac: mac))
+//            discoverDeviceCallback?(devices)
+        }
+//        if CCDevice.isJoy{
+//            let mac = JoySdkManager.getMac(advertisementData) ?? ""
+//            devices.append(DCPeripheral(device: peripheral,mac: mac))
+//            discoverDeviceCallback?(devices)
+//        }
+//        else{
+//            let mac = DcSdkManager.getMac(advertisementData) ?? ""
+//            devices.append(DCPeripheral(device: peripheral,mac: mac))
+//            discoverDeviceCallback?(devices)
+//        }
+    }
+    
+    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
+        stopScanDevice()
+        Logger.debug("蓝牙已连接 \(peripheral)")
+        peripheral.delegate = self
+        if CCDevice.isJoy{
+//            peripheral.discoverServices([CBUUID(string: JoySdkManager.serviceUUID),CBUUID(string: OtaMananger.otaServiceUUId)]);
+        }
+        else{
+            DCBleManager.shared.centralManager(central, didConnect: peripheral)
+            peripheral.discoverServices([CBUUID(string: DCBleManager.serviceUUID),CBUUID(string: OtaMananger.otaServiceUUId)]);
+        }
+    }
+    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
+        Logger.debug("peripheral: %@ failed to connect", peripheral)
+        conetedFailureCallback?(connectPeripheral!)
+    }
+    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
+        Logger.debug("蓝牙已断开 \(peripheral)")
+        YLprogressHUD.showAutoHiden("蓝牙已断开".l10n)
+        self.isConnetd = false
+        if CCDevice.isJoy{
+
+        }
+        else{
+            DCBleManager.shared.centralManager(central, didDisconnectPeripheral: peripheral, error: nil)
+        }
+        NotificationManager.post(type: .deviceValidChange, objtect: nil)
+        OtaMananger.shared.otaManager.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
+        checkConectState()
+    }
+}
+
+extension CCBleManager: CBPeripheralDelegate {
+    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
+        Logger.debug("发现服务成功")
+        for service in peripheral.services! {
+            Logger.debug("peripheral service: %@", service)
+            peripheral.discoverCharacteristics(nil, for: service)
+        }
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
+        if CCDevice.isJoy{
+//            if (service.uuid.uuidString == JoySdkManager.serviceUUID) {
+//                JoySdkManager.shared.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
+//            }
+//            else if service.uuid.uuidString == OtaMananger.otaServiceUUId{
+//                OtaMananger.shared.otaManager.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
+//            }
+        }
+        else{
+            DCBleManager.shared.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
+        }
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: (any Error)?) {
+        if CCDevice.isJoy{
+//            if (characteristic.isNotifying == true && characteristic.service?.uuid.uuidString == JoySdkManager.serviceUUID && characteristic.uuid.uuidString == JoySdkManager.notifyUUID) {
+//                Logger.debug("特征使能成功")
+//                JoySdkManager.shared.bleConnected()
+//            }
+//            if OtaMananger.isOtadata(characteristic){
+//                OtaMananger.shared.otaManager.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
+//            }
+        }
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
+        //        Logger.debug("收到数据 ===uUId ",characteristic.uuid)
+        if CCDevice.isJoy{
+//            if OtaMananger.isOtadata(characteristic){
+//                if let _ = characteristic.value,error == nil {
+//                    OtaMananger.shared.otaManager.peripheral(peripheral, didUpdateValueFor: characteristic)
+//                }
+//                else{
+//                    Logger.debug("ota 收到数据 ===\(characteristic.uuid)","无数据")
+//                }
+//            }
+//            else {
+//                //MARK: 需要配置传入数据
+//                JoySdkManager.shared.receiveValue(characteristic)
+//            }
+        }
+        else{
+            DCBleManager.shared.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
+        }
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) {
+        // Accessory's GATT database has updated. Refresh your local cache (if any)
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: (any Error)?) {
+        
+    }
+}
+
+extension CCBleManager{
+    func startScanDevice() {
+        //        centralManager.stopScan()
+        Logger.debug("扫描中...")
+        Logger.debug("蓝牙状态",centralManager.state.rawValue)
+        devices = []
+        //        let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)])
+        //        Logger.debug("已连接设备",list)
+        //        for item in list {
+        //            if let mac = DeviceCache.shared.getMac(item.identifier.uuidString){
+        //                devices.append(DCPeripheral(device: item,mac: mac))
+        //            }
+        //        }
+        if CCDevice.isJoy{
+//            centralManager.scanForPeripherals(withServices: [CBUUID(string: JoySdkManager.serviceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
+        }
+        else{
+            centralManager.scanForPeripherals(withServices: [CBUUID(string: DCBleManager.serviceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
+        }
+        discoverDeviceCallback?(devices)
+    }
+    
+    func stopScanDevice() {
+        centralManager.stopScan()
+    }
+    
+    func connectPeripheral(_ peripheral: DCPeripheral) {
+        connectPeripheral = peripheral
+        if let name = peripheral.device.name,name.hasPrefix("AI") {
+            CCDevice.isJoy = false
+        }
+        else{
+            CCDevice.isJoy = true
+        }
+        CCDevice.initSdk()
+        Logger.debug(peripheral.device.name ?? "","连接中...")
+        centralManager.connect(peripheral.device, options: [CBConnectPeripheralOptionEnableTransportBridgingKey:true])
+    }
+    
+    func cancel() {
+        guard let peripheral = connectPeripheral else { return  }
+        if self.isConnetd {
+            self.isConnetd = false
+            centralManager.cancelPeripheralConnection(peripheral.device)
+        }
+        
+        NotificationManager.post(type: .deviceValidChange, objtect: nil)
+        connectPeripheral = nil
+    }
+    func unbind(_ peripheral: DCPeripheral){
+        if let mac = connectPeripheral?.mac ,peripheral.mac == mac{
+            cancel()
+        }
+    }
+}
+
+extension CCBleManager{
+    func joySdkSend(_ data: Data, with characteristic: CBCharacteristic) {
+        if let connectPeripheral = connectPeripheral{
+            connectPeripheral.device.writeValue(data, for: characteristic, type:.withoutResponse)
+        }
+    }
+}
+
+extension CCBleManager{
+    func isConected(mac:String)->Bool{
+        guard let device = connectPeripheral else { return false }
+        if device.mac == mac {
+            return isConnetd
+        }
+        else{
+            return false
+        }
+    }
+    
+    //    #连接有问题,应当获取设置里面已连接的设备
+    func connect(mac:String, finished:@escaping ((Bool) -> Void)){
+        CCBleManager.shared.cancel()
+        CCBleManager.shared.discoverDeviceCallback = { list in
+            if list.count <= 0 {
+                return
+            }
+            for item in list {
+                if item.mac == mac {
+                    CCBleManager.shared.connectPeripheral(item)
+                    break
+                }
+            }
+        }
+        CCBleManager.shared.didConnectDeviceCallback = { device in
+            finished(true)
+        }
+        CCBleManager.shared.conetedFailureCallback = {  device in
+            finished(false)
+        }
+        CCBleManager.shared.startScanDevice()
+    }
+    
+    func checkSettingsConnected()->[CBPeripheral]{
+        if CCDevice.isJoy {
+//            let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: JoySdkManager.serviceUUID)])
+//            Logger.debug("已连接设备",list)
+//            return list
+            return []
+        }
+        else{
+            let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: DCBleManager.serviceUUID)])
+            Logger.debug("已连接设备",list)
+            return list
+        }
+    }
+}
+
+extension CCBleManager{
+    func checkConectState(){
+        guard let mac = connectPeripheral?.mac else {
+            return
+        }
+        if isConnetd {
+            return
+        }
+        connect(mac: mac) {result in
+        }
+        
+        DispatchQueue.main.asyncAfter(deadline:.now() + 10) {
+            self.checkConectState()
+        }
+    }
+}
diff --git a/ShenYin/ShenYin/Sdk/DcSdk/CCDevice.swift b/ShenYin/ShenYin/Sdk/DcSdk/CCDevice.swift
new file mode 100644 (file)
index 0000000..60fd7ea
--- /dev/null
@@ -0,0 +1,268 @@
+//
+//  Device.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/12/25.
+//
+//import JoyGemAI
+import DeepChordsSdk
+class CCDevice{
+    static var isJoy = false
+    static func initSdk(){
+        if CCDevice.isJoy {
+//            JoySdkManager.shared.setupSdk()
+        }
+        else{
+            DcSdkManager.shared.initSdk()
+        }
+    }
+    static func translate(text:String,from:String,to:String,finished:@escaping ((stream:String,finish:Bool)?)->Void){
+        if isJoy {
+//            JoyGemAIManager.shared().cancelTranslateRequest()
+//            JoyGemAIManager.shared().translate(text, from: from, to: to) { result, finish in
+//                finished((result,finish))
+//            } error: { error in
+//                finished(nil)
+//            }
+        }
+        else{
+            DCText.cancelTranslateByTextWithSplit()
+            DCText.translate(text: text, from: from, to: to) { result in
+                finished(result)
+            }
+        }
+    }
+    static func summary(text:String,finished:@escaping ((stream:String,finish:Bool)?)->Void){
+        if isJoy {
+//            JoyGemAIManager.shared().cancelSummaryRequest()
+//            JoyGemAIManager.shared().summary(text) { text, finish in
+//                finished((text,finish))
+//            } error: { error in
+//                finished(nil)
+//            }
+        }
+        else{
+            DCText.cancelSummaryByTextWithSplit()
+            DCText.sumary(text: text) { result in
+                finished(result)
+            }
+        }
+    }
+}
+extension CCDevice{
+    static func findHeadphone(_ mode:FindType){
+        if CCDevice.isJoy {
+//            var value:JoyGemFindHeadphoneMode = .all
+//            switch mode {
+//            case .left:
+//                value = .left
+//            case .right:
+//                value = .right
+//            case .cancel:
+//                value = .cancel
+//            case .all:
+//                value = .all
+//            }
+//            JoyGemAIManager.shared().device.findHeadphone(value) { err in
+//                Logger.debug("findHeadphone:\(err)");
+//            }
+        }
+        else{
+            let value:UInt8 = mode == .cancel ? 0:1
+            DCDevice.shared.findDevice(state: value) { result in
+            }
+        }
+    }
+    static func getEQMode(finished:@escaping (ModeEffectsType?)->Void){
+        if CCDevice.isJoy {
+//            JoyGemAIManager.shared().device.getEQMode { mode in
+//                var value:ModeEffectsType = .normal
+//                switch mode {
+//                case .normal:
+//                    value = .normal
+//                case .pop:
+//                    value = .pop
+//                case .classic:
+//                    value = .classic
+//                case .rock:
+//                    value = .rock
+//                case .jazz:
+//                    value = .jazz
+//                case .custom:
+//                    value = .custom
+//                }
+//                finished(value)
+//            } error: { err in
+//                Logger.debug("getEQMode:\(err)");
+//                finished(nil)
+//            }
+        }
+        else{
+            /// type, 0x00(正常模式)
+            //    0x01(流行)
+            //    0x02(经典)
+            //    0x03(爵士)
+            //    0x04(摇滚)
+            //    0x05(自定义)
+            DCDevice.shared.getEQ { (arg0,result) in
+                guard let (type,list) = arg0 else{
+                    finished(nil)
+                    return
+                }
+                switch type{
+                case 0:
+                    finished(.normal)
+                case 1:
+                    finished(.pop)
+                case 2:
+                    finished(.classic)
+                case 3:
+                    finished(.jazz)
+                case 4:
+                    finished(.rock)
+                case 5:
+                    finished(.custom)
+                default:
+                    finished(nil)
+                }
+            }
+        }
+    }
+    static func setEQMode(_ type:ModeEffectsType){
+        if CCDevice.isJoy {
+//            var value:JoyGemEQMode = .normal
+//            switch type {
+//            case .normal:
+//                value = .normal
+//            case .pop:
+//                value = .pop
+//            case .classic:
+//                value = .classic
+//            case .rock:
+//                value = .rock
+//            case .jazz:
+//                value = .jazz
+//            case .custom:
+//                value = .custom
+//            }
+//            
+//            JoyGemAIManager.shared().device.setEQMode(value) { err in
+//                Logger.debug("setEQMode:\(err)");
+//            }
+        }else{
+            let value:UInt8 = UInt8(type.rawValue)
+            DCDevice.shared.setEQ(type: value) { success in
+                
+            }
+        }
+    }
+    
+    
+    static func getCustomEQ(finished:@escaping ([NSNumber]?)->Void){
+        if CCDevice.isJoy {
+//            JoyGemAIManager.shared().device.getCustomEQ { eq in
+//                Logger.debug("getCustomEQ:\(eq)");
+//                finished(eq.bands)
+//            } error: { err in
+//                Logger.debug("getCustomEQ:\(err)");
+//                finished(nil)
+//            }
+        }
+        else{
+            DCDevice.shared.getEQ { (arg0,result) in
+                guard let (type,list) = arg0 else{
+                    finished(nil)
+                    return
+                }
+                if type == 5{
+                    let nums = list.map { NSNumber(value: $0) }
+                    finished(nums)
+                }
+                else{
+                    finished(nil)
+                }
+            }
+        }
+    }
+    static func resetCustomEQ(){
+        if CCDevice.isJoy {
+//            JoyGemAIManager.shared().device.resetCustomEQ { err in
+//                Logger.debug("resetCustomEQ:\(err)");
+//            }
+        }
+        else{
+            let list = [
+                0,0,0,0,0,0,0,0,0,0,0,0
+            ]
+            let dispatchGroup = DispatchGroup()
+            for (index,item) in list.enumerated() {
+                dispatchGroup.enter()
+                DCDevice.shared.setCustomEQ(index: UInt8(index), value: item) {result in
+                    dispatchGroup.leave()
+                }
+            }
+            dispatchGroup.notify(queue:.main) {
+                DCDevice.shared.setEQ(type: 0x05) {result in
+                }
+            }
+        }
+    }
+    static func setCustomEQ(index:Int,value:Int){
+        if CCDevice.isJoy {
+//            JoyGemAIManager.shared().device.setCustomEQ(UInt(index), withGain: value) { err in
+//                Logger.debug("setCustomEQ:\(err)");
+//            }
+        }
+        else{
+            DCDevice.shared.setCustomEQ(index: UInt8(index), value: value) {result in
+            }
+        }
+    }
+}
+extension CCDevice{
+//    static func getMac(finished:@escaping ((_ mac:String?)->Void)) {
+//        if CCDevice.isJoy {
+//            JoyGemAIManager.shared().device.macAddress { edr, ble in
+//                Logger.debug("edr:\(edr),ble:\(ble)");
+//                finished(edr.uppercased())
+//            } error: { error in
+//                Logger.debug("\(error!.localizedDescription)")
+//                finished(nil)
+//            }
+//        }
+//        else{
+////            DCDevice.shared.getSoftVersion {result in
+////                finished(result)
+////            }
+//        }
+//    }
+    static func getDN(finished:@escaping ((_ mac:String?)->Void)) {
+        if CCDevice.isJoy {
+//            JoyGemAIManager.shared().device.getDN { deviceName in
+//                finished(deviceName)
+//            } error: { error in
+//                Logger.debug("获取dn失败","\(error!.localizedDescription)")
+//                finished(nil)
+//            }
+        }
+        else{
+            let dn = DCText.getDeviceName()
+            finished(dn)
+        }
+    }
+    static func getVersion(finished:@escaping ((_ version:String?)->Void)) {
+        if CCDevice.isJoy {
+//            JoyGemAIManager.shared().device.software { version in
+//                finished(version)
+//            } error: { error in
+//                Logger.debug("\(error!.localizedDescription)");
+//                finished(nil)
+//            }
+        }
+        else{
+            DCDevice.shared.getSoftVersion {result in
+                finished(result)
+            }
+        }
+    }
+}
diff --git a/ShenYin/ShenYin/Sdk/DcSdk/CCPage.swift b/ShenYin/ShenYin/Sdk/DcSdk/CCPage.swift
new file mode 100644 (file)
index 0000000..3272eab
--- /dev/null
@@ -0,0 +1,67 @@
+//
+//  CCVCManager.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/12/26.
+//
+
+class CCPage{
+    static func gotoChat(){
+        if CCDevice.isJoy {
+//            App.shared.goToPage(JoyChatVC())
+        }
+        else{
+            App.shared.goToPage(DcChatVC())
+        }
+    }
+    static func gotoFieldRecord(){
+        if CCDevice.isJoy {
+//            App.shared.goToPage(JoyXclyVC())
+        }
+        else{
+            App.shared.goToPage(DcXclyVC())
+        }
+    }
+    static func gotoCallRecord(){
+        if CCDevice.isJoy {
+//            if JoySdkManager.shared.callRecord.supportStereo{
+//                App.shared.goToPage(JoyStereoCallVC())
+//            }
+//            else{
+//                App.shared.goToPage(JoyCallingRecordVC())
+//            }
+        }
+        else{
+//            if JoySdkManager.shared.callRecord.supportStereo{
+                App.shared.goToPage(DcStereoCallVC())
+//            }
+//            else{
+//                App.shared.goToPage(DcCallingRecordVC())
+//            }
+        }
+    }
+    static func gotoChinese2Enlgish(){
+        if CCDevice.isJoy {
+//            App.shared.goToPage(JoyChinese2EnglishVC())
+        }
+        else{
+            App.shared.goToPage(DcChinese2EnglishVC())
+        }
+    }
+    static func gotoTcty(){
+        if CCDevice.isJoy {
+//            App.shared.goToPage(JoyTctyVC())
+        }
+        else{
+            App.shared.goToPage(DcTctyVC())
+        }
+    }
+    static func gotoDialogTranslate(){
+        if CCDevice.isJoy {
+//            App.shared.goToPage(JoyDialogTranslateVC())
+        }
+        else{
+            App.shared.goToPage(DcDialogTranslateVC())
+        }
+    }
+}
diff --git a/ShenYin/ShenYin/Sdk/JoySdk/CCBleManager.swift b/ShenYin/ShenYin/Sdk/JoySdk/CCBleManager.swift
new file mode 100644 (file)
index 0000000..a58e431
--- /dev/null
@@ -0,0 +1,321 @@
+//
+//  CCBleManager.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/12/25.
+//
+
+import UIKit
+import CoreBluetooth
+import AVFAudio
+
+//#if FEATURE_X
+//import DeepChordsSdk
+//#endif
+
+
+class DCPeripheral{
+    var device:CBPeripheral!
+    var mac = ""
+    init(device: CBPeripheral!, mac: String = "") {
+        self.device = device
+        self.mac = mac
+    }
+}
+
+class CCBleManager: NSObject {
+    var discoverDeviceCallback: (([DCPeripheral]) -> Void)?
+    var didConnectDeviceCallback: ((DCPeripheral) -> Void)?
+    var conetedFailureCallback: ((DCPeripheral) -> Void)?
+    
+    private var centralManager: CBCentralManager!
+    var devices: [DCPeripheral] = []
+    var connectPeripheral: DCPeripheral?
+    static let shared = CCBleManager()
+    var isConnetd:Bool = false
+    
+    private override init() {
+        super.init()
+        centralManager = CBCentralManager(delegate: self, queue: nil)
+    }
+}
+extension CCBleManager:CBCentralManagerDelegate{
+    func centralManagerDidUpdateState(_ central: CBCentralManager) {
+        Logger.debug("蓝牙状态",central.state.rawValue)
+        switch central.state {
+        case.unknown:
+            break
+        case.resetting:
+            break
+        case.unsupported:
+            break
+        case.unauthorized:
+            break
+        case.poweredOff:
+            self.isConnetd = false
+            NotificationManager.post(type: .deviceValidChange, objtect: nil)
+            break
+        case.poweredOn:
+            //            startScanDevice()
+            checkConectState()
+            break
+        @unknown default:
+            break
+        }
+        OtaMananger.shared.otaManager.centralManagerDidUpdateState(central)
+    }
+    
+    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
+        if devices.map({ $0.device }).contains(peripheral) {
+            return
+        }
+        Logger.debug(peripheral)
+        
+//        if let name = peripheral.name,name.hasPrefix("AI") {
+//            let mac = DcSdkManager.getMac(advertisementData) ?? ""
+//            devices.append(DCPeripheral(device: peripheral,mac: mac))
+//            discoverDeviceCallback?(devices)
+//        }
+//        else{
+////            let mac = JoySdkManager.getMac(advertisementData) ?? ""
+////            devices.append(DCPeripheral(device: peripheral,mac: mac))
+////            discoverDeviceCallback?(devices)
+//        }
+        if CCDevice.isJoy{
+            let mac = JoySdkManager.getMac(advertisementData) ?? ""
+            devices.append(DCPeripheral(device: peripheral,mac: mac))
+            discoverDeviceCallback?(devices)
+        }
+//        else{
+//            let mac = DcSdkManager.getMac(advertisementData) ?? ""
+//            devices.append(DCPeripheral(device: peripheral,mac: mac))
+//            discoverDeviceCallback?(devices)
+//        }
+    }
+    
+    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
+        stopScanDevice()
+        Logger.debug("蓝牙已连接 \(peripheral)")
+        peripheral.delegate = self
+        if CCDevice.isJoy{
+            peripheral.discoverServices([CBUUID(string: JoySdkManager.serviceUUID),CBUUID(string: OtaMananger.otaServiceUUId)]);
+        }
+        else{
+//            DCBleManager.shared.centralManager(central, didConnect: peripheral)
+//            peripheral.discoverServices([CBUUID(string: DCBleManager.serviceUUID),CBUUID(string: OtaMananger.otaServiceUUId)]);
+        }
+    }
+    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
+        Logger.debug("peripheral: %@ failed to connect", peripheral)
+        conetedFailureCallback?(connectPeripheral!)
+    }
+    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
+        Logger.debug("蓝牙已断开 \(peripheral)")
+        YLprogressHUD.showAutoHiden("蓝牙已断开".l10n)
+        self.isConnetd = false
+        if CCDevice.isJoy{
+        }
+        else{
+//            DCBleManager.shared.centralManager(central, didDisconnectPeripheral: peripheral, error: nil)
+        }
+        NotificationManager.post(type: .deviceValidChange, objtect: nil)
+        OtaMananger.shared.otaManager.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
+        checkConectState()
+    }
+}
+
+extension CCBleManager: CBPeripheralDelegate {
+    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
+        Logger.debug("发现服务成功")
+        for service in peripheral.services! {
+            Logger.debug("peripheral service: %@", service)
+            peripheral.discoverCharacteristics(nil, for: service)
+        }
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
+        if CCDevice.isJoy{
+            if (service.uuid.uuidString == JoySdkManager.serviceUUID) {
+                JoySdkManager.shared.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
+            }
+            else if service.uuid.uuidString == OtaMananger.otaServiceUUId{
+                OtaMananger.shared.otaManager.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
+            }
+        }
+        else{
+//            DCBleManager.shared.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
+        }
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: (any Error)?) {
+        if CCDevice.isJoy{
+            if (characteristic.isNotifying == true && characteristic.service?.uuid.uuidString == JoySdkManager.serviceUUID && characteristic.uuid.uuidString == JoySdkManager.notifyUUID) {
+                Logger.debug("特征使能成功")
+                JoySdkManager.shared.bleConnected()
+            }
+            if OtaMananger.isOtadata(characteristic){
+                OtaMananger.shared.otaManager.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
+            }
+        }
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
+        //        Logger.debug("收到数据 ===uUId ",characteristic.uuid)
+        if CCDevice.isJoy{
+            if OtaMananger.isOtadata(characteristic){
+                if let _ = characteristic.value,error == nil {
+                    OtaMananger.shared.otaManager.peripheral(peripheral, didUpdateValueFor: characteristic)
+                }
+                else{
+                    Logger.debug("ota 收到数据 ===\(characteristic.uuid)","无数据")
+                }
+            }
+            else {
+                //MARK: 需要配置传入数据
+                JoySdkManager.shared.receiveValue(characteristic)
+            }
+        }
+        else{
+//            DCBleManager.shared.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
+        }
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) {
+        // Accessory's GATT database has updated. Refresh your local cache (if any)
+    }
+    
+    func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: (any Error)?) {
+        
+    }
+}
+
+extension CCBleManager{
+    func startScanDevice() {
+        //        centralManager.stopScan()
+        Logger.debug("扫描中...")
+        Logger.debug("蓝牙状态",centralManager.state.rawValue)
+        devices = []
+        //        let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)])
+        //        Logger.debug("已连接设备",list)
+        //        for item in list {
+        //            if let mac = DeviceCache.shared.getMac(item.identifier.uuidString){
+        //                devices.append(DCPeripheral(device: item,mac: mac))
+        //            }
+        //        }
+        if CCDevice.isJoy{
+            centralManager.scanForPeripherals(withServices: [CBUUID(string: JoySdkManager.serviceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
+        }
+        else{
+//            centralManager.scanForPeripherals(withServices: [CBUUID(string: DCBleManager.serviceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
+        }
+        discoverDeviceCallback?(devices)
+    }
+    
+    func stopScanDevice() {
+        centralManager.stopScan()
+    }
+    
+    func connectPeripheral(_ peripheral: DCPeripheral) {
+        connectPeripheral = peripheral
+        if let name = peripheral.device.name,name.hasPrefix("AI") {
+            CCDevice.isJoy = false
+        }
+        else{
+            CCDevice.isJoy = true
+        }
+        CCDevice.initSdk()
+        Logger.debug(peripheral.device.name ?? "","连接中...")
+        centralManager.connect(peripheral.device, options: [CBConnectPeripheralOptionEnableTransportBridgingKey:true])
+    }
+    
+    func cancel() {
+        guard let peripheral = connectPeripheral else { return  }
+        if self.isConnetd {
+            self.isConnetd = false
+            centralManager.cancelPeripheralConnection(peripheral.device)
+        }
+        
+        NotificationManager.post(type: .deviceValidChange, objtect: nil)
+        connectPeripheral = nil
+    }
+    func unbind(_ peripheral: DCPeripheral){
+        if let mac = connectPeripheral?.mac ,peripheral.mac == mac{
+            cancel()
+        }
+    }
+}
+
+extension CCBleManager{
+    func joySdkSend(_ data: Data, with characteristic: CBCharacteristic) {
+        if let connectPeripheral = connectPeripheral{
+            connectPeripheral.device.writeValue(data, for: characteristic, type:.withoutResponse)
+        }
+    }
+}
+
+extension CCBleManager{
+    func isConected(mac:String)->Bool{
+        guard let device = connectPeripheral else { return false }
+        if device.mac == mac {
+            return isConnetd
+        }
+        else{
+            return false
+        }
+    }
+    
+    //    #连接有问题,应当获取设置里面已连接的设备
+    func connect(mac:String, finished:@escaping ((Bool) -> Void)){
+        CCBleManager.shared.cancel()
+        CCBleManager.shared.discoverDeviceCallback = { list in
+            if list.count <= 0 {
+                return
+            }
+            for item in list {
+                if item.mac == mac {
+                    CCBleManager.shared.connectPeripheral(item)
+                    break
+                }
+            }
+        }
+        CCBleManager.shared.didConnectDeviceCallback = { device in
+            finished(true)
+        }
+        CCBleManager.shared.conetedFailureCallback = {  device in
+            finished(false)
+        }
+        CCBleManager.shared.startScanDevice()
+    }
+    
+    func checkSettingsConnected()->[CBPeripheral]{
+        if CCDevice.isJoy {
+            let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: JoySdkManager.serviceUUID)])
+            Logger.debug("已连接设备",list)
+            return list
+//            return []
+        }
+        else{
+//            let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: DCBleManager.serviceUUID)])
+//            Logger.debug("已连接设备",list)
+//            return list
+            return []
+        }
+    }
+}
+
+extension CCBleManager{
+    func checkConectState(){
+        guard let mac = connectPeripheral?.mac else {
+            return
+        }
+        if isConnetd {
+            return
+        }
+        connect(mac: mac) {result in
+        }
+        
+        DispatchQueue.main.asyncAfter(deadline:.now() + 10) {
+            self.checkConectState()
+        }
+    }
+}
index c008fd7..a7a45aa 100644 (file)
@@ -5,7 +5,6 @@
 //  Created by liangshi on 2025/12/25.
 //
 import JoyGemAI
-import DeepChordsSdk
 class CCDevice{
     static var isJoy = true
     static func initSdk(){
@@ -13,7 +12,7 @@ class CCDevice{
             JoySdkManager.shared.setupSdk()
         }
         else{
-            DcSdkManager.shared.initSdk()
+//            DcSdkManager.shared.initSdk()
         }
     }
     static func translate(text:String,from:String,to:String,finished:@escaping ((stream:String,finish:Bool)?)->Void){
@@ -26,10 +25,10 @@ class CCDevice{
             }
         }
         else{
-            DCText.cancelTranslateByTextWithSplit()
-            DCText.translate(text: text, from: from, to: to) { result in
-                finished(result)
-            }
+//            DCText.cancelTranslateByTextWithSplit()
+//            DCText.translate(text: text, from: from, to: to) { result in
+//                finished(result)
+//            }
         }
     }
     static func summary(text:String,finished:@escaping ((stream:String,finish:Bool)?)->Void){
@@ -42,10 +41,10 @@ class CCDevice{
             }
         }
         else{
-            DCText.cancelSummaryByTextWithSplit()
-            DCText.sumary(text: text) { result in
-                finished(result)
-            }
+//            DCText.cancelSummaryByTextWithSplit()
+//            DCText.sumary(text: text) { result in
+//                finished(result)
+//            }
         }
     }
 }
@@ -68,9 +67,9 @@ extension CCDevice{
             }
         }
         else{
-            let value:UInt8 = mode == .cancel ? 0:1
-            DCDevice.shared.findDevice(state: value) { result in
-            }
+//            let value:UInt8 = mode == .cancel ? 0:1
+//            DCDevice.shared.findDevice(state: value) { result in
+//            }
         }
     }
     static func getEQMode(finished:@escaping (ModeEffectsType?)->Void){
@@ -104,28 +103,28 @@ extension CCDevice{
             //    0x03(爵士)
             //    0x04(摇滚)
             //    0x05(自定义)
-            DCDevice.shared.getEQ { (arg0,result) in
-                guard let (type,list) = arg0 else{
-                    finished(nil)
-                    return
-                }
-                switch type{
-                case 0:
-                    finished(.normal)
-                case 1:
-                    finished(.pop)
-                case 2:
-                    finished(.classic)
-                case 3:
-                    finished(.jazz)
-                case 4:
-                    finished(.rock)
-                case 5:
-                    finished(.custom)
-                default:
-                    finished(nil)
-                }
-            }
+//            DCDevice.shared.getEQ { (arg0,result) in
+//                guard let (type,list) = arg0 else{
+//                    finished(nil)
+//                    return
+//                }
+//                switch type{
+//                case 0:
+//                    finished(.normal)
+//                case 1:
+//                    finished(.pop)
+//                case 2:
+//                    finished(.classic)
+//                case 3:
+//                    finished(.jazz)
+//                case 4:
+//                    finished(.rock)
+//                case 5:
+//                    finished(.custom)
+//                default:
+//                    finished(nil)
+//                }
+//            }
         }
     }
     static func setEQMode(_ type:ModeEffectsType){
@@ -150,10 +149,10 @@ extension CCDevice{
                 Logger.debug("setEQMode:\(err)");
             }
         }else{
-            let value:UInt8 = UInt8(type.rawValue)
-            DCDevice.shared.setEQ(type: value) { success in
-                
-            }
+//            let value:UInt8 = UInt8(type.rawValue)
+//            DCDevice.shared.setEQ(type: value) { success in
+//                
+//            }
         }
     }
     
@@ -169,19 +168,19 @@ extension CCDevice{
             }
         }
         else{
-            DCDevice.shared.getEQ { (arg0,result) in
-                guard let (type,list) = arg0 else{
-                    finished(nil)
-                    return
-                }
-                if type == 5{
-                    let nums = list.map { NSNumber(value: $0) }
-                    finished(nums)
-                }
-                else{
-                    finished(nil)
-                }
-            }
+//            DCDevice.shared.getEQ { (arg0,result) in
+//                guard let (type,list) = arg0 else{
+//                    finished(nil)
+//                    return
+//                }
+//                if type == 5{
+//                    let nums = list.map { NSNumber(value: $0) }
+//                    finished(nums)
+//                }
+//                else{
+//                    finished(nil)
+//                }
+//            }
         }
     }
     static func resetCustomEQ(){
@@ -191,20 +190,20 @@ extension CCDevice{
             }
         }
         else{
-            let list = [
-                0,0,0,0,0,0,0,0,0,0,0,0
-            ]
-            let dispatchGroup = DispatchGroup()
-            for (index,item) in list.enumerated() {
-                dispatchGroup.enter()
-                DCDevice.shared.setCustomEQ(index: UInt8(index), value: item) {result in
-                    dispatchGroup.leave()
-                }
-            }
-            dispatchGroup.notify(queue:.main) {
-                DCDevice.shared.setEQ(type: 0x05) {result in
-                }
-            }
+//            let list = [
+//                0,0,0,0,0,0,0,0,0,0,0,0
+//            ]
+//            let dispatchGroup = DispatchGroup()
+//            for (index,item) in list.enumerated() {
+//                dispatchGroup.enter()
+//                DCDevice.shared.setCustomEQ(index: UInt8(index), value: item) {result in
+//                    dispatchGroup.leave()
+//                }
+//            }
+//            dispatchGroup.notify(queue:.main) {
+//                DCDevice.shared.setEQ(type: 0x05) {result in
+//                }
+//            }
         }
     }
     static func setCustomEQ(index:Int,value:Int){
@@ -214,8 +213,8 @@ extension CCDevice{
             }
         }
         else{
-            DCDevice.shared.setCustomEQ(index: UInt8(index), value: value) {result in
-            }
+//            DCDevice.shared.setCustomEQ(index: UInt8(index), value: value) {result in
+//            }
         }
     }
 }
@@ -246,8 +245,8 @@ extension CCDevice{
             }
         }
         else{
-            let dn = DCText.getDeviceName()
-            finished(dn)
+//            let dn = DCText.getDeviceName()
+//            finished(dn)
         }
     }
     static func getVersion(finished:@escaping ((_ version:String?)->Void)) {
@@ -260,9 +259,9 @@ extension CCDevice{
             }
         }
         else{
-            DCDevice.shared.getSoftVersion {result in
-                finished(result)
-            }
+//            DCDevice.shared.getSoftVersion {result in
+//                finished(result)
+//            }
         }
     }
 }
diff --git a/ShenYin/ShenYin/Sdk/JoySdk/CCPage.swift b/ShenYin/ShenYin/Sdk/JoySdk/CCPage.swift
new file mode 100644 (file)
index 0000000..e73b8a5
--- /dev/null
@@ -0,0 +1,62 @@
+//
+//  CCVCManager.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/12/26.
+//
+
+class CCPage{
+    static func gotoChat(){
+        if CCDevice.isJoy {
+            App.shared.goToPage(JoyChatVC())
+        }
+        else{
+//            App.shared.goToPage(DcChatVC())
+        }
+    }
+    static func gotoFieldRecord(){
+        if CCDevice.isJoy {
+            App.shared.goToPage(JoyXclyVC())
+        }
+        else{
+//            App.shared.goToPage(DcXclyVC())
+        }
+    }
+    static func gotoCallRecord(){
+        if CCDevice.isJoy {
+            if JoySdkManager.shared.callRecord.supportStereo{
+                App.shared.goToPage(JoyStereoCallVC())
+            }
+            else{
+                App.shared.goToPage(JoyCallingRecordVC())
+            }
+        }
+        else{
+//               App.shared.goToPage(DcStereoCallVC())
+        }
+    }
+    static func gotoChinese2Enlgish(){
+        if CCDevice.isJoy {
+            App.shared.goToPage(JoyChinese2EnglishVC())
+        }
+        else{
+//            App.shared.goToPage(DcChinese2EnglishVC())
+        }
+    }
+    static func gotoTcty(){
+        if CCDevice.isJoy {
+            App.shared.goToPage(JoyTctyVC())
+        }
+        else{
+//            App.shared.goToPage(DcTctyVC())
+        }
+    }
+    static func gotoDialogTranslate(){
+        if CCDevice.isJoy {
+            App.shared.goToPage(JoyDialogTranslateVC())
+        }
+        else{
+//            App.shared.goToPage(DcDialogTranslateVC())
+        }
+    }
+}
index 4e9a702..9741485 100644 (file)
@@ -199,10 +199,10 @@ extension JoySdkManager{
             if (advMsd.count >= 13) {
                 let mac = advMsd[7...12];
                 let text = mac.map { String($0, radix: 16).padLeft(toLength: 2, withPad: "0") }.joined(separator: ":").uppercased()
-                Logger.debug(dict)
-                Logger.debug(advMsd)
-                Logger.debug(mac.joined())
-                Logger.debug(text)
+//                Logger.debug(dict)
+//                Logger.debug(advMsd)
+//                Logger.debug(mac.joined())
+//                Logger.debug(text)
                 return text
             } else {
                 return nil
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemAI-Swift.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemAI-Swift.h
new file mode 100644 (file)
index 0000000..344f048
--- /dev/null
@@ -0,0 +1,315 @@
+#if 0
+#elif defined(__arm64__) && __arm64__
+// Generated by Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
+#ifndef JOYGEMAI_SWIFT_H
+#define JOYGEMAI_SWIFT_H
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgcc-compat"
+
+#if !defined(__has_include)
+# define __has_include(x) 0
+#endif
+#if !defined(__has_attribute)
+# define __has_attribute(x) 0
+#endif
+#if !defined(__has_feature)
+# define __has_feature(x) 0
+#endif
+#if !defined(__has_warning)
+# define __has_warning(x) 0
+#endif
+
+#if __has_include(<swift/objc-prologue.h>)
+# include <swift/objc-prologue.h>
+#endif
+
+#pragma clang diagnostic ignored "-Wauto-import"
+#if defined(__OBJC__)
+#include <Foundation/Foundation.h>
+#endif
+#if defined(__cplusplus)
+#include <cstdint>
+#include <cstddef>
+#include <cstdbool>
+#include <cstring>
+#include <stdlib.h>
+#include <new>
+#include <type_traits>
+#else
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#endif
+#if defined(__cplusplus)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-modular-include-in-framework-module"
+#if defined(__arm64e__) && __has_include(<ptrauth.h>)
+# include <ptrauth.h>
+#else
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
+# ifndef __ptrauth_swift_value_witness_function_pointer
+#  define __ptrauth_swift_value_witness_function_pointer(x)
+# endif
+# ifndef __ptrauth_swift_class_method_pointer
+#  define __ptrauth_swift_class_method_pointer(x)
+# endif
+#pragma clang diagnostic pop
+#endif
+#pragma clang diagnostic pop
+#endif
+
+#if !defined(SWIFT_TYPEDEFS)
+# define SWIFT_TYPEDEFS 1
+# if __has_include(<uchar.h>)
+#  include <uchar.h>
+# elif !defined(__cplusplus)
+typedef uint_least16_t char16_t;
+typedef uint_least32_t char32_t;
+# endif
+typedef float swift_float2  __attribute__((__ext_vector_type__(2)));
+typedef float swift_float3  __attribute__((__ext_vector_type__(3)));
+typedef float swift_float4  __attribute__((__ext_vector_type__(4)));
+typedef double swift_double2  __attribute__((__ext_vector_type__(2)));
+typedef double swift_double3  __attribute__((__ext_vector_type__(3)));
+typedef double swift_double4  __attribute__((__ext_vector_type__(4)));
+typedef int swift_int2  __attribute__((__ext_vector_type__(2)));
+typedef int swift_int3  __attribute__((__ext_vector_type__(3)));
+typedef int swift_int4  __attribute__((__ext_vector_type__(4)));
+typedef unsigned int swift_uint2  __attribute__((__ext_vector_type__(2)));
+typedef unsigned int swift_uint3  __attribute__((__ext_vector_type__(3)));
+typedef unsigned int swift_uint4  __attribute__((__ext_vector_type__(4)));
+#endif
+
+#if !defined(SWIFT_PASTE)
+# define SWIFT_PASTE_HELPER(x, y) x##y
+# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
+#endif
+#if !defined(SWIFT_METATYPE)
+# define SWIFT_METATYPE(X) Class
+#endif
+#if !defined(SWIFT_CLASS_PROPERTY)
+# if __has_feature(objc_class_property)
+#  define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
+# else
+#  define SWIFT_CLASS_PROPERTY(...) 
+# endif
+#endif
+#if !defined(SWIFT_RUNTIME_NAME)
+# if __has_attribute(objc_runtime_name)
+#  define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
+# else
+#  define SWIFT_RUNTIME_NAME(X) 
+# endif
+#endif
+#if !defined(SWIFT_COMPILE_NAME)
+# if __has_attribute(swift_name)
+#  define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
+# else
+#  define SWIFT_COMPILE_NAME(X) 
+# endif
+#endif
+#if !defined(SWIFT_METHOD_FAMILY)
+# if __has_attribute(objc_method_family)
+#  define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
+# else
+#  define SWIFT_METHOD_FAMILY(X) 
+# endif
+#endif
+#if !defined(SWIFT_NOESCAPE)
+# if __has_attribute(noescape)
+#  define SWIFT_NOESCAPE __attribute__((noescape))
+# else
+#  define SWIFT_NOESCAPE 
+# endif
+#endif
+#if !defined(SWIFT_RELEASES_ARGUMENT)
+# if __has_attribute(ns_consumed)
+#  define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed))
+# else
+#  define SWIFT_RELEASES_ARGUMENT 
+# endif
+#endif
+#if !defined(SWIFT_WARN_UNUSED_RESULT)
+# if __has_attribute(warn_unused_result)
+#  define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+# else
+#  define SWIFT_WARN_UNUSED_RESULT 
+# endif
+#endif
+#if !defined(SWIFT_NORETURN)
+# if __has_attribute(noreturn)
+#  define SWIFT_NORETURN __attribute__((noreturn))
+# else
+#  define SWIFT_NORETURN 
+# endif
+#endif
+#if !defined(SWIFT_CLASS_EXTRA)
+# define SWIFT_CLASS_EXTRA 
+#endif
+#if !defined(SWIFT_PROTOCOL_EXTRA)
+# define SWIFT_PROTOCOL_EXTRA 
+#endif
+#if !defined(SWIFT_ENUM_EXTRA)
+# define SWIFT_ENUM_EXTRA 
+#endif
+#if !defined(SWIFT_CLASS)
+# if __has_attribute(objc_subclassing_restricted)
+#  define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
+#  define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
+# else
+#  define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
+#  define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
+# endif
+#endif
+#if !defined(SWIFT_RESILIENT_CLASS)
+# if __has_attribute(objc_class_stub)
+#  define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub))
+#  define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME)
+# else
+#  define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME)
+#  define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME)
+# endif
+#endif
+#if !defined(SWIFT_PROTOCOL)
+# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
+# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
+#endif
+#if !defined(SWIFT_EXTENSION)
+# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
+#endif
+#if !defined(OBJC_DESIGNATED_INITIALIZER)
+# if __has_attribute(objc_designated_initializer)
+#  define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
+# else
+#  define OBJC_DESIGNATED_INITIALIZER 
+# endif
+#endif
+#if !defined(SWIFT_ENUM_ATTR)
+# if __has_attribute(enum_extensibility)
+#  define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility)))
+# else
+#  define SWIFT_ENUM_ATTR(_extensibility) 
+# endif
+#endif
+#if !defined(SWIFT_ENUM)
+# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
+# if __has_feature(generalized_swift_name)
+#  define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
+# else
+#  define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility)
+# endif
+#endif
+#if !defined(SWIFT_UNAVAILABLE)
+# define SWIFT_UNAVAILABLE __attribute__((unavailable))
+#endif
+#if !defined(SWIFT_UNAVAILABLE_MSG)
+# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
+#endif
+#if !defined(SWIFT_AVAILABILITY)
+# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
+#endif
+#if !defined(SWIFT_WEAK_IMPORT)
+# define SWIFT_WEAK_IMPORT __attribute__((weak_import))
+#endif
+#if !defined(SWIFT_DEPRECATED)
+# define SWIFT_DEPRECATED __attribute__((deprecated))
+#endif
+#if !defined(SWIFT_DEPRECATED_MSG)
+# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
+#endif
+#if !defined(SWIFT_DEPRECATED_OBJC)
+# if __has_feature(attribute_diagnose_if_objc)
+#  define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
+# else
+#  define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
+# endif
+#endif
+#if defined(__OBJC__)
+#if !defined(IBSegueAction)
+# define IBSegueAction 
+#endif
+#endif
+#if !defined(SWIFT_EXTERN)
+# if defined(__cplusplus)
+#  define SWIFT_EXTERN extern "C"
+# else
+#  define SWIFT_EXTERN extern
+# endif
+#endif
+#if !defined(SWIFT_CALL)
+# define SWIFT_CALL __attribute__((swiftcall))
+#endif
+#if !defined(SWIFT_INDIRECT_RESULT)
+# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result))
+#endif
+#if !defined(SWIFT_CONTEXT)
+# define SWIFT_CONTEXT __attribute__((swift_context))
+#endif
+#if !defined(SWIFT_ERROR_RESULT)
+# define SWIFT_ERROR_RESULT __attribute__((swift_error_result))
+#endif
+#if defined(__cplusplus)
+# define SWIFT_NOEXCEPT noexcept
+#else
+# define SWIFT_NOEXCEPT 
+#endif
+#if !defined(SWIFT_C_INLINE_THUNK)
+# if __has_attribute(always_inline)
+# if __has_attribute(nodebug)
+#  define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug))
+# else
+#  define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline))
+# endif
+# else
+#  define SWIFT_C_INLINE_THUNK inline
+# endif
+#endif
+#if defined(_WIN32)
+#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL)
+# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport)
+#endif
+#else
+#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL)
+# define SWIFT_IMPORT_STDLIB_SYMBOL 
+#endif
+#endif
+#if defined(__OBJC__)
+#if __has_feature(objc_modules)
+#if __has_warning("-Watimport-in-framework-header")
+#pragma clang diagnostic ignored "-Watimport-in-framework-header"
+#endif
+#endif
+
+#endif
+#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
+#pragma clang diagnostic ignored "-Wduplicate-method-arg"
+#if __has_warning("-Wpragma-clang-attribute")
+# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
+#endif
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Wnullability"
+#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
+#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
+
+#if __has_attribute(external_source_symbol)
+# pragma push_macro("any")
+# undef any
+# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="JoyGemAI",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
+# pragma pop_macro("any")
+#endif
+
+#if defined(__OBJC__)
+#endif
+#if __has_attribute(external_source_symbol)
+# pragma clang attribute pop
+#endif
+#if defined(__cplusplus)
+#endif
+#pragma clang diagnostic pop
+#endif
+
+#else
+#error unsupported Swift architecture
+#endif
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemAI.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemAI.h
new file mode 100644 (file)
index 0000000..f16e0fe
--- /dev/null
@@ -0,0 +1,28 @@
+//
+//  JoyGemAI.h
+//  JoyGemAI
+//
+//  Created by JoyGem on 2025/2/10.
+//
+
+#import <Foundation/Foundation.h>
+
+//! Project version number for JoyGemAI.
+FOUNDATION_EXPORT double JoyGemAIVersionNumber;
+
+//! Project version string for JoyGemAI.
+FOUNDATION_EXPORT const unsigned char JoyGemAIVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <JoyGemAI/PublicHeader.h>
+
+#import <JoyGemAI/JoyGemAIManager.h>
+#import <JoyGemAI/JoyGemParam.h>
+#import <JoyGemAI/JoyGemModel.h>
+#import <JoyGemAI/JoyGemChatManager.h>
+#import <JoyGemAI/JoyGemSIManager.h>
+#import <JoyGemAI/JoyGemSIDeviceManager.h>
+#import <JoyGemAI/JoyGemRecordManager.h>
+#import <JoyGemAI/JoyGemCallManager.h>
+#import <JoyGemAI/JoyGemEnum.h>
+#import <JoyGemAI/JoyGemDeviceManager.h>
+#import <JoyGemAI/JoyGemSubtitleManager.h>
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemAIManager.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemAIManager.h
new file mode 100644 (file)
index 0000000..f60ed8d
--- /dev/null
@@ -0,0 +1,140 @@
+//
+//  JoyGemAIManager.h
+//  JoyGemAI
+//
+//  Created by JoyGem on 2025/2/10.
+//
+
+#import <Foundation/Foundation.h>
+#import <CoreBluetooth/CoreBluetooth.h>
+#import <JoyGemAI/JoyGemParam.h>
+#import <JoyGemAI/JoyGemModel.h>
+#import <JoyGemAI/JoyGemEnum.h>
+#import <SocketRocket/SocketRocket.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol JoyGemAIManagerDelegate <NSObject>
+
+/// 鉴权成功时回调
+-(void)joyGemAuthSuccessCallback;
+
+/// 鉴权失败时回调
+-(void)joyGemAuthFailedCallback;
+
+/// AI\b耳机动作回调
+/// - NOTE: 对话相关动作是通知,即消息来时已经发生,录音相关动作是请求,即耳机没有实际操作
+@optional
+-(void)joyGemAction:(JoyGemActionMode)action;
+
+@end
+
+@protocol JoyGemAIManagerDataSource <NSObject>
+
+///实现该方法,将数据转发给蓝牙
+@required
+-(void)joyGemSendData:(NSData*)data withCharacteristic:(CBCharacteristic*)characteristic;
+
+@end
+
+@class JoyGemDeviceManager;
+
+@interface JoyGemAIManager : NSObject
+
+@property(nonatomic, weak) id<JoyGemAIManagerDelegate> delegate;
+@property(nonatomic, weak) id<JoyGemAIManagerDataSource> dataSource;
+
+@property(nonatomic, strong) JoyGemDeviceManager *device;
+
+// 实例对象
++ (instancetype)shared;
+
+/// 初始化sdk
+- (void)initSdk;
+
+/// 初始化sdk
+/// - Parameter projectID: 可选方法
+- (void)initSdk:(nullable NSString*)projectID;
+
+/// 日志打印级别
+/// - Parameter level: 日志等级 分为关闭,简略,完全
+- (void)setLogMode:(JoyGemLogMode)mode;
+
+/// 日志存储路径
+/// - Parameter path: 日志存储文件路径
+/// - Description: 为空时不进行日志存储, 不支持多次配置
+- (void)setLogPath:(nullable NSString*)path;
+
+/// 传入蓝牙服务对象
+/// - Parameters:
+///  - service: 服务对象
+///  - characteristics: 需要\bnotify的特征
+/// - Returns: 是否正确的配置了相关服务特征
+/// - Description: Block为同步操作
+- (BOOL)configService:(CBService*)service needNotify:(void (^)(NSArray<CBCharacteristic*>*))characteristics;
+
+/// 收到蓝牙设备传过来的数据,调用此方法交给sdk处理
+/// - Parameter characteristic:更新的特征
+- (void)receiveValue:(CBCharacteristic *)characteristic;
+
+/// 蓝牙设备已连接
+- (void)bleConnected;
+
+/// 蓝牙断开连接
+- (void)bleDisConnected;
+
+/// SDK文件存储文件夹
+/// - Parameter path: SDK文件存储路径(SDK需要用到文件存储时所指向的路径)
+- (void)setCacheDirectory:(nullable NSString*)path;
+
+/// 清除临时文件
+/// - Description: 只会清除当前配置路径下的文件
+- (void)clearCacheDirectory;
+
+/// \bTWS耳机主从切换时是否尝试当前AI功能自动延续
+/// - Parameters:
+///  - enable: 默认为false
+-(void)setTWSAutoSync:(BOOL)enable;
+
+-(void)setTextAutoSync:(BOOL)enable;
+
+-(void)setEmotionAutoSync:(BOOL)enable;
+
+/// 文本翻译
+/// - Parameters:
+///   - text: 翻译的文字
+///   - fromLanguage: 原始语言
+///   - toLanguage: 翻译语言
+///   - stream: 结果回调
+///   - error: 错误回调
+/// - Description: 最大文本支持30K
+- (void)translate:(NSString *)text from:(NSString*)fromLanguage to:(NSString*)toLanguage stream:(void (^)(NSString* llmResponse,BOOL finish))stream error:(void (^)( NSError * _Nullable err))error;
+
+/// 取消文本翻译
+-(void)cancelTranslateRequest;
+
+/// 文本摘要
+/// - Parameters:
+///   - text: 摘要的文字
+///   - stream: 结果回调
+///   - error: 错误回调
+/// - Description: 最大文本支持30K
+- (void)summary:(NSString *)text stream:(void (^)(NSString* llmResponse,BOOL finish))stream error:(void (^)( NSError * _Nullable err))error;
+
+/// 取消文本摘要
+-(void)cancelSummaryRequest;
+
+
+/// 设置同传的tts回应速度
+/// - Parameters:
+///   - speed: 默认1.0,范围[0.8,2]
+-(void)setTtsSpeed:(float)speed;
+
+/// 配置测试环境
+/// - Parameters:
+///   - info: 测试环境字典
+-(void)setDebugEnvironment:(NSDictionary*)info;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemCallManager.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemCallManager.h
new file mode 100644 (file)
index 0000000..5a4dd0f
--- /dev/null
@@ -0,0 +1,132 @@
+//
+//  JoyGemCallController.h
+//  JoyGemAI
+//
+//  Created by jjjs on 2025/7/12.
+//
+
+#import <UIKit/UIKit.h>
+#import <JoyGemAI/JoyGemEnum.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class JoyGemCallManager;
+@class JoyGemAsrModel;
+
+//通话录音的委托类
+@protocol JoyGemCallManagerDelegate <NSObject>
+
+///录音文字识别时
+/// - Parameters:
+///   - model: asr识别的对象
+@optional
+-(void)callManager:(JoyGemCallManager*)manager didUpdateAsr:(JoyGemAsrModel*)model DEPRECATED_MSG_ATTRIBUTE("Use callManager:didUpdateMonoAsr instead \bif supportStereo is false");;
+
+///文件生成后的回调
+/// - Parameters:
+///   - path: 文件存储路径 wav格式
+-(void)callManager:(JoyGemCallManager*)manager saveFile:(NSString*)path;
+
+///录音状态回调
+/// - Parameters:
+///   - code: 状态变化
+-(void)callManager:(JoyGemCallManager*)manager stateChange:(JoyGemStateCode)code;
+
+/// 录音错误回调
+///  - Parameters:
+///   - mode:错误代码
+-(void)callManager:(JoyGemCallManager*)manager onError:(JoyGemErrorCode)code;
+
+/// 通话录音开启时,不处于通话状态
+/// - Description: 需要确认耳机是否支持该判断,如果耳机不支持将不会收到回调
+@optional
+-(void)callManagerNotonCall:(JoyGemCallManager*)manager;
+
+///结束时的回调
+/// - Parameters:
+///   - code: 录音结束的原因
+-(void)callManagerStopped:(JoyGemCallManager*)manager reason:(JoyGemRecordStopCode)code;
+
+/// 录音完成时的回调
+/// - Description: 录音任务调用结束后,会在服务器所有响应结束后进行回调
+/// - Note: 该接口仅在任务成功完成时才会进行回调,并不保证和stop方法实现一一对应
+@optional
+-(void)callManagerCompleted:(JoyGemCallManager*)manager;
+
+@end
+
+@protocol JoyGemCallMonoDelegate <NSObject>
+
+///录音文字识别时
+/// - Parameters:
+///   - model: asr识别的对象
+@required
+-(void)callManager:(JoyGemCallManager*)manager didUpdateMonoAsr:(JoyGemAsrModel*)model;
+
+/// 录音时的声波强度回调
+/// - Parameters:
+///   - list: 强度数组
+///   - timestamp: 时间戳(ms)
+@optional
+-(void)callManager:(JoyGemCallManager*)manager monoIntensity:(NSArray<NSNumber*>*)list timestamp:(NSTimeInterval)timestamp;
+
+@end
+
+@protocol JoyGemCallStereoDelegate <NSObject>
+
+///录音文字识别
+/// - Parameters:
+///   - model: asr识别的对象
+///   - index: 声道序号 1,2
+@required
+-(void)callManager:(JoyGemCallManager*)manager didUpdateStereoAsr:(JoyGemAsrModel*)model channel:(NSUInteger)index;
+
+/// 录音时的声波强度回调
+/// - Parameters:
+///   - lists: 强度数组(二维数组,0为左声道,1为右声道)
+///   - timestamp: 时间戳(ms)
+@optional
+-(void)callManager:(JoyGemCallManager*)manager stereoIntensity:(NSArray<NSArray<NSNumber*>*>*)lists timestamp:(NSTimeInterval)timestamp;
+
+
+@end
+
+
+/// 通话录音的管理类
+@interface JoyGemCallManager : NSObject
+
+/// 委托类
+/// - Description: 通话录音状态委托
+@property(nonatomic, weak) id<JoyGemCallManagerDelegate> delegate;
+
+/// 耳机识别语言
+@property(nonatomic, strong) NSString* originalLanguage;
+
+/// 是否正在录音
+@property(nonatomic, assign) BOOL isRecording;
+
+/// 是否支持立体声录音
+/// - NOTE:鉴权后再使用该字段
+@property(nonatomic, assign ,readonly) BOOL supportStereo;
+
+/// 单声道委托
+/// - Description: 固件支持单声道通话录音时会通过此委托进行回调
+@property(nonatomic, weak) id<JoyGemCallMonoDelegate> monoDelegate;
+
+/// 立体声委托
+/// - Description: 固件支持双声道通话录音时会通过此委托进行回调
+@property(nonatomic, weak) id<JoyGemCallStereoDelegate> stereoDelegate;
+
+/// 实例对象
++ (instancetype)shared;
+
+/// 开始通话录音
+- (void)start;
+
+/// 结束通话录音
+- (void)stop;
+
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemChatManager.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemChatManager.h
new file mode 100644 (file)
index 0000000..32c1303
--- /dev/null
@@ -0,0 +1,122 @@
+//
+//  JoyGemChatManager.h
+//  JoyGemAI
+//
+//  Created by JoyGem on 2025/2/21.
+//
+
+#import <Foundation/Foundation.h>
+#import <JoyGemAI/JoyGemEnum.h>
+
+@class JoyGemChatManager;
+@class JoyGemSpeaker;
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol JoyGemChatManagerDelegate <NSObject>
+
+///AI语音接收
+/// - Parameters:
+///   - data: 音频数据 pcm格式
+///   - index: 语句ID
+///   - sampleRate: 采样率
+///   - finish: 该句是否结束
+-(void)chatManager:(JoyGemChatManager*)manager audioData:(nullable NSData*)data index:(NSUInteger)index sampleRate:(NSUInteger)sampleRate finish:(BOOL)isFinish;
+
+///用户语音识别
+/// - Parameters:
+///   - text: 文字数据
+///   - index: 语句ID
+-(void)chatManager:(JoyGemChatManager*)manager requestText:(nullable NSString*)text index:(NSUInteger)index;
+
+///AI语音识别
+/// - Parameters:
+///   - text: 文字数据
+///   - index: 语句ID
+///   - isFinish\b:单次对话结束
+-(void)chatManager:(JoyGemChatManager*)manager responseText:(nullable NSString*)text index:(NSUInteger)index finish:(BOOL)isFinish;
+
+///对话状态回调
+/// - Parameters:
+///   - code: 状态变化
+@optional
+-(void)chatManager:(JoyGemChatManager*)manager stateChange:(JoyGemStateCode)code DEPRECATED_MSG_ATTRIBUTE("Use chatManager:eventUpdate instead");
+
+///对话事件回调
+/// - Parameters:
+///   - event: 对话相关事件回调
+/// - NOTE: 需要相关固件支持
+@optional
+-(void)chatManager:(JoyGemChatManager*)manager eventUpdate:(JoyGemChatEvent)event;
+
+/// 错误回调
+///  - Parameters:
+///   - mode:错误代码
+-(void)chatManager:(JoyGemChatManager*)manager onError:(JoyGemErrorCode)code;
+
+@optional
+-(void)chatManagerStopped:(JoyGemChatManager*)manager DEPRECATED_MSG_ATTRIBUTE("Use isActive instead");
+
+@end
+
+//AI对话的管理类
+@interface JoyGemChatManager : NSObject
+
+@property(nonatomic, weak) id<JoyGemChatManagerDelegate> delegate;
+
+//是否正在对话录音中
+@property(nonatomic, assign) BOOL isRecording;
+
+///是否正在活跃中
+/// - NOTE:可以采用KVO的方式监听该对象, 单次对话不会造成该状态改变
+@property(atomic, assign) BOOL isActive DEPRECATED_MSG_ATTRIBUTE("Use chatManager:eventUpdate instead \bif supportEvent is\b true");
+
+///是否支持事件上报模式
+/// - NOTE:鉴权后再使用该字段
+@property(nonatomic,assign,readonly) BOOL supportEvent;
+
+// 实例对象
++ (instancetype)shared;
+
+/// 开启单次对话
+/// - Note: 如正在播报,需要提前关闭tts后再调用,否则开启无效
+- (void)startSingleChat;
+
+/// 结束单次对话
+/// - Note:请勿在开启单次对话后立刻调用该方法,否则耳机可能不会处理该次请求
+- (void)stopSingleChat;
+
+/// 开启连续对话
+- (void)startChat;
+
+/// 结束连续对话
+- (void)stopChat;
+
+/// 播放音频开始前需要调用此方法告诉耳机
+- (void)playAudioStart;
+
+/// 播放音频结束时需要调用此方法告诉耳机
+/// - Description: 如果处于连续对话状态,则在调用该方法后会直接开启下一轮对话
+- (void)playAudioEnd;
+
+///获取支持角色列表
+/// - Parameters:
+///   - list: 角色列表
+-(void)getSpeakerList:(void (^)(NSArray<JoyGemSpeaker *>*))list;
+
+/// 配置当前角色
+-(void)setSpeaker:(JoyGemSpeaker*)speaker;
+
+/// 重置为默认角色
+-(void)resetSpearker;
+
+/// 进入英语口语陪练模式
+-(void)startSpoken;
+
+/// 退出英语口语陪练模式
+-(void)stopSpoken;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemDeviceManager.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemDeviceManager.h
new file mode 100644 (file)
index 0000000..39217c0
--- /dev/null
@@ -0,0 +1,101 @@
+//
+//  JoyGemDeviceManager.h
+//  JoyGemAI
+//
+//  Created by jjjs on 2025/9/1.
+//
+
+#import <Foundation/Foundation.h>
+#import "JoyGemEnum.h"
+#import "JoyGemModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface JoyGemDeviceManager : NSObject
+
+@property(nonatomic,assign) BOOL twsStatus;
+
+/// 获取mac地址
+/// - Returns:
+///     - edrAddress: 经典蓝牙地址
+///     - bleAddress:  ble蓝牙地址
+-(void)macAddress:(void (^)(NSString* edrAddress,NSString* bleAddress))address error:(void (^)( NSError * _Nullable err))error;
+
+/// 获取软件版本
+/// - Returns:
+///     - version:  软件版本
+-(void)software:(void (^)(NSString* version))infomation error:(void (^)( NSError * _Nullable err))error;
+
+
+/// 设置电量监听
+/// - Parameters:
+///  - left: 左耳电量
+///  - right: 右耳电量
+/// - Description: 电量范围为0~100,当未获取到电量时,电量为-1,配置回调时,如果有历史数据,会返回最后的历史数据,耳机会在电量变更时主动上报数据
+-(void)setBatteryListener:(void (^)(NSInteger left, NSInteger right))batteryListener;
+
+/// 主动获取电量
+-(void)updateBattery;
+
+/// 设置耳机状态监听
+/// - Parameters:
+///  - btConnected: 经典蓝牙连接状态
+///  - twsConnected : 双耳模式连接状态
+/// - Description: 部分设置需要在双耳模式下才能生效
+-(void)setStatusListener:(void (^)(BOOL btConnected,BOOL twsConnected))statusListener;
+
+/// 主动获取耳机状态
+-(void)updateStatus;
+
+/// 设置VAD打断状态
+/// - Parameters:
+///  - isOpen: VAD打断是否开启
+/// - Description: 该设置必须在双耳模式下才能生效,否则返回失败
+-(void)setVADInterruptedStatus:(BOOL)isOpen callback:(void (^)( NSError * _Nullable err))error;
+
+/// 获取VAD打断状态
+/// - Returns:
+///     - status:  VAD打断是否开启
+-(void)getVADInterruptedStatus:(void (^)(BOOL isOpen))status error:(void (^)( NSError * _Nullable err))error;
+
+
+/// 设置EQ模式
+/// - Parameters:
+///  - mode: \bEQ模式
+/// - Description: 该设置必须在双耳模式下才能生效,否则返回失败
+-(void)setEQMode:(JoyGemEQMode)mode callback:(void (^)( NSError * _Nullable err))error;
+
+/// 获取EQ模式
+/// - Returns:
+///     - mode:  VAD打断是否开启
+-(void)getEQMode:(void (^)(JoyGemEQMode mode))mode error:(void (^)( NSError * _Nullable err))error;
+
+/// 设置自定义EQ
+/// - Parameters:
+///  - index: 频段  范围为0~9
+///  - gain:  增益 范围为 -12~12
+/// - Description: 该设置必须在双耳模式下才能生效,否则返回失败
+-(void)setCustomEQ:(NSUInteger)index withGain:(NSInteger)gain callback:(void (^)( NSError * _Nullable err))error;
+
+/// 重置自定义EQ
+/// - Description: 该设置必须在双耳模式下才能生效,否则返回失败
+-(void)resetCustomEQ:(void (^)( NSError * _Nullable err))error;
+
+/// 获取自定义EQ
+/// - Returns:
+///    - custom:  自定义EQ类型
+-(void)getCustomEQ:(void (^)(JoyGemCustomEQ*))custom error:(void (^)( NSError * _Nullable err))error;
+
+/// 查找耳机
+/// - Parameters:
+///  - mode: 查找耳机命令类型
+-(void)findHeadphone:(JoyGemFindHeadphoneMode)mode callback:(void (^)( NSError * _Nullable err))error;
+
+/// 获取设备DN码
+/// - Parameters:
+///  - dn: 设备DN,取不到则返回空值
+-(void)getDN:(void (^)(NSString*))dn error:(void (^)( NSError * _Nullable err))error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemEnum.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemEnum.h
new file mode 100644 (file)
index 0000000..b95de14
--- /dev/null
@@ -0,0 +1,86 @@
+//
+//  JoyGemAIEnum.h
+//  JoyGemAI
+//
+//  Created by JoyGem on 2025/2/21.
+//
+
+#ifndef JoyGemAIEnum_h
+#define JoyGemAIEnum_h
+
+/// 状态变化
+typedef NS_OPTIONS(NSInteger,JoyGemStateCode) {
+    JoyGemStateCodeStartRecord = 1001,///开始录音
+    JoyGemStateCodeStopRecord = 1002,///停止录音
+    JoyGemStateCodeWebsocketConnected = 3001,///socket连上
+    JoyGemStateCodeWebsocketDisconnected = 3002,///socket断开连接
+};
+
+/// 错误
+typedef NS_OPTIONS(NSInteger,JoyGemErrorCode) {
+    JoyGemErrorCodeRecordError = 1003,///录音出错
+    JoyGemErrorCodeNetError = 3003,///网络错误
+    JoyGemErrorCodeUnAuth = 9999,///未鉴权
+};
+
+/// 录音类型
+typedef NS_ENUM(NSUInteger, JoyGemRecordMode) {
+    JoyGemRecordModeLive = 1,  ///现场录音
+    JoyGemRecordModeCall = 2,  ///通话录音
+};
+
+/// 日志类型
+typedef NS_ENUM(NSUInteger, JoyGemLogMode) {
+    JoyGemLogModeClose,   ///关闭日志
+    JoyGemLogModeSimple,  ///简略日志
+    JoyGemLogModeAll,     ///完整日志
+};
+
+/// 动作类型
+typedef NS_ENUM(NSUInteger, JoyGemActionMode) {
+    JoyGemActionModeCancel = 0,      ///关闭当前AI功能
+    JoyGemActionModeRecordLive = 1,  ///现场录音
+    JoyGemActionModeRecordCall = 2,  ///通话录音
+    JoyGemActionModeSi = 3,          ///同声传译
+    JoyGemActionModeChat = 4,        ///AI对话
+};
+
+/// 录音结束类型
+typedef NS_ENUM(NSUInteger, JoyGemRecordStopCode) {
+    JoyGemRecordStopCodeActively = 0,   ///用户主动关闭录音
+    JoyGemRecordStopCodePassively = 1,  ///用户被动关闭录音
+};
+
+
+/// 对话事件类型
+typedef NS_ENUM(NSUInteger, JoyGemChatEvent) {
+    JoyGemChatEventIdle = 0,                /// 空闲中
+    JoyGemChatEventBegin,                   /// 开始对话(单轮对话不会产生该事件)
+    JoyGemChatEventEnd,                     /// 结束对话(单轮对话不会产生该事件)
+    JoyGemChatEventNewRound,                /// 开始新一轮对话
+    JoyGemChatEventRecording,               /// 录音中
+    JoyGemChatEventRspWaiting,              /// 等待中
+    JoyGemChatEventPlaying,                 /// 正在播放声音
+    JoyGemChatEventPlayEnd,                 /// 结束播放声音
+};
+
+/// EQ类型
+typedef NS_ENUM(NSUInteger, JoyGemEQMode) {
+    JoyGemEQModeNormal,   ///普通
+    JoyGemEQModeRock,    ///摇滚
+    JoyGemEQModePop,        ///流行
+    JoyGemEQModeClassic,    ///经典
+    JoyGemEQModeJazz,       ///爵士
+    JoyGemEQModeCustom,      ///自定义
+};
+
+
+/// EQ类型
+typedef NS_ENUM(NSUInteger, JoyGemFindHeadphoneMode) {
+    JoyGemFindHeadphoneModeCancel,       ///关闭查找耳机
+    JoyGemFindHeadphoneModeLeft,        ///查找左耳
+    JoyGemFindHeadphoneModeRight,        ///查找右耳
+    JoyGemFindHeadphoneModeAll,         ///查找双耳
+};
+
+#endif /* JoyGemAIEnum_h */
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemModel.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemModel.h
new file mode 100644 (file)
index 0000000..3a7cf57
--- /dev/null
@@ -0,0 +1,55 @@
+//
+//  JoyGemAIModel.h
+//  JoyGemAI
+//
+//  Created by JoyGem on 2025/2/10.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+///AI对话角色
+@interface JoyGemSpeaker : NSObject
+
+@property (nonatomic, strong) NSString *sid;/// 音色id
+@property (nonatomic, strong) NSString *name;/// 名称
+@property (nonatomic, strong) NSString *type;/// 类型
+@property (nonatomic, strong) NSString *role;/// 角色
+
+///默认角色
++(JoyGemSpeaker*)defaultRole;
+
+///默认的口语陪练角色
++(JoyGemSpeaker*)defaultSpoken;
+
+@end
+
+///ASR对象
+@interface JoyGemAsrModel : NSObject
+
+@property (nonatomic, strong) NSString *text;   /// 文本
+@property (nonatomic, assign) NSUInteger index; /// 序号
+@property (nonatomic, assign) BOOL definite;    /// 片段化确定(不建议作为断句标识)
+
+@end
+
+///自定义EQ设置对象
+@interface JoyGemCustomEQ : NSObject
+
+@property (nonatomic, strong) NSArray<NSNumber*> *bands;
+
+@end
+
+///录音声纹识别
+@interface JoyGemRecordSpeaker : NSObject
+
+@property (nonatomic, copy, nullable) NSString *speakerId;     /// 说话人ID(字符串,如 "1")
+@property (nonatomic, assign) NSInteger startTime;             /// 起始时间(ms)
+@property (nonatomic, assign) NSInteger endTime;               /// 结束时间(ms)
+@property (nonatomic, copy, nullable) NSString *text;          /// 该段文本
+@property (nonatomic, assign) NSInteger index;                 /// 该段确定序号
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemParam.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemParam.h
new file mode 100644 (file)
index 0000000..b1f5ab6
--- /dev/null
@@ -0,0 +1,75 @@
+//
+//  JoyGemAIParam.h
+//  JoyGemAI
+//
+//  Created by JoyGem on 2025/2/10.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+///MARK: 语音语言
+
+//自动识别中英
+extern NSString* const kJoyGemAILocalizationAuto;
+
+//简体中文 zh-CN
+extern NSString* const kJoyGemAILocalizationZH;
+
+//英文  en-US
+extern NSString* const kJoyGemAILocalizationEN;
+
+//日语 ja-JP
+extern NSString* const kJoyGemAILocalizationJA;
+
+//韩语 ko-KR
+extern NSString* const kJoyGemAILocalizationKO;
+
+//法语 fr-FR
+extern NSString* const kJoyGemAILocalizationFR;
+
+//西班牙语 es-MX
+extern NSString* const kJoyGemAILocalizationES;
+
+//葡萄牙语 pt-BR
+extern NSString* const kJoyGemAILocalizationPT;
+
+//印尼语 id-ID
+extern NSString* const kJoyGemAILocalizationID;
+
+//俄语(输入) ru-RU
+extern NSString* const kJoyGemAILocalizationRU_Original;
+
+//俄语(输出) ru
+extern NSString* const kJoyGemAILocalizationRU_Target;
+
+//马来语 ms-MY
+extern NSString* const kJoyGemAILocalizationMS;
+
+//德语 de-DE
+extern NSString* const kJoyGemAILocalizationDE;
+
+//菲律宾语 fil-PH
+extern NSString* const kJoyGemAILocalizationFIL;
+
+//泰语 th-TH
+extern NSString* const kJoyGemAILocalizationTH;
+
+//阿拉伯语 ar-SA
+extern NSString* const kJoyGemAILocalizationAR;
+
+//越南语 vi
+extern NSString* const kJoyGemAILocalizationVI;
+
+
+
+///MARK: 蓝牙相关
+///
+///AI功能使用的蓝牙服务
+extern NSString* const kJoyGemAIServiceUUID;
+
+extern NSString* const kJoyGemAICharacteristicNotifyUUID;
+
+
+NS_ASSUME_NONNULL_END
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemRecordManager.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemRecordManager.h
new file mode 100644 (file)
index 0000000..e95de63
--- /dev/null
@@ -0,0 +1,102 @@
+//
+//  JoyGemRecordManager.h
+//  JoyGemAI
+//
+//  Created by JoyGem on 2025/2/21.
+//
+
+#import <Foundation/Foundation.h>
+#import <JoyGemAI/JoyGemEnum.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class JoyGemRecordManager;
+@class JoyGemAsrModel;
+@class JoyGemRecordSpeaker;
+
+//现场录音的委托类
+@protocol JoyGemRecordManagerDelegate <NSObject>
+
+///录音文字识别时
+/// - Parameters:
+///   - model: asr识别的对象
+@required
+-(void)recordManager:(JoyGemRecordManager*)manager didUpdateAsr:(JoyGemAsrModel*)model;
+
+///文件生成后的回调
+/// - Parameters:
+///   - path: 文件存储路径 wav格式
+-(void)recordManager:(JoyGemRecordManager*)manager saveFile:(NSString*)path;
+
+///录音状态回调
+/// - Parameters:
+///   - code: 状态变化
+-(void)recordManager:(JoyGemRecordManager*)manager stateChange:(JoyGemStateCode)code;
+
+/// 录音错误回调
+///  - Parameters:
+///   - mode:错误代码
+-(void)recordManager:(JoyGemRecordManager*)manager onError:(JoyGemErrorCode)code;
+
+///结束时的回调
+/// - Parameters:
+///   - code: 录音结束的原因
+-(void)recordManagerStopped:(JoyGemRecordManager*)manager reason:(JoyGemRecordStopCode)code;
+
+/// 录音完成时的回调
+/// - Description: 录音任务调用结束后,会在服务器所有响应结束后进行回调
+/// - Note: 该接口仅在任务成功完成时才会进行回调,并不保证和stop方法实现一一对应,
+@optional
+-(void)recordManagerCompleted:(JoyGemRecordManager*)manager;
+
+/// 录音时的声波强度回调
+/// - Parameters:
+///   - list: 强度数组
+///   - timestamp: 时间戳(ms)
+@optional
+-(void)recordManager:(JoyGemRecordManager*)manager intensity:(NSArray<NSNumber*>*)list timestamp:(NSTimeInterval)timestamp;
+
+/// 录音时的说话人区分
+/// - Parameters:
+///   - list: 强度数组
+///   - timestamp: 时间戳(ms)
+@optional
+-(void)recordManager:(JoyGemRecordManager*)manager speakers:(NSArray<JoyGemRecordSpeaker*>*)list;
+
+@end
+
+/// 现场录音的管理类
+@interface JoyGemRecordManager : NSObject
+
+/// 委托类
+@property(nonatomic, weak) id<JoyGemRecordManagerDelegate> delegate;
+
+/// 耳机识别语言
+@property(nonatomic, strong) NSString* originalLanguage;
+
+/// 是否正在暂停中
+@property(nonatomic,assign) BOOL isPause;
+
+/// 是否开启声纹识别
+@property(nonatomic,assign) BOOL useVpr;
+
+/// 实例对象
++ (instancetype)shared;
+
+/// 开启现场录音
+- (void)start;
+
+/// 结束现场录音
+- (void)stop;
+
+/// 暂停录音
+- (void)pause;
+
+/// 恢复录音
+- (void)resume;
+
+
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemSIDeviceManager.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemSIDeviceManager.h
new file mode 100644 (file)
index 0000000..826b9c6
--- /dev/null
@@ -0,0 +1,91 @@
+//
+//  JoyGemSIDeviceManager.h
+//  JoyGemAI
+//
+//  Created by jjjs on 2025/5/21.
+//
+
+#import <UIKit/UIKit.h>
+#import <JoyGemAI/JoyGemEnum.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class JoyGemSIDeviceManager;
+@class JoyGemAsrModel;
+
+/// 同声传译(设备)的管理类
+@protocol JoyGemSIDeviceManagerDelegate <NSObject>
+
+///录音文字识别时
+/// - Parameters:
+///   - model: asr识别的对象
+@required
+-(void)siDeviceManager:(JoyGemSIDeviceManager*)manager didUpdateRaw:(JoyGemAsrModel*)model;
+
+///录音文字翻译时
+/// - Parameters:
+///   - model: asr识别的对象
+@required
+-(void)siDeviceManager:(JoyGemSIDeviceManager*)manager didUpdateTranslate:(JoyGemAsrModel*)model;
+
+///音频数据更新时
+/// - Parameters:
+///   - data: 流数据 pcm格式
+@required
+-(void)siDeviceManager:(JoyGemSIDeviceManager*)manager didUpdateAudioData:(NSData*)data sampleRate:(NSUInteger)sampleRate;
+
+///结束时的回调
+/// - Parameters:
+///   - code: 录音结束的原因
+-(void)siDeviceManagerStopped:(JoyGemSIDeviceManager*)manager reason:(JoyGemRecordStopCode)code;
+
+/// 录音完成时的回调
+/// - Description: 录音任务调用结束后,会在服务器所有响应结束后进行回调
+/// - Note: 该接口仅在任务成功完成时才会进行回调,并不保证和stop方法实现一一对应
+@optional
+-(void)siDeviceManagerCompleted:(JoyGemSIDeviceManager*)manager;
+
+///文件生成后的回调
+/// - Parameters:
+///   - path: 文件存储路径 wav格式
+-(void)siDeviceManager:(JoyGemSIDeviceManager*)manager saveFile:(NSString*)path;
+
+///录音状态回调
+/// - Parameters:
+///   - code: 状态变化
+-(void)siDeviceManager:(JoyGemSIDeviceManager*)manager stateChange:(JoyGemStateCode)code;
+
+/// 录音错误回调
+///  - Parameters:
+///   - mode:错误代码
+-(void)siDeviceManager:(JoyGemSIDeviceManager*)manager onError:(JoyGemErrorCode)code;
+
+@end
+
+/// 同声传译(设备)的管理类
+@interface JoyGemSIDeviceManager : NSObject
+
+/// 委托类
+@property(nonatomic, weak) id<JoyGemSIDeviceManagerDelegate> delegate;
+
+/// 耳机识别语言
+@property(nonatomic, strong) NSString* originalLanguage;
+
+/// 耳机输出语言
+@property(nonatomic, strong) NSString* targetLanguage;
+
+/// 是否正在录音
+@property(nonatomic,assign) BOOL isRecording;
+
+/// 实例对象
++ (instancetype)shared;
+
+/// 开始同声传译(设备)
+- (void)start;
+
+/// 结束同声传译(设备)
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemSIManager.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemSIManager.h
new file mode 100644 (file)
index 0000000..bf64e1c
--- /dev/null
@@ -0,0 +1,91 @@
+//
+//  JoyGemSIManager.h
+//  JoyGemAI
+//
+//  Created by JoyGem on 2025/2/21.
+//
+
+#import <Foundation/Foundation.h>
+#import <JoyGemAI/JoyGemEnum.h>
+
+@class JoyGemSIManager;
+@class JoyGemAsrModel;
+
+NS_ASSUME_NONNULL_BEGIN
+
+//同声传译的委托类
+@protocol JoyGemSIManagerDelegate <NSObject>
+
+///录音文字识别时
+/// - Parameters:
+///   - model: asr识别的对象
+@required
+-(void)siManager:(JoyGemSIManager*)manager didUpdateRaw:(JoyGemAsrModel*)model;
+
+///录音文字翻译时
+/// - Parameters:
+///   - model: asr识别的对象
+@required
+-(void)siManager:(JoyGemSIManager*)manager didUpdateTranslate:(JoyGemAsrModel*)model;
+
+///音频数据更新时
+/// - Parameters:
+///   - data: 流数据 pcm格式
+@required
+-(void)siManager:(JoyGemSIManager*)manager didUpdateAudioData:(NSData*)data sampleRate:(NSUInteger)sampleRate;
+
+///录音状态切换时
+-(void)siManager:(JoyGemSIManager*)manager stateChange:(JoyGemStateCode)code;
+
+///结束时的回调
+/// - Parameters:
+///   - code: 录音结束的原因
+-(void)siManagerStopped:(JoyGemSIManager*)manager reason:(JoyGemRecordStopCode)code;
+
+/// 录音完成时的回调
+/// - Description: 录音任务调用结束后,会在服务器所有响应结束后进行回调
+/// - Note: 该接口仅在任务成功完成时才会进行回调,并不保证和stop方法实现一一对应
+@optional
+-(void)siManagerCompleted:(JoyGemSIManager*)manager;
+
+///文件生成后的回调
+/// - Parameters:
+///   - path: 文件存储路径 wav格式
+-(void)siManager:(JoyGemSIManager*)manager saveFile:(NSString*)path;
+
+/// 错误回调
+-(void)siManager:(JoyGemSIManager*)manager onError:(JoyGemErrorCode)code;
+
+@end
+
+/// 同声传译的管理类
+@interface JoyGemSIManager : NSObject
+
+@property(nonatomic, weak) id<JoyGemSIManagerDelegate> delegate;
+
+///原始语言
+///目前原始语言设置无效,默认为kJoyGemAILocalizationAuto
+@property(nonatomic, strong) NSString* originalLanguage;
+
+///目标语言
+///默认为kJoyGemAILocalizationAuto,可以设置为中文或者英文
+@property(nonatomic, strong) NSString* targetLanguage;
+
+/// 是否正在录音
+@property(nonatomic,assign) BOOL isRecording;
+
+
+/// 实例对象
++ (instancetype)shared;
+
+/// 开启同声传译
+- (void)start;
+
+/// 结束同声传译
+- (void)stop;
+
+
+@end
+
+NS_ASSUME_NONNULL_END
+
diff --git a/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemSubtitleManager.h b/ShenYin/framework/JoyGemAI.framework/Headers/JoyGemSubtitleManager.h
new file mode 100644 (file)
index 0000000..18f6bc5
--- /dev/null
@@ -0,0 +1,79 @@
+//
+//  JoyGemSubtitleManager.h
+//  JoyGemAI
+//
+//  Created by jjjs on 2025/10/17.
+//
+
+#import <Foundation/Foundation.h>
+#import <JoyGemAI/JoyGemEnum.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class JoyGemSubtitleManager;
+@class JoyGemAsrModel;
+
+/// 字幕翻译的委托
+@protocol JoyGemSubtitleManagerDelegate <NSObject>
+
+///录音文字识别时
+/// - Parameters:
+///   - model: asr识别的对象
+@required
+-(void)subtitleManager:(JoyGemSubtitleManager*)manager didUpdateRaw:(JoyGemAsrModel*)model;
+
+///录音文字翻译时
+/// - Parameters:
+///   - model: asr识别的对象
+@required
+-(void)subtitleManager:(JoyGemSubtitleManager*)manager didUpdateTranslate:(JoyGemAsrModel*)model;
+
+///结束时的回调
+/// - Parameters:
+///   - code: 录音结束的原因
+-(void)subtitleManagerStopped:(JoyGemSubtitleManager*)manager;
+
+///录音状态回调
+/// - Parameters:
+///   - code: 状态变化
+-(void)subtitleManager:(JoyGemSubtitleManager*)manager stateChange:(JoyGemStateCode)code;
+
+/// 录音错误回调
+///  - Parameters:
+///   - mode:错误代码
+-(void)subtitleManager:(JoyGemSubtitleManager*)manager onError:(JoyGemErrorCode)code;
+
+@end
+
+//字幕翻译的管理类
+@interface JoyGemSubtitleManager : NSObject
+
+/// 委托类
+/// - Description: 字幕翻译状态委托
+@property(nonatomic, weak) id<JoyGemSubtitleManagerDelegate> delegate;
+
+/// 耳机识别语言
+@property(nonatomic, strong) NSString* originalLanguage;
+
+/// 耳机输出语言
+@property(nonatomic, strong) NSString* targetLanguage;
+
+/// 是否正在录音
+@property(nonatomic, assign) BOOL isRecording;
+
+/// 是否支持字幕翻译功能
+@property(nonatomic, assign) BOOL support;
+
+
+/// 实例对象
++ (instancetype)shared;
+
+/// 开始字幕翻译
+- (void)start;
+
+/// 结束字幕翻译
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ShenYin/framework/JoyGemAI.framework/Info.plist b/ShenYin/framework/JoyGemAI.framework/Info.plist
new file mode 100644 (file)
index 0000000..3374824
Binary files /dev/null and b/ShenYin/framework/JoyGemAI.framework/Info.plist differ
diff --git a/ShenYin/framework/JoyGemAI.framework/JoyGemAI b/ShenYin/framework/JoyGemAI.framework/JoyGemAI
new file mode 100755 (executable)
index 0000000..b8dcb56
Binary files /dev/null and b/ShenYin/framework/JoyGemAI.framework/JoyGemAI differ
diff --git a/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo b/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo
new file mode 100644 (file)
index 0000000..8ef7c46
Binary files /dev/null and b/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo differ
diff --git a/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.abi.json b/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.abi.json
new file mode 100644 (file)
index 0000000..993acce
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "ABIRoot": {
+    "kind": "Root",
+    "name": "JoyGemAI",
+    "printedName": "JoyGemAI",
+    "children": [
+      {
+        "kind": "Import",
+        "name": "Foundation",
+        "printedName": "Foundation",
+        "declKind": "Import",
+        "moduleName": "JoyGemAI",
+        "declAttributes": [
+          "RawDocComment"
+        ]
+      }
+    ],
+    "json_format_version": 8
+  },
+  "ConstValues": []
+}
\ No newline at end of file
diff --git a/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.private.swiftinterface b/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.private.swiftinterface
new file mode 100644 (file)
index 0000000..428908e
--- /dev/null
@@ -0,0 +1,10 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
+// swift-module-flags: -target arm64-apple-ios13.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -enable-bare-slash-regex -module-name JoyGemAI
+// swift-module-flags-ignorable: -no-verify-emitted-module-interface
+import Foundation
+@_exported import JoyGemAI
+import Swift
+import _Concurrency
+import _StringProcessing
+import _SwiftConcurrencyShims
diff --git a/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc b/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc
new file mode 100644 (file)
index 0000000..8d660ce
Binary files /dev/null and b/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc differ
diff --git a/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftinterface b/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftinterface
new file mode 100644 (file)
index 0000000..428908e
--- /dev/null
@@ -0,0 +1,10 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
+// swift-module-flags: -target arm64-apple-ios13.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -enable-bare-slash-regex -module-name JoyGemAI
+// swift-module-flags-ignorable: -no-verify-emitted-module-interface
+import Foundation
+@_exported import JoyGemAI
+import Swift
+import _Concurrency
+import _StringProcessing
+import _SwiftConcurrencyShims
diff --git a/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule b/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule
new file mode 100644 (file)
index 0000000..1001f97
Binary files /dev/null and b/ShenYin/framework/JoyGemAI.framework/Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule differ
diff --git a/ShenYin/framework/JoyGemAI.framework/Modules/module.modulemap b/ShenYin/framework/JoyGemAI.framework/Modules/module.modulemap
new file mode 100644 (file)
index 0000000..f9d9ea3
--- /dev/null
@@ -0,0 +1,11 @@
+framework module JoyGemAI {
+  umbrella header "JoyGemAI.h"
+  export *
+
+  module * { export * }
+}
+
+module JoyGemAI.Swift {
+  header "JoyGemAI-Swift.h"
+  requires objc
+}
diff --git a/ShenYin/framework/JoyGemAI.framework/PrivacyInfo.xcprivacy b/ShenYin/framework/JoyGemAI.framework/PrivacyInfo.xcprivacy
new file mode 100644 (file)
index 0000000..c8b6829
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!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>
+               <dict>
+                       <key>NSPrivacyCollectedDataType</key>
+                       <string>NSPrivacyCollectedDataTypeAudioData</string>
+                       <key>NSPrivacyCollectedDataTypeLinked</key>
+                       <false/>
+                       <key>NSPrivacyCollectedDataTypeTracking</key>
+                       <false/>
+                       <key>NSPrivacyCollectedDataTypePurposes</key>
+                       <array>
+                               <string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
+                       </array>
+               </dict>
+       </array>
+       <key>NSPrivacyTrackingDomains</key>
+       <array/>
+       <key>NSPrivacyAccessedAPITypes</key>
+       <array/>
+</dict>
+</plist>
diff --git a/ShenYin/framework/JoyGemAI.framework/_CodeSignature/CodeResources b/ShenYin/framework/JoyGemAI.framework/_CodeSignature/CodeResources
new file mode 100644 (file)
index 0000000..39407de
--- /dev/null
@@ -0,0 +1,333 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>files</key>
+       <dict>
+               <key>Headers/JoyGemAI-Swift.h</key>
+               <data>
+               okSjIYqQdjYFuhBqjGvwfYh8+aU=
+               </data>
+               <key>Headers/JoyGemAI.h</key>
+               <data>
+               7HO7XUA3NdXWlvtUWyiYdTaaZ4M=
+               </data>
+               <key>Headers/JoyGemAIManager.h</key>
+               <data>
+               D/pnfOpF7qKhUfhoTsKEfdEQQRQ=
+               </data>
+               <key>Headers/JoyGemCallManager.h</key>
+               <data>
+               j3rnAsYkKzhbISebVqN00PCSeTk=
+               </data>
+               <key>Headers/JoyGemChatManager.h</key>
+               <data>
+               RmM4HQA4Ay7VLvTFWPw7s69sqBk=
+               </data>
+               <key>Headers/JoyGemDeviceManager.h</key>
+               <data>
+               GnuSbYAD+3F7R21VuV35n97Bubk=
+               </data>
+               <key>Headers/JoyGemEnum.h</key>
+               <data>
+               M1/juV+sL7ggbp4Y9srW0rq/Dqo=
+               </data>
+               <key>Headers/JoyGemModel.h</key>
+               <data>
+               WP0CE48Wvoq3FJX4ldz90bcNpTw=
+               </data>
+               <key>Headers/JoyGemParam.h</key>
+               <data>
+               fq/eezzfuJFDMFtH+PXLOMYQQCs=
+               </data>
+               <key>Headers/JoyGemRecordManager.h</key>
+               <data>
+               GzBtgXRPoBuyG0YwvFmoGA8Yg20=
+               </data>
+               <key>Headers/JoyGemSIDeviceManager.h</key>
+               <data>
+               aH1rBy/dU7IVJkpw/BVW3BvfNtk=
+               </data>
+               <key>Headers/JoyGemSIManager.h</key>
+               <data>
+               363bn6W4/w8F3xEYQrU0LEVD/XM=
+               </data>
+               <key>Headers/JoyGemSubtitleManager.h</key>
+               <data>
+               fDUdqGo5wSc78huSI4OUK8Qr8AU=
+               </data>
+               <key>Info.plist</key>
+               <data>
+               yyyfSn0pDOYFx2gtlmBDVpKhVxw=
+               </data>
+               <key>Modules/JoyGemAI.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo</key>
+               <data>
+               CPeqh4HaaR/F9LP2LFiPwE3Qxzo=
+               </data>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.abi.json</key>
+               <data>
+               iVs2bUNJJDbD/ENi/Q0lo4aP3uk=
+               </data>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.private.swiftinterface</key>
+               <data>
+               sOTjmG3OZu9FvWVYyTuqSix+tzU=
+               </data>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc</key>
+               <data>
+               s/YEyU+lH4pYoG62jihLM2SJPTU=
+               </data>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftinterface</key>
+               <data>
+               sOTjmG3OZu9FvWVYyTuqSix+tzU=
+               </data>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule</key>
+               <data>
+               OKLv2mrRkW9EiT9AdyIjFh6WmI8=
+               </data>
+               <key>Modules/module.modulemap</key>
+               <data>
+               qguEoXSNM0mFX+7WmMXUO3TTSLk=
+               </data>
+               <key>PrivacyInfo.xcprivacy</key>
+               <data>
+               SRctDO3cqibONLEG7CPcNZVBnXw=
+               </data>
+       </dict>
+       <key>files2</key>
+       <dict>
+               <key>Headers/JoyGemAI-Swift.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       Jktn0pvS86rbDKXpgT8xSUtpGRzWvf2yzqxwqMqFKS4=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemAI.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       AWVDZqJirRMWfVQc7FdxP1cjTTx2LWTSTwHDN0/ySRA=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemAIManager.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       hAXAZoFB6Ja0kc5Gm3Bo952k9fZUiSUPYM2f9gyTkQw=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemCallManager.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       eKpRq8GaSD9YaI7Tfafc4BVLc/Vz2rS7cEcx8W6S+EI=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemChatManager.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       TrJNORF2yq5ZRf++PfcoxEwE0ic9W2VxQ+Nz7M7WKPM=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemDeviceManager.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       b8SW0vyfvdZ5JjAexckdczSXWjl11+WIJDM6wuHhBEo=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemEnum.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       6xL0kb6k/tdSxOKLIazlAA2o8gm1ZE3njRHg40EOYMw=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemModel.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       0kLzuK/HuYBvk9JPhWYbR2z7t1XSX83X5Am9ZD+vLXw=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemParam.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       QKmLGG6IwVxT2QonEGJzea6rMbUX0PBNGoWpzqSNRbY=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemRecordManager.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       ep9EdHop9Qn0M9nCT7YwmHXxJh/XXCjBqtYjErKFd+8=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemSIDeviceManager.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       x40L/ElpDJCMjpEBZZancy57toshn0DM6MOhkwnIMYQ=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemSIManager.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       NTKnVzoipmhtgLLzocc8J5kT4Q2qmUmVhZ3MgZUrbkA=
+                       </data>
+               </dict>
+               <key>Headers/JoyGemSubtitleManager.h</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       jGDopDnKVm0z/p6dEPEs54wWT6iwbetpqbTXTk8zoAQ=
+                       </data>
+               </dict>
+               <key>Modules/JoyGemAI.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       dSyxVyC1vMbliDqKuW0d31f2wCYxeWsx2/NHJQYPrRc=
+                       </data>
+               </dict>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.abi.json</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       li11LC5FIVL81dorkSyLKnyNa2JtjEuBDo/IzoAeVCU=
+                       </data>
+               </dict>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.private.swiftinterface</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       Xu9oOK+bUwZsz7YKaBS7sdDWZvQJwX6GCeM7UKDOIew=
+                       </data>
+               </dict>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       4ZSTOVNx5VInV3CLCGXGsOKMICdleteG1O8aHABZCzw=
+                       </data>
+               </dict>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftinterface</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       Xu9oOK+bUwZsz7YKaBS7sdDWZvQJwX6GCeM7UKDOIew=
+                       </data>
+               </dict>
+               <key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       nRKcutC82zySWegf6JkCelatcDI5wxHUuHo6O2D+Osc=
+                       </data>
+               </dict>
+               <key>Modules/module.modulemap</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       EYrXhwPscfz6NC5xiiSHpFYdSR7Z5+JCyV2sAnxwmPc=
+                       </data>
+               </dict>
+               <key>PrivacyInfo.xcprivacy</key>
+               <dict>
+                       <key>hash2</key>
+                       <data>
+                       cuaVRkQIQRl8fLAPRH2XlUdsPxO0W90uL0WcSHvmSnY=
+                       </data>
+               </dict>
+       </dict>
+       <key>rules</key>
+       <dict>
+               <key>^.*</key>
+               <true/>
+               <key>^.*\.lproj/</key>
+               <dict>
+                       <key>optional</key>
+                       <true/>
+                       <key>weight</key>
+                       <real>1000</real>
+               </dict>
+               <key>^.*\.lproj/locversion.plist$</key>
+               <dict>
+                       <key>omit</key>
+                       <true/>
+                       <key>weight</key>
+                       <real>1100</real>
+               </dict>
+               <key>^Base\.lproj/</key>
+               <dict>
+                       <key>weight</key>
+                       <real>1010</real>
+               </dict>
+               <key>^version.plist$</key>
+               <true/>
+       </dict>
+       <key>rules2</key>
+       <dict>
+               <key>.*\.dSYM($|/)</key>
+               <dict>
+                       <key>weight</key>
+                       <real>11</real>
+               </dict>
+               <key>^(.*/)?\.DS_Store$</key>
+               <dict>
+                       <key>omit</key>
+                       <true/>
+                       <key>weight</key>
+                       <real>2000</real>
+               </dict>
+               <key>^.*</key>
+               <true/>
+               <key>^.*\.lproj/</key>
+               <dict>
+                       <key>optional</key>
+                       <true/>
+                       <key>weight</key>
+                       <real>1000</real>
+               </dict>
+               <key>^.*\.lproj/locversion.plist$</key>
+               <dict>
+                       <key>omit</key>
+                       <true/>
+                       <key>weight</key>
+                       <real>1100</real>
+               </dict>
+               <key>^Base\.lproj/</key>
+               <dict>
+                       <key>weight</key>
+                       <real>1010</real>
+               </dict>
+               <key>^Info\.plist$</key>
+               <dict>
+                       <key>omit</key>
+                       <true/>
+                       <key>weight</key>
+                       <real>20</real>
+               </dict>
+               <key>^PkgInfo$</key>
+               <dict>
+                       <key>omit</key>
+                       <true/>
+                       <key>weight</key>
+                       <real>20</real>
+               </dict>
+               <key>^embedded\.provisionprofile$</key>
+               <dict>
+                       <key>weight</key>
+                       <real>20</real>
+               </dict>
+               <key>^version\.plist$</key>
+               <dict>
+                       <key>weight</key>
+                       <real>20</real>
+               </dict>
+       </dict>
+</dict>
+</plist>