diff --git a/VoidLink/Base.lproj/iPad.storyboard b/VoidLink/Base.lproj/iPad.storyboard index 1a20d237..0e56bdfe 100644 --- a/VoidLink/Base.lproj/iPad.storyboard +++ b/VoidLink/Base.lproj/iPad.storyboard @@ -500,10 +500,11 @@ - + + @@ -2895,7 +2896,7 @@ - + @@ -2904,13 +2905,13 @@ - + - + - + diff --git a/VoidLink/Base.lproj/iPhone.storyboard b/VoidLink/Base.lproj/iPhone.storyboard index d3538fe4..28e66e55 100644 --- a/VoidLink/Base.lproj/iPhone.storyboard +++ b/VoidLink/Base.lproj/iPhone.storyboard @@ -1700,10 +1700,11 @@ - + + @@ -2937,19 +2938,19 @@ - + - + - + - + diff --git a/VoidLink/Database/DataManager.h b/VoidLink/Database/DataManager.h index e26e5cf1..ae1962f0 100644 --- a/VoidLink/Database/DataManager.h +++ b/VoidLink/Database/DataManager.h @@ -27,11 +27,6 @@ typedef NS_ENUM(NSInteger, ControllerGyroSwitchMode) { ControllerGyroSwitchHoldDown }; -typedef NS_ENUM(NSInteger, AudioEngine) { - SystemAudioEngine, - SDLAudioEngine -}; - typedef NS_ENUM(NSInteger, TouchMode) { RelativeTouch, NativeTouch, diff --git a/VoidLink/Localization/Localizable.xcstrings b/VoidLink/Localization/Localizable.xcstrings index 7a7ba048..65977dbf 100644 --- a/VoidLink/Localization/Localizable.xcstrings +++ b/VoidLink/Localization/Localizable.xcstrings @@ -858,6 +858,35 @@ } } }, + "audioConfigStackTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "- Stereo: Stereo mode driven by the system audio engine. Offers better audio quality and continues playback when the screen is off.\n\n- Stereo (SDL): Stereo mode driven by the SDL engine. This mode is essentially equivalent to Moonlight-iOS audio. Playback cannot be maintained after the screen is turned off.\n\n- 5.1 / 7.1 Channels: both are driven by the SDL engine. Playback cannot be maintained after the screen is turned off. Available for iOS 18+." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "- 双声道:由系统音频引擎驱动的双声道模式。音质更好、熄屏可维持播放。\n\n- 双声道(SDL):由SDL引擎驱动的双声道模式。此模式基本上等价于moonlight-iOS音频。熄屏后无法维持播放。\n\n- 5.1 / 7.1 声道:均为SDL引擎驱动。熄屏后无法维持播放。需 iOS 18 以上支持。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "- 雙聲道:由系統音訊引擎驅動的雙聲道模式。音質較佳,且在熄屏後仍可維持播放。\n\n- 雙聲道(SDL):由 SDL 引擎驅動的雙聲道模式。此模式基本等同於 Moonlight-iOS 的音訊。熄屏後無法維持播放。\n\n5.1/7.1 聲道:皆由 SDL 引擎驅動。熄屏後無法維持播放,需 iOS 18 以上支援。" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "- 雙聲道:由系統音訊引擎驅動的雙聲道模式。音質較佳,且在熄屏後仍可維持播放。\n\n- 雙聲道(SDL):由 SDL 引擎驅動的雙聲道模式。此模式基本等同於 Moonlight-iOS 的音訊。熄屏後無法維持播放。\n\n5.1/7.1 聲道:皆由 SDL 引擎驅動。熄屏後無法維持播放,需 iOS 18 以上支援。" + } + } + } + }, "Auto tap disabled" : { "extractionState" : "manual", "localizations" : { diff --git a/VoidLink/Stream/Connection.m b/VoidLink/Stream/Connection.m index 6d8c82d3..2acf3dc4 100644 --- a/VoidLink/Stream/Connection.m +++ b/VoidLink/Stream/Connection.m @@ -296,7 +296,7 @@ int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, v DataManager* dataMan = [[DataManager alloc] init]; TemporarySettings* tempSettings = [dataMan getSettings]; bool useBluetoothD2P = tempSettings.useBuiltinMic || !tempSettings.redirectMic; - AVAudioSessionCategoryOptions bluetoothAudioOption = useBluetoothD2P ? AVAudioSessionCategoryOptionAllowBluetoothA2DP : AVAudioSessionCategoryOptionAllowBluetoothHFP; + AVAudioSessionCategoryOptions bluetoothAudioOption = useBluetoothD2P ? AVAudioSessionCategoryOptionAllowBluetoothA2DP : AVAudioSessionCategoryOptionAllowBluetooth; AVAudioSessionCategoryOptions volumeMixOption = tempSettings.duckOtherApps ? AVAudioSessionCategoryOptionDuckOthers : AVAudioSessionCategoryOptionMixWithOthers; AVAudioSession *session = [AVAudioSession sharedInstance]; [session setCategory:tempSettings.redirectMic ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategoryPlayback @@ -425,7 +425,7 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength) float* fbuf = (float*)audioBuffer; - if(audioConfig.channelCount <= 2) { + if(useSystemAudioEngine){ // 创建 AVAudioPCMBuffer AVAudioFrameCount frameCount = decodeLen; AVAudioPCMBuffer *buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:audioFormat frameCapacity:frameCount]; @@ -460,6 +460,7 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength) Log(LOG_E, @"Failed to queue audio sample: %s\n", SDL_GetError()); } } + } } diff --git a/VoidLink/ViewControllers/MainFrameViewController.m b/VoidLink/ViewControllers/MainFrameViewController.m index 963c7dc7..ec78583c 100644 --- a/VoidLink/ViewControllers/MainFrameViewController.m +++ b/VoidLink/ViewControllers/MainFrameViewController.m @@ -850,6 +850,7 @@ static NSMutableSet* hostList; } int numberOfChannels = MIN([streamSettings.audioConfig intValue], physicalOutputChannels); + Log(LOG_I, @"Selected number of audio channels %d", numberOfChannels); if (numberOfChannels >= 8) { _streamConfig.audioConfiguration = AUDIO_CONFIGURATION_71_SURROUND; @@ -861,6 +862,7 @@ static NSMutableSet* hostList; _streamConfig.audioConfiguration = AUDIO_CONFIGURATION_STEREO; } + Connection.useSystemAudioEngine = streamSettings.audioConfig.intValue == 2; switch (streamSettings.preferredCodec) { case CODEC_PREF_AV1: @@ -1191,7 +1193,24 @@ static NSMutableSet* hostList; [settingsViewController.emulatedControllerTypeSelector setEnabled:!_settingsExpandedInStreamView]; [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.citrixX1MouseStack]; [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.externalDisplayModeStack]; - [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.audioConfigStack]; + + if(settingsViewController.audioConfigSelector.numberOfSegments>2){ + if(_settingsExpandedInStreamView){ + if(settingsViewController.audioConfigSelector.selectedSegmentIndex>=2){ + [settingsViewController.audioConfigSelector setEnabled:false]; + } + else { + [settingsViewController.audioConfigSelector setEnabled:false forSegmentAtIndex:2]; + [settingsViewController.audioConfigSelector setEnabled:false forSegmentAtIndex:3]; + } + } + else{ + [settingsViewController.audioConfigSelector setEnabled:true]; + [settingsViewController.audioConfigSelector setEnabled:true forSegmentAtIndex:2]; + [settingsViewController.audioConfigSelector setEnabled:true forSegmentAtIndex:3]; + } + } + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.duckOtherAppStack]; [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.pipStack]; [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.appThemeStack]; diff --git a/VoidLink/ViewControllers/SettingsViewController.m b/VoidLink/ViewControllers/SettingsViewController.m index 8cb7461a..e0bdd9a3 100644 --- a/VoidLink/ViewControllers/SettingsViewController.m +++ b/VoidLink/ViewControllers/SettingsViewController.m @@ -876,7 +876,7 @@ BOOL isCustomResolution(int resolutionSelected) { [self addSetting:self.muteInBackgroundStack ofId:@"muteInBackgroundStack" withInfoTag:NO withDynamicLabel:NO to:audioSection]; // [self addSetting:self.audioEngineStack ofId:@"audioEngineStack" withInfoTag:YES withDynamicLabel:NO to:audioSection]; // cancel audio engine selector due to system engine is unable to playback multi-channel audio - [self addSetting:self.audioConfigStack ofId:@"audioConfigStack" withInfoTag:NO withDynamicLabel:NO to:audioSection]; + [self addSetting:self.audioConfigStack ofId:@"audioConfigStack" withInfoTag:YES withDynamicLabel:NO to:audioSection]; [audioSection addToParentStack:_parentStack]; // [audioSection setExpanded:NO]; @@ -1423,6 +1423,10 @@ BOOL isCustomResolution(int resolutionSelected) { tipText = [LocalizationHelper localizedStringForKey:@"physicaStickMinOffsetTip"]; showOnlineDocAction = false; } + if([sender.superview.accessibilityIdentifier isEqualToString: @"audioConfigStack"]){ + tipText = [LocalizationHelper localizedStringForKey:@"audioConfigStackTip"]; + showOnlineDocAction = false; + } UIAlertController *tipsAlertController = [UIAlertController alertControllerWithTitle: [LocalizationHelper localizedStringForKey:@"Tips"] message:tipText preferredStyle:UIAlertControllerStyleAlert]; @@ -1908,22 +1912,30 @@ BOOL isCustomResolution(int resolutionSelected) { self.audioEngineSelector.selectedSegmentIndex = self->tempSettings.audioEngine.intValue; if (@available(iOS 18.0, tvOS 18.0, *)) {}else{ - [self.audioConfigSelector removeSegmentAtIndex:1 animated:false]; - [self.audioConfigSelector removeSegmentAtIndex:1 animated:false]; // segment 2 goes away when you remove index 2 + [self.audioConfigSelector removeSegmentAtIndex:2 animated:false]; + [self.audioConfigSelector removeSegmentAtIndex:2 animated:false]; // segment 2 goes away when you remove index 2 + /* [self.audioConfigSelector setTitle:[LocalizationHelper localizedStringForKey:@"Stereo (surround sound available for iOS18+)"] forSegmentAtIndex:0]; - [self.audioConfigSelector setEnabled:NO]; + [self.audioConfigSelector setEnabled:NO];*/ } switch ([self->tempSettings.audioConfig integerValue]) { case 2: [self.audioConfigSelector setSelectedSegmentIndex:0]; break; - case 6: + case 3: [self.audioConfigSelector setSelectedSegmentIndex:1]; break; - case 8: + case 6: [self.audioConfigSelector setSelectedSegmentIndex:2]; break; + case 8: + [self.audioConfigSelector setSelectedSegmentIndex:3]; + break; } + // 2 - stereo (system) + // 3 - stereo (SDL) + // 6 - 5.1 (SDL) + // 8 - 7.1 (SDL) // Unlock Display Orientation setting bool unlockDisplayOrientationSelectorEnabled = [self isFullScreenRequired] || [self isIPhone];//need "requires fullscreen" enabled in the app bunddle to make runtime orientation limitation working @@ -3280,7 +3292,12 @@ BOOL isCustomResolution(int resolutionSelected) { NSInteger framerate = [self getChosenFrameRate]; - NSInteger audioConfig = [@[@2, @6, @8][[self.audioConfigSelector selectedSegmentIndex]] integerValue]; + NSInteger audioConfig = [@[@2, @3, @6, @8][[self.audioConfigSelector selectedSegmentIndex]] integerValue]; + // 2 - stereo (system) + // 3 - stereo (SDL) + // 6 - 5.1 (SDL) + // 8 - 7.1 (SDL) + NSInteger renderingBackend = [self.renderingBackendSelector selectedSegmentIndex]; NSInteger framePacingMode = [self.framePacingModeSelector selectedSegmentIndex]; NSInteger onscreenControls = [self.onScreenWidgetSelector selectedSegmentIndex]; diff --git a/VoidLink/ViewControllers/StreamFrameViewController.m b/VoidLink/ViewControllers/StreamFrameViewController.m index 2a9f6eb4..7eefe1f3 100644 --- a/VoidLink/ViewControllers/StreamFrameViewController.m +++ b/VoidLink/ViewControllers/StreamFrameViewController.m @@ -376,7 +376,6 @@ } else [micHandler stopTappingWithStopEngine:false]; - Connection.useSystemAudioEngine = _settings.audioEngine.intValue == SystemAudioEngine; Connection.muteInBackground = _settings.muteInBackground; if(!viewJustLoaded) [_controllerSupport updateControllerSupport:self.streamConfig delegate:self]; diff --git a/VoidLink/mul.lproj/iPad.xcstrings b/VoidLink/mul.lproj/iPad.xcstrings index 8f4899e7..6ee86dad 100644 --- a/VoidLink/mul.lproj/iPad.xcstrings +++ b/VoidLink/mul.lproj/iPad.xcstrings @@ -3074,7 +3074,37 @@ } }, "iZL-dA-jk9.segmentTitles[1]" : { - "comment" : "Class = \"UISegmentedControl\"; iZL-dA-jk9.segmentTitles[1] = \"5.1‑channel\"; ObjectID = \"iZL-dA-jk9\";", + "comment" : "Class = \"UISegmentedControl\"; iZL-dA-jk9.segmentTitles[1] = \"Stereo(SDL)\"; ObjectID = \"iZL-dA-jk9\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Stereo(SDL)" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "双声道(SDL)" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "雙聲道(SDL)" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "雙聲道(SDL)" + } + } + } + }, + "iZL-dA-jk9.segmentTitles[2]" : { + "comment" : "Class = \"UISegmentedControl\"; iZL-dA-jk9.segmentTitles[2] = \"5.1‑channel\"; ObjectID = \"iZL-dA-jk9\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { @@ -3103,8 +3133,8 @@ } } }, - "iZL-dA-jk9.segmentTitles[2]" : { - "comment" : "Class = \"UISegmentedControl\"; iZL-dA-jk9.segmentTitles[2] = \"7.1‑channel\"; ObjectID = \"iZL-dA-jk9\";", + "iZL-dA-jk9.segmentTitles[3]" : { + "comment" : "Class = \"UISegmentedControl\"; iZL-dA-jk9.segmentTitles[3] = \"7.1‑channel\"; ObjectID = \"iZL-dA-jk9\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { diff --git a/VoidLink/mul.lproj/iPhone.xcstrings b/VoidLink/mul.lproj/iPhone.xcstrings index 9fa0a3d3..7b564f15 100644 --- a/VoidLink/mul.lproj/iPhone.xcstrings +++ b/VoidLink/mul.lproj/iPhone.xcstrings @@ -2408,7 +2408,37 @@ } }, "hfR-K8-Ti4.segmentTitles[1]" : { - "comment" : "Class = \"UISegmentedControl\"; hfR-K8-Ti4.segmentTitles[1] = \"5.1-channel\"; ObjectID = \"hfR-K8-Ti4\";", + "comment" : "Class = \"UISegmentedControl\"; hfR-K8-Ti4.segmentTitles[1] = \"Stereo(SDL)\"; ObjectID = \"hfR-K8-Ti4\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Stereo(SDL)" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "双声道(SDL)" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "雙聲道(SDL)" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "雙聲道(SDL)" + } + } + } + }, + "hfR-K8-Ti4.segmentTitles[2]" : { + "comment" : "Class = \"UISegmentedControl\"; hfR-K8-Ti4.segmentTitles[2] = \"5.1-channel\"; ObjectID = \"hfR-K8-Ti4\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { @@ -2425,20 +2455,20 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "5.1聲道" } }, "zh-HK" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "5.1聲道" } } } }, - "hfR-K8-Ti4.segmentTitles[2]" : { - "comment" : "Class = \"UISegmentedControl\"; hfR-K8-Ti4.segmentTitles[2] = \"7.1-channel\"; ObjectID = \"hfR-K8-Ti4\";", + "hfR-K8-Ti4.segmentTitles[3]" : { + "comment" : "Class = \"UISegmentedControl\"; hfR-K8-Ti4.segmentTitles[3] = \"7.1-channel\"; ObjectID = \"hfR-K8-Ti4\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { @@ -2455,13 +2485,13 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "7.1聲道" } }, "zh-HK" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "7.1聲道" } }