From 858e7c7440670753db62efcffb43c5d38e218475 Mon Sep 17 00:00:00 2001 From: TrueZhuanjia Date: Wed, 24 Sep 2025 12:49:25 +0800 Subject: [PATCH] feat: use built-in mic --- VoidLink/Base.lproj/iPad.storyboard | 22 ++++++++++ VoidLink/Base.lproj/iPhone.storyboard | 32 +++++++++++--- VoidLink/Database/DataManager.h | 1 + VoidLink/Database/DataManager.m | 2 + VoidLink/Database/TemporarySettings.h | 1 + VoidLink/Database/TemporarySettings.m | 1 + VoidLink/Input/MicHandler.swift | 15 ++++++- .../VoidLink v1.0.xcdatamodel/contents | 1 + VoidLink/Localization/Localizable.xcstrings | 29 ++++++++++++ .../ViewControllers/MainFrameViewController.m | 2 + .../ViewControllers/SettingsViewController.h | 3 ++ .../ViewControllers/SettingsViewController.m | 12 ++++- .../StreamFrameViewController.m | 2 +- VoidLink/mul.lproj/iPad.xcstrings | 44 ++++++++++++++++--- VoidLink/mul.lproj/iPhone.xcstrings | 30 +++++++++++++ 15 files changed, 182 insertions(+), 15 deletions(-) diff --git a/VoidLink/Base.lproj/iPad.storyboard b/VoidLink/Base.lproj/iPad.storyboard index 4ce8b453..373eb8e5 100644 --- a/VoidLink/Base.lproj/iPad.storyboard +++ b/VoidLink/Base.lproj/iPad.storyboard @@ -1155,6 +1155,26 @@ + + + + + + + + + + + + + + + @@ -1258,6 +1278,8 @@ + + diff --git a/VoidLink/Base.lproj/iPhone.storyboard b/VoidLink/Base.lproj/iPhone.storyboard index eb41ec1d..a33e7a19 100644 --- a/VoidLink/Base.lproj/iPhone.storyboard +++ b/VoidLink/Base.lproj/iPhone.storyboard @@ -1869,7 +1869,7 @@ - + + + + + + + + + + + + + + + + @@ -1990,6 +2010,8 @@ + + @@ -2011,19 +2033,19 @@ - + - + - + - + diff --git a/VoidLink/Database/DataManager.h b/VoidLink/Database/DataManager.h index d5213527..c3ab661b 100644 --- a/VoidLink/Database/DataManager.h +++ b/VoidLink/Database/DataManager.h @@ -88,6 +88,7 @@ typedef NS_ENUM(NSInteger, WidgetSizeTransition) { swapABXYButtons:(BOOL)swapABXYButtons audioOnPC:(BOOL)audioOnPC redirectMic:(BOOL)redirectMic + useBuiltinMic:(BOOL)useBuiltinMic preferredCodec:(uint32_t)preferredCodec enableYUV444:(BOOL)enableYUV444 enablePIP:(BOOL)enablePIP diff --git a/VoidLink/Database/DataManager.m b/VoidLink/Database/DataManager.m index 15937ac1..7c1585fc 100644 --- a/VoidLink/Database/DataManager.m +++ b/VoidLink/Database/DataManager.m @@ -83,6 +83,7 @@ swapABXYButtons:(BOOL)swapABXYButtons audioOnPC:(BOOL)audioOnPC redirectMic:(BOOL)redirectMic + useBuiltinMic:(BOOL)useBuiltinMic preferredCodec:(uint32_t)preferredCodec enableYUV444:(BOOL)enableYUV444 enablePIP:(BOOL)enablePIP @@ -134,6 +135,7 @@ settingsToSave.swapABXYButtons = swapABXYButtons; settingsToSave.playAudioOnPC = audioOnPC; settingsToSave.redirectMic = redirectMic; + settingsToSave.useBuiltinMic = useBuiltinMic; settingsToSave.preferredCodec = preferredCodec; settingsToSave.enableYUV444 = enableYUV444; settingsToSave.enablePIP = enablePIP; diff --git a/VoidLink/Database/TemporarySettings.h b/VoidLink/Database/TemporarySettings.h index 9acfaf83..cc2e4fd3 100644 --- a/VoidLink/Database/TemporarySettings.h +++ b/VoidLink/Database/TemporarySettings.h @@ -57,6 +57,7 @@ @property (nonatomic) BOOL swapABXYButtons; @property (nonatomic) BOOL playAudioOnPC; @property (nonatomic) BOOL redirectMic; +@property (nonatomic) BOOL useBuiltinMic; @property (nonatomic) BOOL optimizeGames; @property (nonatomic) BOOL enableHdr; @property (nonatomic) BOOL btMouseSupport; diff --git a/VoidLink/Database/TemporarySettings.m b/VoidLink/Database/TemporarySettings.m index b5723a5f..76802096 100644 --- a/VoidLink/Database/TemporarySettings.m +++ b/VoidLink/Database/TemporarySettings.m @@ -91,6 +91,7 @@ self.frameQueueSize = settings.frameQueueSize; self.playAudioOnPC = settings.playAudioOnPC; self.redirectMic = settings.redirectMic; + self.useBuiltinMic = settings.useBuiltinMic; self.enableHdr = settings.enableHdr; self.optimizeGames = settings.optimizeGames; self.multiController = settings.multiController; diff --git a/VoidLink/Input/MicHandler.swift b/VoidLink/Input/MicHandler.swift index 527eecc4..02adc98c 100644 --- a/VoidLink/Input/MicHandler.swift +++ b/VoidLink/Input/MicHandler.swift @@ -20,6 +20,7 @@ public class MicHandler: NSObject { private var audioSink: Any? private var micInputFormat: AVAudioFormat! private var isRecording = false + private var useBuiltinMic = false private var pcm16Buffer: [Int16] = [] private let bufferQueue = DispatchQueue(label: "pcm.buffer.queue") @@ -42,8 +43,9 @@ public class MicHandler: NSObject { public weak var delegate: MicHandlerDelegate? - public override init() { + @objc public init(useBuiltinMic:Bool) { super.init() + self.useBuiltinMic = useBuiltinMic do { try configureSession() try configureEngine() @@ -185,6 +187,17 @@ public class MicHandler: NSObject { try session.setAllowHapticsAndSystemSoundsDuringRecording(true) } try session.setActive(true) + + // 列出所有可用输入 + if self.useBuiltinMic, let inputs = session.availableInputs { + for port in inputs { + if port.portType == .builtInMic { + try session.setPreferredInput(port) + print("Set preferred input to built-in mic") + break + } + } + } } private func sendOpusFrame() { diff --git a/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents b/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents index 6befb009..e86ad2cc 100644 --- a/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents +++ b/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents @@ -71,6 +71,7 @@ + \ No newline at end of file diff --git a/VoidLink/Localization/Localizable.xcstrings b/VoidLink/Localization/Localizable.xcstrings index 3f897c5e..4b149a4f 100644 --- a/VoidLink/Localization/Localizable.xcstrings +++ b/VoidLink/Localization/Localizable.xcstrings @@ -5670,6 +5670,35 @@ } } }, + "useBuiltinMicStackTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When enabled, app will use built-in mic when Bluetooth headset is connected, which benefits audio quality." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "开启后, App将在蓝牙耳机接入状态下使用设备内置麦克风, 以维持蓝牙耳机最佳音质。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "開啟後,App 在藍牙耳機連接時將使用裝置內建麥克風,以維持藍牙耳機的最佳音質。" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "開啟後,App 在藍牙耳機連接時將使用裝置內建麥克風,以維持藍牙耳機的最佳音質。" + } + } + } + }, "Version %@" : { }, diff --git a/VoidLink/ViewControllers/MainFrameViewController.m b/VoidLink/ViewControllers/MainFrameViewController.m index e2498048..281059c7 100644 --- a/VoidLink/ViewControllers/MainFrameViewController.m +++ b/VoidLink/ViewControllers/MainFrameViewController.m @@ -1200,6 +1200,8 @@ static NSMutableSet* hostList; // Disable mic switch if sunshine does not support mic redirection [settingsViewController.redirectMicSwitch setEnabled:!_settingsExpandedInStreamView||streamFrameViewController.micStreamInitialized]; if(_settingsExpandedInStreamView && !streamFrameViewController.micStreamInitialized) [settingsViewController.redirectMicSwitch setOn:false]; + [settingsViewController setHidden:!settingsViewController.redirectMicSwitch.isOn forStack:settingsViewController.useBuiltinMicStack]; + [settingsViewController.useBuiltinMicSwitch setEnabled:!_settingsExpandedInStreamView]; } - (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position { diff --git a/VoidLink/ViewControllers/SettingsViewController.h b/VoidLink/ViewControllers/SettingsViewController.h index a94be53c..8d3287fd 100644 --- a/VoidLink/ViewControllers/SettingsViewController.h +++ b/VoidLink/ViewControllers/SettingsViewController.h @@ -138,6 +138,9 @@ @property (strong, nonatomic) IBOutlet UIStackView *localVolumeStack; @property (strong, nonatomic) IBOutlet UISlider *localVolumeSlider; +@property (strong, nonatomic) IBOutlet UIStackView *useBuiltinMicStack; +@property (strong, nonatomic) IBOutlet UISwitch *useBuiltinMicSwitch; + @property (nonatomic, strong) MicHandler *micHandler; diff --git a/VoidLink/ViewControllers/SettingsViewController.m b/VoidLink/ViewControllers/SettingsViewController.m index 0a3cdda2..f66b8a61 100644 --- a/VoidLink/ViewControllers/SettingsViewController.m +++ b/VoidLink/ViewControllers/SettingsViewController.m @@ -677,9 +677,10 @@ BOOL isCustomResolution(int resolutionSelected) { [self addSetting:self.audioOnPcStack ofId:@"audioOnPcStack" withInfoTag:NO withDynamicLabel:NO to:audioSection]; [self addSetting:self.localVolumeStack ofId:@"localVolumeStack" withInfoTag:NO withDynamicLabel:YES to:audioSection]; [self addSetting:self.redirectMicStack ofId:@"redirectMicStack" withInfoTag:YES withDynamicLabel:NO to:audioSection]; + [self addSetting:self.useBuiltinMicStack ofId:@"useBuiltinMicStack" withInfoTag:YES withDynamicLabel:NO to:audioSection]; [self addSetting:self.audioConfigStack ofId:@"audioConfigStack" withInfoTag:NO withDynamicLabel:NO to:audioSection]; [audioSection addToParentStack:_parentStack]; - [audioSection setExpanded:YES]; + [audioSection setExpanded:YES]; otherSection = [[MenuSectionView alloc] init]; @@ -1158,6 +1159,10 @@ BOOL isCustomResolution(int resolutionSelected) { tipText = [LocalizationHelper localizedStringForKey:@"sendDummyEventStackTip"]; showOnlineDocAction = false; } + if([sender.superview.accessibilityIdentifier isEqualToString: @"useBuiltinMicStack"]){ + tipText = [LocalizationHelper localizedStringForKey:@"useBuiltinMicStackTip"]; + showOnlineDocAction = false; + } UIAlertController *tipsAlertController = [UIAlertController alertControllerWithTitle: [LocalizationHelper localizedStringForKey:@"Tips"] message:tipText preferredStyle:UIAlertControllerStyleAlert]; @@ -1562,6 +1567,8 @@ BOOL isCustomResolution(int resolutionSelected) { [self.redirectMicSwitch addTarget:self action:@selector(redirectMicSwitchFlipped:) forControlEvents:UIControlEventValueChanged]; [self redirectMicSwitchFlipped:self.redirectMicSwitch]; + [self.useBuiltinMicSwitch setOn:tempSettings.useBuiltinMic]; + _lastSelectedResolutionIndex = resolution; [self.resolutionSelector setSelectedSegmentIndex:resolution]; [self.resolutionSelector addTarget:self action:@selector(newResolutionChosen) forControlEvents:UIControlEventValueChanged]; @@ -2070,6 +2077,7 @@ BOOL isCustomResolution(int resolutionSelected) { - (void)redirectMicSwitchFlipped:(UISwitch* )sender{ if(sender.isOn) [self checkAndRequestMicPermission]; + [self setHidden:!sender.isOn forStack:_useBuiltinMicStack]; } - (void)enableOswForNativeTouchSwitchFlipped:(UISwitch *)sender{ @@ -2491,6 +2499,7 @@ BOOL isCustomResolution(int resolutionSelected) { NSInteger emulatedControllerType = [self segmentIndexToControllerType:self.emulatedControllerTypeSelector.selectedSegmentIndex]; //self.emulatedControllerTypeSelector.selectedSegmentIndex; BOOL audioOnPC = self.audioOnPcSwitch.isOn; BOOL redirectMic = self.redirectMicSwitch.isOn; + BOOL useBuiltinMic = self.useBuiltinMicSwitch.isOn; uint32_t preferredCodec = [self getChosenCodecPreference]; BOOL enableYUV444 = self.yuv444Switch.isOn; BOOL enablePIP = self.pipSwitch.isOn; @@ -2540,6 +2549,7 @@ BOOL isCustomResolution(int resolutionSelected) { swapABXYButtons:swapABXYButtons audioOnPC:audioOnPC redirectMic:redirectMic + useBuiltinMic:useBuiltinMic preferredCodec:preferredCodec enableYUV444:enableYUV444 enablePIP:enablePIP diff --git a/VoidLink/ViewControllers/StreamFrameViewController.m b/VoidLink/ViewControllers/StreamFrameViewController.m index 18a1a168..af0f65aa 100644 --- a/VoidLink/ViewControllers/StreamFrameViewController.m +++ b/VoidLink/ViewControllers/StreamFrameViewController.m @@ -1302,7 +1302,7 @@ dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ if(self->_streamConfig.redirectMic){ self->_micStreamInitialized = true; - self->micHandler = [MicHandler new]; + self->micHandler = [[MicHandler alloc] initWithUseBuiltinMic:self->_settings.useBuiltinMic]; [self->micHandler startTapping]; } }); diff --git a/VoidLink/mul.lproj/iPad.xcstrings b/VoidLink/mul.lproj/iPad.xcstrings index acb249e2..408b2ecd 100644 --- a/VoidLink/mul.lproj/iPad.xcstrings +++ b/VoidLink/mul.lproj/iPad.xcstrings @@ -13,7 +13,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "异步多点触控" } }, @@ -43,7 +43,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "关闭" } }, @@ -103,7 +103,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "队列缓冲" } }, @@ -175,7 +175,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "被窗口捕获" } }, @@ -631,19 +631,19 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "内置" } }, "zh-Hant" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "內建" } }, "zh-HK" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "內建" } } @@ -955,6 +955,36 @@ } } }, + "bfV-QT-eKw.text" : { + "comment" : "Class = \"UILabel\"; text = \"Use Built-in Mic\"; ObjectID = \"bfV-QT-eKw\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Use Built-in Mic" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "使用内置Mic" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "使用內建Mic" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "使用內建Mic" + } + } + } + }, "bhC-da-VGd.segmentTitles[0]" : { "comment" : "Class = \"UISegmentedControl\"; bhC-da-VGd.segmentTitles[0] = \"Touchpad\"; ObjectID = \"bhC-da-VGd\";", "extractionState" : "extracted_with_value", diff --git a/VoidLink/mul.lproj/iPhone.xcstrings b/VoidLink/mul.lproj/iPhone.xcstrings index 39ff641f..0ade7140 100644 --- a/VoidLink/mul.lproj/iPhone.xcstrings +++ b/VoidLink/mul.lproj/iPhone.xcstrings @@ -1621,6 +1621,36 @@ } } }, + "GiW-tl-1GX.text" : { + "comment" : "Class = \"UILabel\"; text = \"Use Built-in Mic\"; ObjectID = \"GiW-tl-1GX\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Use Built-in Mic" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "使用内置Mic" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "使用內建Mic" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "使用內建Mic" + } + } + } + }, "hfR-K8-Ti4.segmentTitles[0]" : { "comment" : "Class = \"UISegmentedControl\"; hfR-K8-Ti4.segmentTitles[0] = \"Stereo\"; ObjectID = \"hfR-K8-Ti4\";", "extractionState" : "extracted_with_value",