// StarburstConfig.shared().sdkFolder = NSHomeDirectory() + "/Documents/DeepChordsSdk"
// 日志路径
// StarburstConfig.shared().logPath = logFilePath()
- StarburstConfig.shared().logPath = nil
+// StarburstConfig.shared().logPath = nil
//是否下发文字到耳机仓
StarburstConfig.shared().enableTextSyncToDevice = false
//主从耳机切换是否同步sdk信息到耳机
644D1BB5EDD3EA1D77C57786 /* Pods_DeepChordsSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 248D8B53B5A178ACA5867275 /* Pods_DeepChordsSdk.framework */; };
7666589AAA94A323B6090425 /* Pods_playboy.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4F1BB919D567C3B6B0EBAA7 /* Pods_playboy.framework */; };
7A6613B4B617D6E71D34944C /* Pods_ShenYin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90FF0C8B0D4D6AE0933FA672 /* Pods_ShenYin.framework */; };
- 817510A595D00CAD05E3772C /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
- F2E449CAD5874BE652A69B50 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
+ 817510A595D00CAD05E3772C /* (null) in Frameworks */ = {isa = PBXBuildFile; };
+ F2E449CAD5874BE652A69B50 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
Sdk/JoySdk/VC/JoyTctyVC.swift,
Sdk/JoySdk/VC/JoyXclyVC.swift,
Sdk/JoySdk/VC/ModeVC.swift,
+ UI/Home/SubTitle/LanguagePickerView1.swift,
+ UI/Home/SubTitle/PiPManager.swift,
+ UI/Home/SubTitle/PipPicker.swift,
+ UI/Home/SubTitle/PipSetView.swift,
+ UI/Home/SubTitle/SubTitleVC.swift,
);
target = 3FD1DFE32F0E00BF00A62733 /* playboy */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */
- 3FCC8B152F1E0280004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" build phase */ = {
+ 3FCC8B152F1E0280004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" phase from "ShenYin" target */ = {
isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
+ attributesByRelativePath = {
+ Sdk/JoySdk/tool/JoyGemAI.framework = (CodeSignOnCopy, RemoveHeadersOnCopy, );
+ };
buildPhase = 3FEFE9092F1B252000D82F17 /* Embed Frameworks */;
membershipExceptions = (
Sdk/JoySdk/tool/JoyGemAI.framework,
);
};
- 3FCC8B1A2F1E030E004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" build phase */ = {
+ 3FCC8B1A2F1E030E004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" phase from "playboy" target */ = {
isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
+ attributesByRelativePath = {
+ Sdk/DcSdk/tool/JLAudioUnitKit.xcframework = (CodeSignOnCopy, RemoveHeadersOnCopy, );
+ };
buildPhase = 3FD1DFEF2F0E00BF00A62733 /* Embed Frameworks */;
membershipExceptions = (
Sdk/DcSdk/tool/JLAudioUnitKit.xcframework,
);
};
- 3FFB77C62F17A11100EF9A60 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" build phase */ = {
+ 3FFB77C62F17A11100EF9A60 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" phase from "DeepChordsSdk" target */ = {
isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
+ attributesByRelativePath = {
+ StarburstSdk.framework = (CodeSignOnCopy, RemoveHeadersOnCopy, );
+ };
buildPhase = 3FFB77C52F17A11100EF9A60 /* Embed Frameworks */;
membershipExceptions = (
StarburstSdk.framework,
0D54E0F02F0A61E600A80EE7 /* DeepChordsSdk */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
- 3FFB77C62F17A11100EF9A60 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" build phase */,
+ 3FFB77C62F17A11100EF9A60 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" phase from "DeepChordsSdk" target */,
3FFB77C82F17A14C00EF9A60 /* Exceptions for "DeepChordsSdk" folder in "playboy" target */,
);
path = DeepChordsSdk;
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
3F887BAE2E38D8DD00C98658 /* Exceptions for "ShenYin" folder in "ShenYin" target */,
- 3FCC8B152F1E0280004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" build phase */,
+ 3FCC8B152F1E0280004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" phase from "ShenYin" target */,
3FD1DFF52F0E00BF00A62733 /* Exceptions for "ShenYin" folder in "playboy" target */,
- 3FCC8B1A2F1E030E004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" build phase */,
+ 3FCC8B1A2F1E030E004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" phase from "playboy" target */,
3F03696C2F2B604900F3CB95 /* Exceptions for "ShenYin" folder in "playboy copy" target */,
);
path = ShenYin;
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- F2E449CAD5874BE652A69B50 /* BuildFile in Frameworks */,
+ F2E449CAD5874BE652A69B50 /* (null) in Frameworks */,
7A6613B4B617D6E71D34944C /* Pods_ShenYin.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
buildActionMask = 2147483647;
files = (
3FFB77C12F179F3100EF9A60 /* DeepChordsSdk.framework in Frameworks */,
- 817510A595D00CAD05E3772C /* BuildFile in Frameworks */,
+ 817510A595D00CAD05E3772C /* (null) in Frameworks */,
30B13DEF1AA0E4C54D873276 /* Pods_playboy.framework in Frameworks */,
7666589AAA94A323B6090425 /* Pods_playboy.framework in Frameworks */,
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-resources-${CONFIGURATION}-input-files.xcfilelist",
);
+ inputPaths = (
+ );
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-resources-${CONFIGURATION}-output-files.xcfilelist",
);
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-resources.sh\"\n";
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-playboy/Pods-playboy-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
+ inputPaths = (
+ );
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-playboy/Pods-playboy-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-playboy/Pods-playboy-frameworks.sh\"\n";
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
+ inputPaths = (
+ );
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks.sh\"\n";
CODE_SIGN_ENTITLEMENTS = ShenYin/PLAYBOY.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 202603031106;
+ CURRENT_PROJECT_VERSION = 202603051206;
DEVELOPMENT_TEAM = JKLJ58J33Q;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "ShenYin/ShenYin copy-Info.plist";
- INFOPLIST_KEY_CFBundleDisplayName = PLAYBOY;
+ INFOPLIST_KEY_CFBundleDisplayName = "PLAYBOY眼镜";
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "扫描附近蓝牙设备需要获得权限";
INFOPLIST_KEY_NSCameraUsageDescription = "修改用户头像、提交意见反馈需要访问相册使用摄像头";
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 1.0.0;
+ MARKETING_VERSION = 0.01;
PRODUCT_BUNDLE_IDENTIFIER = com.ios.playboy;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
CODE_SIGN_ENTITLEMENTS = ShenYin/PLAYBOY.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 202603031106;
+ CURRENT_PROJECT_VERSION = 202603051206;
DEVELOPMENT_TEAM = JKLJ58J33Q;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "ShenYin/ShenYin copy-Info.plist";
- INFOPLIST_KEY_CFBundleDisplayName = PLAYBOY;
+ INFOPLIST_KEY_CFBundleDisplayName = "PLAYBOY眼镜";
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "扫描附近蓝牙设备需要获得权限";
INFOPLIST_KEY_NSCameraUsageDescription = "修改用户头像、提交意见反馈需要访问相册使用摄像头";
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 1.0.0;
+ MARKETING_VERSION = 0.01;
PRODUCT_BUNDLE_IDENTIFIER = com.ios.playboy;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "2620"
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES"
+ buildArchitectures = "Automatic">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "3FD1DFE32F0E00BF00A62733"
+ BuildableName = "playboy.app"
+ BlueprintName = "playboy"
+ ReferencedContainer = "container:ShenYin.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ shouldAutocreateTestPlan = "YES">
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "3FD1DFE32F0E00BF00A62733"
+ BuildableName = "playboy.app"
+ BlueprintName = "playboy"
+ ReferencedContainer = "container:ShenYin.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "3FD1DFE32F0E00BF00A62733"
+ BuildableName = "playboy.app"
+ BlueprintName = "playboy"
+ ReferencedContainer = "container:ShenYin.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Slice 49@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Slice 49@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Slice 47@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Slice 47@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let model = DeviceVM.shared.dataList[indexPath.row]
- App.shared.goToPage(AiFunctionVC(device: model))
+// App.shared.goToPage(AiFunctionVC(device: model))
+
+ if #available(iOS 15.0, *) {
+ App.shared.goToPage(SubTitleVC())
+ } else {
+ // Fallback on earlier versions
+ }
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView{
<string>bluetooth-central</string>
<string>audio</string>
</array>
- <key>UIViewControllerBasedStatusBarAppearance</key>
- <true/>
<key>UIDesignRequiresCompatibility</key>
<true/>
+ <key>UIViewControllerBasedStatusBarAppearance</key>
+ <true/>
</dict>
</plist>
func setupUI(){
if CCDevice.isJoy{
let homeVC = HomeDeviceVC()
-// let homeVC = CustomerVC()
+
let modeVC = ModeVC()
let sleepVC = SleepVC()
--- /dev/null
+//
+// Untitled.swift
+// ShenYin
+//
+// Created by liangshi on 2026/3/5.
+//
+
+import UIKit
+import JoyGemAI
+@available(iOS 15.0, *)
+// MARK: - 数据模型
+struct LanguageModel {
+
+ let code: String
+ let name: String
+ let nativeName: String
+
+ static let chinese = LanguageModel(code: kJoyGemAILocalizationZH, name: "Chinese", nativeName: "中文")
+ static let english = LanguageModel(code: kJoyGemAILocalizationEN, name: "English", nativeName: "英语")
+ static let japanese = LanguageModel(code: kJoyGemAILocalizationJA, name: "Japanese", nativeName: "日本語")
+ static let korean = LanguageModel(code: kJoyGemAILocalizationKO, name: "Korean", nativeName: "韩语")
+ static let french = LanguageModel(code: kJoyGemAILocalizationFR, name: "French", nativeName: "法语")
+ static let spanish = LanguageModel(code: kJoyGemAILocalizationES, name: "Spanish", nativeName: "西班牙语")
+ static let portuguese = LanguageModel(code: kJoyGemAILocalizationPT, name: "Portuguese", nativeName: "葡萄牙语")
+ static let indonesia = LanguageModel(code: kJoyGemAILocalizationID, name: "Indonesia", nativeName: "印尼语")
+ static let russian_ori = LanguageModel(code: kJoyGemAILocalizationRU_Original, name: "Russian", nativeName: "俄语")
+ static let russian_tar = LanguageModel(code: kJoyGemAILocalizationRU_Target, name: "Russian", nativeName: "俄语")
+ static let malay = LanguageModel(code: kJoyGemAILocalizationMS, name: "Malay", nativeName: "马来语")
+ static let german = LanguageModel(code: kJoyGemAILocalizationDE, name: "German", nativeName: "德语")
+ static let filipino = LanguageModel(code: kJoyGemAILocalizationFIL, name: "Filipino", nativeName: "菲律宾语")
+ static let thai = LanguageModel(code: kJoyGemAILocalizationTH, name: "Thai", nativeName: "泰语")
+ static let arabic = LanguageModel(code: kJoyGemAILocalizationAR, name: "Arabic", nativeName: "阿拉伯语")
+ static let vietnamese = LanguageModel(code: kJoyGemAILocalizationVI, name: "Vietnamese", nativeName: "越南语")
+}
+
+// 语言选择器的委托协议
+@available(iOS 15.0, *)
+protocol LanguagePickerView1Delegate: AnyObject {
+
+ func languagePickerView(_ pickerView: LanguagePickerView1,
+ didSelectSourceLanguage source: LanguageModel,
+ targetLanguage target: LanguageModel)
+
+ func languagePickerViewDidTapSwap(_ pickerView: LanguagePickerView1)
+}
+@available(iOS 15.0, *)
+class LanguagePickerView1: UIView {
+
+ // MARK: - UI 组件
+ private let sourcePickerView = UIPickerView()
+ private let targetPickerView = UIPickerView()
+ private let swapButton = UIButton(type: .system)
+ private let sourceLabel = UILabel()
+ private let targetLabel = UILabel()
+
+ // MARK: - 属性
+ weak var delegate: LanguagePickerView1Delegate?
+
+ var selectedSourceLanguage: LanguageModel? {
+ didSet { updateSelection() }
+ }
+
+ var selectedTargetLanguage: LanguageModel? {
+ didSet { updateSelection() }
+ }
+
+ var languages: [LanguageModel] = [
+ .chinese, .english, .japanese,.korean,.french,.spanish,.portuguese,.indonesia,.russian_ori,.malay,.german,.filipino,.thai,.arabic,.vietnamese
+ ]
+
+ // MARK: - 初始化
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ setupUI()
+ setupDefaults()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ setupUI()
+ setupDefaults()
+ }
+
+ // MARK: - UI 设置
+ private func setupUI() {
+ backgroundColor = .systemBackground
+
+ setupLabels()
+ setupPickerViews()
+ setupSwapButton()
+ setupConstraints()
+ }
+
+ private func setupLabels() {
+ sourceLabel.text = "源语言"
+ sourceLabel.font = UIFont.boldSystemFont(ofSize: 16)
+ sourceLabel.textAlignment = .center
+ addSubview(sourceLabel)
+
+ targetLabel.text = "目标语言"
+ targetLabel.font = UIFont.boldSystemFont(ofSize: 16)
+ targetLabel.textAlignment = .center
+ addSubview(targetLabel)
+ }
+
+ private func setupPickerViews() {
+ // 源语言选择器
+ sourcePickerView.translatesAutoresizingMaskIntoConstraints = false
+ sourcePickerView.dataSource = self
+ sourcePickerView.delegate = self
+ sourcePickerView.tag = 0
+ addSubview(sourcePickerView)
+
+ // 目标语言选择器
+ targetPickerView.translatesAutoresizingMaskIntoConstraints = false
+ targetPickerView.dataSource = self
+ targetPickerView.delegate = self
+ targetPickerView.tag = 1
+ addSubview(targetPickerView)
+ }
+
+ private func setupSwapButton() {
+ swapButton.translatesAutoresizingMaskIntoConstraints = false
+ swapButton.setImage(UIImage(systemName: "arrow.left.arrow.right"), for: .normal)
+ swapButton.tintColor = .systemBlue
+ swapButton.backgroundColor = .systemGray6
+ swapButton.layer.cornerRadius = 20
+ swapButton.addTarget(self, action: #selector(swapButtonTapped), for: .touchUpInside)
+ addSubview(swapButton)
+ }
+
+ private func setupConstraints() {
+ sourceLabel.snp.makeConstraints { make in
+ make.top.equalToSuperview().offset(8)
+ make.leading.equalToSuperview().offset(20)
+ make.trailing.equalTo(swapButton.snp.leading).offset(-20)
+ make.height.equalTo(20)
+ }
+
+ targetLabel.snp.makeConstraints { make in
+ make.top.equalToSuperview().offset(8)
+ make.trailing.equalToSuperview().offset(-20)
+ make.leading.equalTo(swapButton.snp.trailing).offset(20)
+ make.height.equalTo(20)
+ }
+
+ sourcePickerView.snp.makeConstraints { make in
+ make.top.equalTo(sourceLabel.snp.bottom).offset(8)
+ make.leading.equalToSuperview().offset(20)
+ make.trailing.equalTo(swapButton.snp.leading).offset(-20)
+ make.bottom.equalToSuperview().offset(-8)
+ }
+
+ targetPickerView.snp.makeConstraints { make in
+ make.top.equalTo(targetLabel.snp.bottom).offset(8)
+ make.trailing.equalToSuperview().offset(-20)
+ make.leading.equalTo(swapButton.snp.trailing).offset(20)
+ make.bottom.equalToSuperview().offset(-8)
+ }
+
+ swapButton.snp.makeConstraints { make in
+ make.centerX.equalToSuperview()
+ make.centerY.equalTo(sourcePickerView.snp.centerY)
+ make.height.equalTo(40)
+ make.width.equalTo(40)
+ }
+ }
+
+ private func setupDefaults() {
+ // 设置默认选择
+ if let chineseIndex = languages.firstIndex(where: { $0.code == "zh" }) {
+ sourcePickerView.selectRow(chineseIndex, inComponent: 0, animated: false)
+ selectedSourceLanguage = languages[chineseIndex]
+ }
+
+ if let englishIndex = languages.firstIndex(where: { $0.code == "en" }) {
+ targetPickerView.selectRow(englishIndex, inComponent: 0, animated: false)
+ selectedTargetLanguage = languages[englishIndex]
+ }
+ }
+
+ // MARK: - 公共方法
+ func setLanguages(source: LanguageModel, target: LanguageModel) {
+ if let sourceIndex = languages.firstIndex(where: { $0.code == source.code }) {
+ sourcePickerView.selectRow(sourceIndex, inComponent: 0, animated: true)
+ selectedSourceLanguage = source
+ }
+
+ if let targetIndex = languages.firstIndex(where: { $0.code == target.code }) {
+ targetPickerView.selectRow(targetIndex, inComponent: 0, animated: true)
+ selectedTargetLanguage = target
+ }
+ }
+
+ func getSelectedLanguages() -> (source: LanguageModel?, target: LanguageModel?) {
+ return (selectedSourceLanguage, selectedTargetLanguage)
+ }
+
+ // MARK: - 私有方法
+ private func updateSelection() {
+ // 可以在这里添加选择更新后的逻辑
+ print("源语言: \(selectedSourceLanguage?.nativeName ?? "无")")
+ print("目标语言: \(selectedTargetLanguage?.nativeName ?? "无")")
+
+ // 通知委托
+ if let source = selectedSourceLanguage, let target = selectedTargetLanguage {
+ delegate?.languagePickerView(self, didSelectSourceLanguage: source, targetLanguage: target)
+ }
+ }
+
+ @objc private func swapButtonTapped() {
+ guard let source = selectedSourceLanguage,
+ let target = selectedTargetLanguage else { return }
+
+ // 交换语言
+ setLanguages(source: target, target: source)
+
+ // 通知委托
+ delegate?.languagePickerViewDidTapSwap(self)
+ }
+}
+
+// MARK: - UIPickerView DataSource & Delegate
+@available(iOS 15.0, *)
+extension LanguagePickerView1: UIPickerViewDataSource, UIPickerViewDelegate {
+
+ func numberOfComponents(in pickerView: UIPickerView) -> Int {
+ return 1
+ }
+
+ func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
+ return languages.count
+ }
+
+ func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
+ let language = languages[row]
+ return "\(language.nativeName) (\(language.name))"
+ }
+
+ func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
+ let selectedLanguage = languages[row]
+
+ if pickerView.tag == 0 {
+ selectedSourceLanguage = selectedLanguage
+ } else {
+ selectedTargetLanguage = selectedLanguage
+ }
+
+ // 防止选择相同的语言
+ validateSelection()
+ }
+
+ func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
+ return 44.0
+ }
+
+ func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
+ let language = languages[row]
+
+ let containerView = UIView()
+ containerView.backgroundColor = .clear
+
+ let stackView = UIStackView()
+ stackView.axis = .vertical
+ stackView.alignment = .center
+ stackView.spacing = 2
+ stackView.translatesAutoresizingMaskIntoConstraints = false
+
+ let nativeLabel = UILabel()
+ nativeLabel.text = language.nativeName
+ nativeLabel.font = UIFont.systemFont(ofSize: 16, weight: .medium)
+ nativeLabel.textAlignment = .center
+ nativeLabel.textColor = .label
+
+ let nameLabel = UILabel()
+ nameLabel.text = language.name
+ nameLabel.font = UIFont.systemFont(ofSize: 12, weight: .regular)
+ nameLabel.textColor = .secondaryLabel
+ nameLabel.textAlignment = .center
+
+ stackView.addArrangedSubview(nativeLabel)
+ stackView.addArrangedSubview(nameLabel)
+ containerView.addSubview(stackView)
+
+ NSLayoutConstraint.activate([
+ stackView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
+ stackView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
+ stackView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 8),
+ stackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -8)
+ ])
+
+ return containerView
+ }
+
+ private func validateSelection() {
+ guard let source = selectedSourceLanguage,
+ let target = selectedTargetLanguage,
+ source.code == target.code else { return }
+
+ // 如果选择了相同的语言,自动调整目标语言
+ if let alternativeIndex = languages.firstIndex(where: { $0.code != source.code }) {
+ targetPickerView.selectRow(alternativeIndex, inComponent: 0, animated: true)
+ selectedTargetLanguage = languages[alternativeIndex]
+ }
+ }
+}
--- /dev/null
+//
+// Untitled.swift
+// ShenYin
+//
+// Created by liangshi on 2026/3/5.
+//
+
+import AVKit
+import UIKit
+
+@available(iOS 15.0, *)
+class PiPManager: NSObject, ObservableObject {
+
+ var pipController: AVPictureInPictureController?
+
+ var contentVC: DesktopLyricsContentVC!
+
+ var messageList : [(String,UInt)] = []
+
+ var translateList : [(String,UInt)] = []
+
+ func setupPictureInPicture(sourceView : UIView) {
+
+ contentVC = DesktopLyricsContentVC()
+ contentVC.preferredContentSize = CGSize(width: UIScreen.main.bounds.width, height: 240) // 画中画窗口大小
+
+ // 设置播放器
+ pipController = AVPictureInPictureController(contentSource: AVPictureInPictureController.ContentSource(
+ activeVideoCallSourceView: sourceView,
+ contentViewController: contentVC
+ ))
+ pipController?.delegate = self
+ }
+
+
+ func startPictureInPicture() {
+ // 1. 检查场景状态
+ if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
+ print("场景激活状态: \(scene.activationState.rawValue)")
+ print("场景状态描述: \(describeActivationState(scene.activationState))")
+ } else {
+ print("❌ 无法获取场景")
+ }
+
+ pipController?.startPictureInPicture()
+ }
+
+ private func describeActivationState(_ state: UIScene.ActivationState) -> String {
+ switch state {
+ case .unattached: return "unattached - 场景未连接到会话"
+ case .foregroundInactive: return "foregroundInactive - 前景但不活跃"
+ case .foregroundActive: return "foregroundActive - 前景且活跃 ✅"
+ case .background: return "background - 后台"
+ @unknown default: return "unknown"
+ }
+ }
+
+ func stopPictureInPicture() {
+ pipController?.stopPictureInPicture()
+ }
+
+ func updateRaw(_ text: String,_ index: UInt) {
+ let msg = messageList.firstIndex (where: { (str,idx) in
+ return idx == index;
+ })
+ if (msg == nil) {
+ messageList.append((text,index))
+ } else {
+ messageList[msg!] = (text,index)
+ }
+
+ let res = messageList.compactMap({ (str,idx) in
+ return str
+ }).joined(separator: "\n")
+ contentVC?.updateRaw(res)
+ }
+
+ func updateTrans(_ text: String,_ index: UInt) {
+ let msg = translateList.firstIndex (where: { (str,idx) in
+ return idx == index;
+ })
+ if (msg == nil) {
+ translateList.append((text,index))
+ } else {
+ translateList[msg!] = (text,index)
+ }
+
+ let res = translateList.compactMap({ (str,idx) in
+ return str
+ }).joined(separator: "\n")
+ contentVC?.updateTrans(res)
+ }
+}
+
+@available(iOS 15.0, *)
+extension PiPManager: AVPictureInPictureControllerDelegate {
+ func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
+ print("画中画即将开始")
+ }
+
+ func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
+ print("画中画已开始")
+ // 开始播放透明视频
+ //player?.play()
+ }
+
+ func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
+ print("画中画启动失败: \(error)")
+ }
+
+
+ func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
+ print("画中画已结束")
+// messageList.removeAll()
+// translateList.removeAll()
+ }
+}
+// 画中画内容视图控制器
+@available(iOS 15.0, *)
+class DesktopLyricsContentVC : AVPictureInPictureVideoCallViewController {
+ let setView = PipSetView()
+ var textView = UITextView()
+ var translateTextView = UITextView()
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupViews()
+ setupLayout()
+ }
+ func setupViews(){
+ view.addSubviews([setView,textView,translateTextView])
+
+ textView.do { v in
+ v.textColor = UIColor.white
+ v.text = "原文"
+ v.font = UIFont.boldSystemFont(ofSize: 14)
+ v.backgroundColor = UIColor.gray
+ }
+
+ translateTextView.do { v in
+ v.textColor = UIColor.orange
+ v.text = "翻译"
+ v.font = UIFont.boldSystemFont(ofSize: 14)
+ v.backgroundColor = UIColor.gray
+ }
+ }
+ func setupLayout(){
+ setView.snp.makeConstraints { make in
+ make.left.right.equalToSuperview()
+ make.height.equalTo(34)
+ make.top.equalToSuperview()
+ }
+ textView.snp.makeConstraints { make in
+ make.top.equalToSuperview().inset(40)
+ make.leading.trailing.equalToSuperview()
+ make.bottom.equalTo(view.snp.centerY)
+ }
+ translateTextView.snp.makeConstraints { make in
+ make.leading.trailing.equalToSuperview()
+ make.top.equalTo(textView.snp.bottom)
+ make.height.equalTo(textView.snp.height)
+ }
+
+ }
+
+ func updateRaw(_ text: String) {
+ textView.text = text
+ textView.scrollRangeToVisible(NSRange(location: textView.text.count, length: 0))
+ }
+
+ func updateTrans(_ text : String) {
+ translateTextView.text = text
+ translateTextView.scrollRangeToVisible(NSRange(location: translateTextView.text.count, length: 0))
+ }
+}
--- /dev/null
+//
+// Untitled.swift
+// ShenYin
+//
+// Created by liangshi on 2026/3/6.
+//
+
+import UIKit
+class PipPicker: BaseView {
+ private let btn = UIButton(type: .custom)
+ private let tableView = UITableView(frame: .zero, style: .plain)
+ var list:[String] = []
+
+ var selectedIndex = 0{
+ didSet{
+ tableView.reloadData()
+ }
+ }
+ var didSelected: ((Int,String)->Void)?
+ private var title:String = ""
+
+ init(list:[String]) {
+ super.init(frame: .zero)
+ }
+
+ @MainActor required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func setupViews() {
+ addSubviews([btn,tableView])
+
+ btn.do { v in
+ v.setImage(UIImage(named: "close_icon"), for: .normal)
+ v.addTarget(self, action: #selector(closeAction), for: .touchUpInside)
+ }
+ tableView.do { v in
+ v.backgroundColor = .color(.cellBg)
+ v.delegate = self
+ v.dataSource = self
+ v.rowHeight = 52
+ v.separatorStyle = .none
+ v.register(CustomButton.SelectCell.self, forCellReuseIdentifier: CustomButton.SelectCell.reuseID)
+ }
+ }
+ override func setupLayout() {
+ super.setupLayout()
+ btn.snp.makeConstraints { (m) in
+ m.bottom.equalToSuperview()
+ m.right.equalToSuperview()
+ m.size.equalTo(60)
+ }
+ tableView.snp.makeConstraints { make in
+ make.left.right.bottom.equalToSuperview()
+ make.top.equalToSuperview().inset(10)
+ }
+ }
+ @objc func closeAction(){
+
+ }
+}
+extension PipPicker:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = CustomButton.SelectCell.cell(withTableView: tableView, indexPath: indexPath)
+ cell.titleLabel.text = list[indexPath.row]
+ cell.selectedIcon.isHidden = selectedIndex != indexPath.row
+ return cell
+ }
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ selectedIndex = indexPath.row
+ tableView.reloadData()
+ didSelected?(selectedIndex,list[selectedIndex])
+ }
+}
+
+fileprivate extension CustomButton {
+ class SelectCell: BaseTableViewCell {
+ let bgView = UIView()
+ let titleLabel = UILabel()
+ let selectedIcon = UIImageView()
+ let line = UIView()
+
+ var fontType:FontType = .min{
+ didSet{
+ titleLabel.text = fontType.title
+ }
+ }
+
+ var shareType:ShareType = .document{
+ didSet{
+ titleLabel.text = shareType.title
+ }
+ }
+
+ var enable:Bool = true{
+ didSet{
+ if enable{
+ titleLabel.textColor = .color(.first)
+ }
+ else{
+ titleLabel.textColor = .color(.secondary)
+ }
+ }
+ }
+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+ super.init(style: style, reuseIdentifier: reuseIdentifier)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+ override func setupViews() {
+ contentView.addSubview(bgView)
+ bgView.addSubviews([titleLabel,selectedIcon,line])
+
+ backgroundColor = .color(.bgColor)
+ contentView.backgroundColor = .clear
+ selectionStyle = .none
+ bgView.do { v in
+ v.backgroundColor = .color(.cellBg)
+ }
+ titleLabel.do { (v) in
+ v.textColor = .color(.first)
+ v.font = .bold(14)
+ v.textAlignment = .left
+ }
+
+ selectedIcon.image = UIImage(named: "cell_selected")
+ line.do { v in
+ v.backgroundColor = .color(.separateLine)
+ }
+ }
+
+ override func setupLayout() {
+ bgView.snp.makeConstraints { (m) in
+ m.left.right.equalToSuperview()
+ m.top.equalToSuperview()
+ m.bottom.equalToSuperview()
+ }
+ selectedIcon.snp.makeConstraints { (m) in
+ m.width.equalTo(21)
+ m.height.equalTo(16)
+ m.right.equalToSuperview().inset(21)
+ m.centerY.equalToSuperview()
+ }
+ titleLabel.snp.makeConstraints { (m) in
+ m.centerY.equalToSuperview()
+ m.left.equalToSuperview().offset(24)
+ m.height.equalToSuperview()
+ }
+ line.snp.makeConstraints { make in
+ make.left.right.equalToSuperview().inset(18)
+ make.bottom.equalToSuperview()
+ make.height.equalTo(0.4)
+ }
+ }
+ }
+
+}
+
--- /dev/null
+//
+// PipSetView.swift
+// ShenYin
+//
+// Created by liangshi on 2026/3/6.
+//
+
+class PipSetView: BaseView {
+ let setBtn = UIButton(type: .custom)
+ let closeBtn = UIButton(type: .custom)
+ let languageItem = UIButton(type: .custom)
+ let dispalyItem = UIButton(type: .custom)
+
+ override func setupViews() {
+ addSubviews([setBtn,languageItem,dispalyItem,closeBtn])
+
+ setBtn.do { v in
+ v.setImage(UIImage(named: "pip_set"), for: .normal)
+ v.addTarget(self, action: #selector(setBtnAction), for: .touchUpInside)
+ }
+ closeBtn.do { v in
+ v.setImage(UIImage(named: "pip_close"), for: .normal)
+ v.addTarget(self, action: #selector(closeAction), for: .touchUpInside)
+ }
+ languageItem.do { v in
+ v.setTitle("", for: .normal)
+ v.addTarget(self, action: #selector(languageAction), for: .touchUpInside)
+ v.yc.setCornerRadius(12)
+ v.backgroundColor = .red
+ }
+ dispalyItem.do { v in
+ v.setTitle("", for: .normal)
+ v.addTarget(self, action: #selector(displayAction), for: .touchUpInside)
+ v.yc.setCornerRadius(12)
+ v.backgroundColor = .red
+ }
+ }
+ override func setupLayout() {
+ setBtn.snp.makeConstraints { make in
+ make.size.equalTo(24)
+ make.left.equalToSuperview().inset(16)
+ make.top.equalToSuperview().inset(10)
+ }
+ closeBtn.snp.makeConstraints { make in
+ make.size.equalTo(24)
+ make.right.equalToSuperview().inset(16)
+ make.centerY.equalTo(setBtn)
+ }
+ languageItem.snp.makeConstraints { make in
+ make.height.equalTo(24)
+ make.left.equalTo(setBtn.snp.right).offset(4)
+ make.centerY.equalTo(setBtn)
+ make.width.equalTo(57)
+ }
+ dispalyItem.snp.makeConstraints { make in
+ make.height.equalTo(24)
+ make.left.equalTo(languageItem.snp.right).offset(4)
+ make.centerY.equalTo(setBtn)
+ make.width.equalTo(57)
+ }
+ }
+ @objc func setBtnAction(){
+ Logger.debug("setBtnAction")
+ }
+ @objc func languageAction(){
+ Logger.debug("languageAction")
+ }
+ @objc func displayAction(){
+ Logger.debug("displayAction")
+ let view = PipPicker(list: ["只显示原文","只显译文","原文 & 译文"])
+ superview?.addSubview(view)
+ }
+ @objc func closeAction(){
+ Logger.debug("closeAction")
+
+ }
+}
--- /dev/null
+//
+// Untitled.swift
+// ShenYin
+//
+// Created by liangshi on 2026/3/5.
+//
+
+
+import UIKit
+import AVKit
+import JoyGemAI
+import SVProgressHUD
+@available(iOS 15.0, *)
+class SubTitleVC: UIViewController {
+
+ lazy var languagePickerView : LanguagePickerView1 = {
+ let pickerView = LanguagePickerView1()
+ pickerView.delegate = self
+ return pickerView
+ }()
+
+ var startButton : UIButton!
+
+ var stopButton : UIButton!
+ let pipManager = PiPManager()
+
+
+ //画中画载体
+ internal var customView : UIView = UIView()
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ view.backgroundColor = UIColor.white
+ title = "字幕翻译"
+
+ self.navigationController?.navigationBar.tintColor = UIColor.black
+ do {
+ try AVAudioSession.sharedInstance().setCategory(.playback)
+ try AVAudioSession.sharedInstance().setActive(true)
+ } catch {
+ print(error)
+ }
+
+ view.addSubview(languagePickerView)
+ languagePickerView.snp.makeConstraints { make in
+ make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
+ make.leading.trailing.equalToSuperview()
+ make.height.equalTo(100)
+ }
+
+ // 或者设置特定语言
+ languagePickerView.setLanguages(
+ source: LanguageModel.chinese,
+ target: LanguageModel.english
+ )
+
+ view.addSubview(customView)
+ customView.snp.makeConstraints { make in
+ make.top.equalTo(languagePickerView.snp.bottom).offset(20)
+ make.height.equalTo(40)
+ make.centerX.equalToSuperview()
+ make.width.equalTo(200)
+ }
+
+ startButton = UIButton(type: .system)
+ startButton.setTitle("开始", for: .normal)
+ startButton.backgroundColor = UIColor.systemGray6
+ startButton.setTitleColor(UIColor.darkText, for: .normal)
+ startButton.addTarget(self, action: #selector(startRecord), for: .touchUpInside)
+
+ stopButton = UIButton(type: .system)
+ stopButton.setTitle("结束", for: .normal)
+ stopButton.backgroundColor = UIColor.systemGray6
+ stopButton.setTitleColor(UIColor.darkText, for: .normal)
+ stopButton.addTarget(self, action: #selector(endRecord), for: .touchUpInside)
+
+ let stackView = UIStackView(arrangedSubviews: [startButton, stopButton])
+ stackView.axis = .horizontal
+ stackView.distribution = .fillEqually
+ stackView.alignment = .center
+ stackView.spacing = 16
+
+ view.addSubview(stackView)
+ stackView.snp.makeConstraints { make in
+ make.height.equalTo(60)
+ make.leading.equalToSuperview().offset(20)
+ make.trailing.equalToSuperview().offset(-20)
+ make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-20)
+ }
+
+ // Do any additional setup after loading the view.
+ JoyGemSubtitleManager.shared().delegate = self
+
+ setupPiPManager()
+ }
+
+ private func setupPiPManager() {
+ // 初始化画中画管理器
+ pipManager.setupPictureInPicture(sourceView: self.customView)
+
+ // 监听画中画状态变化
+ NotificationCenter.default.addObserver(
+ self,
+ selector: #selector(pipStateChanged(_:)),
+ name: NSNotification.Name("PiPStateChanged"),
+ object: nil
+ )
+ }
+
+ @objc func startRecord() {
+ JoyGemSubtitleManager.shared().start()
+
+ guard AVPictureInPictureController.isPictureInPictureSupported() else {
+ print("设备不支持画中画")
+ return
+ }
+
+ pipManager.startPictureInPicture()
+ }
+
+ @objc func endRecord() {
+ JoyGemSubtitleManager.shared().stop()
+
+ pipManager.stopPictureInPicture()
+ }
+
+ @objc private func pipStateChanged(_ notification: Notification) {
+ if let userInfo = notification.userInfo,
+ let isActive = userInfo["isActive"] as? Bool {
+ print("画中画状态: \(isActive ? "活跃" : "非活跃")")
+ }
+ }
+}
+
+// 实现委托方法
+@available(iOS 15.0, *)
+extension SubTitleVC: LanguagePickerView1Delegate {
+
+ func languagePickerView(_ pickerView: LanguagePickerView1,
+ didSelectSourceLanguage source: LanguageModel,
+ targetLanguage target: LanguageModel) {
+ print("语言选择更新: \(source.nativeName) -> \(target.nativeName)")
+ // 更新你的翻译逻辑等
+ JoyGemSubtitleManager.shared().originalLanguage = source.code
+ JoyGemSubtitleManager.shared().targetLanguage = target.code
+ }
+
+ func languagePickerViewDidTapSwap(_ pickerView: LanguagePickerView1) {
+ print("交换了语言")
+ }
+}
+
+@available(iOS 15.0, *)
+extension SubTitleVC : JoyGemSubtitleManagerDelegate {
+
+ func subtitleManager(_ manager: JoyGemSubtitleManager, didUpdateRaw model: JoyGemAsrModel) {
+ debugPrint("text: \(model.text),index: \(model.index)")
+ pipManager.updateRaw(model.text,model.index)
+ }
+
+ func subtitleManager(_ manager: JoyGemSubtitleManager, didUpdateTranslate model: JoyGemAsrModel) {
+ debugPrint("translate text: \(model.text),index: \(model.index)")
+ pipManager.updateTrans(model.text,model.index)
+ }
+
+ func subtitleManagerStopped(_ manager: JoyGemSubtitleManager) {
+
+ }
+
+ func subtitleManager(_ manager: JoyGemSubtitleManager, stateChange code: JoyGemStateCode) {
+
+ }
+
+ func subtitleManager(_ manager: JoyGemSubtitleManager, onError code: JoyGemErrorCode) {
+
+ }
+
+ func subTitleManager(_ manager: JoyGemSubtitleManager, stateChange code: JoyGemStateCode) {
+ debugPrint("code: \(code)")
+ }
+
+ func subTitleManager(_ manager: JoyGemSubtitleManager, onError code: JoyGemErrorCode) {
+
+ }
+
+}