feat: use built-in mic

This commit is contained in:
TrueZhuanjia
2025-09-24 12:49:25 +08:00
parent e5669e2a30
commit 858e7c7440
15 changed files with 182 additions and 15 deletions
+22
View File
@@ -1155,6 +1155,26 @@
<constraint firstAttribute="width" constant="380" id="Oij-e2-w81"/>
</constraints>
</stackView>
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="jCF-si-KLC" userLabel="useBuiltinMicStack">
<rect key="frame" x="432" y="2310" width="270" height="31"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Use Built-in Mic" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.64999997615814209" adjustsLetterSpacingToFitWidth="YES" adjustsFontForContentSizeCategory="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bfV-QT-eKw" userLabel="uiLabel">
<rect key="frame" x="0.0" y="0.0" width="120" height="31"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="H3f-qy-ySA" userLabel="useBuiltinMicSwitch">
<rect key="frame" x="140" y="0.0" width="132" height="31"/>
<constraints>
<constraint firstAttribute="width" constant="130" id="e7s-Xg-mNQ"/>
</constraints>
</switch>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="31" id="GWg-Dx-N44"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
@@ -1258,6 +1278,8 @@
<outlet property="touchPointerVelocityFactorUILabel" destination="egA-7n-Dpe" id="QGf-uN-5Io"/>
<outlet property="unlockDisplayOrientationSelector" destination="KNe-bN-CDb" id="C8u-Ro-HDy"/>
<outlet property="unlockDisplayOrientationStack" destination="5dA-cw-gOa" id="HHx-qM-BZi"/>
<outlet property="useBuiltinMicStack" destination="jCF-si-KLC" id="AnY-Ob-jE9"/>
<outlet property="useBuiltinMicSwitch" destination="H3f-qy-ySA" id="O76-df-ich"/>
<outlet property="yuv444Stack" destination="Qfd-bG-FSa" id="kpm-TK-Ngg"/>
<outlet property="yuv444Switch" destination="jIQ-jh-tvP" id="Qru-gO-haR"/>
</connections>
+27 -5
View File
@@ -1869,7 +1869,7 @@
</constraints>
</stackView>
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="zmq-ah-Vfh" userLabel="localVolumeStack">
<rect key="frame" x="437" y="1235" width="380" height="55.5"/>
<rect key="frame" x="437" y="1238" width="380" height="55.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Local Volume" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GbY-52-itv" userLabel="uiLabel">
<rect key="frame" x="0.0" y="0.0" width="380" height="20.5"/>
@@ -1888,6 +1888,26 @@
<constraint firstAttribute="width" constant="380" id="wiK-dT-C4c"/>
</constraints>
</stackView>
<stackView verifyAmbiguity="off" opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="lbL-2m-AO2" userLabel="useBuiltinMicStack">
<rect key="frame" x="437" y="1189" width="270" height="31"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Use Built-in Mic" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.64999997615814209" adjustsLetterSpacingToFitWidth="YES" adjustsFontForContentSizeCategory="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GiW-tl-1GX" userLabel="uiLabel">
<rect key="frame" x="0.0" y="0.0" width="120" height="31"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="YR4-0Z-D5Z" userLabel="useBuiltinMicSwitch">
<rect key="frame" x="140" y="0.0" width="132" height="31"/>
<constraints>
<constraint firstAttribute="width" constant="130" id="CO9-K5-BX6"/>
</constraints>
</switch>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="31" id="kKP-q4-TzC"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
@@ -1990,6 +2010,8 @@
<outlet property="touchPointerVelocityFactorUILabel" destination="ECJ-bg-fRJ" id="9dF-Th-ARj"/>
<outlet property="unlockDisplayOrientationSelector" destination="0gh-fD-6V5" id="Zwv-rN-soS"/>
<outlet property="unlockDisplayOrientationStack" destination="FKE-J4-bZB" id="Loj-SR-3XK"/>
<outlet property="useBuiltinMicStack" destination="lbL-2m-AO2" id="ZDm-aL-1cC"/>
<outlet property="useBuiltinMicSwitch" destination="YR4-0Z-D5Z" id="rMI-TK-FGJ"/>
<outlet property="yuv444Stack" destination="hnG-J3-IuI" id="whR-kg-UmO"/>
<outlet property="yuv444Switch" destination="OZK-ba-DD9" id="SZA-F4-eo3"/>
</connections>
@@ -2011,19 +2033,19 @@
<image name="trash.fill" catalog="system" width="117" height="128"/>
<image name="tray.full.fill" catalog="system" width="128" height="88"/>
<systemColor name="linkColor">
<color red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="secondarySystemGroupedBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemBrownColor">
<color red="0.63529411759999999" green="0.51764705879999995" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.63529411764705879" green="0.51764705882352946" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemGray2Color">
<color red="0.68235294120000001" green="0.68235294120000001" blue="0.69803921570000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.68235294117647061" green="0.68235294117647061" blue="0.69803921568627447" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemTealColor">
<color red="0.18823529410000001" green="0.69019607839999997" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.18823529411764706" green="0.69019607843137254" blue="0.7803921568627451" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
+1
View File
@@ -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
+2
View File
@@ -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;
+1
View File
@@ -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;
+1
View File
@@ -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;
+14 -1
View File
@@ -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() {
@@ -71,6 +71,7 @@
<attribute name="touchPointerVelocityFactor" optional="YES" attributeType="Float" defaultValueString="1" usesScalarValueType="NO" syncable="YES"/>
<attribute name="uniqueId" attributeType="String" syncable="YES"/>
<attribute name="unlockDisplayOrientation" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
<attribute name="useBuiltinMic" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" usesScalarValueType="NO" syncable="YES"/>
</entity>
</model>
@@ -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 %@" : {
},
@@ -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 {
@@ -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;
@@ -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
@@ -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];
}
});
+37 -7
View File
@@ -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",
+30
View File
@@ -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",