From e5669e2a30379d40638e18e36f87604eb53822b4 Mon Sep 17 00:00:00 2001 From: TrueZhuanjia Date: Tue, 23 Sep 2025 23:51:21 +0800 Subject: [PATCH] feat: local volume --- VoidLink/Base.lproj/iPad.storyboard | 30 ++++++++++++++++--- VoidLink/Base.lproj/iPhone.storyboard | 30 ++++++++++++++++--- VoidLink/Database/DataManager.h | 1 + VoidLink/Database/DataManager.m | 2 ++ VoidLink/Database/TemporarySettings.h | 1 + VoidLink/Database/TemporarySettings.m | 1 + .../VoidLink v1.0.xcdatamodel/contents | 1 + VoidLink/Stream/Connection.h | 1 + VoidLink/Stream/Connection.m | 21 +++++++++++++ VoidLink/Stream/StreamConfiguration.h | 1 + VoidLink/Stream/StreamConfiguration.m | 2 +- .../ViewControllers/MainFrameViewController.m | 1 + .../ViewControllers/SettingsViewController.h | 3 ++ .../ViewControllers/SettingsViewController.m | 20 ++++++++++--- VoidLink/mul.lproj/iPad.xcstrings | 30 +++++++++++++++++++ VoidLink/mul.lproj/iPhone.xcstrings | 30 +++++++++++++++++++ 16 files changed, 162 insertions(+), 13 deletions(-) diff --git a/VoidLink/Base.lproj/iPad.storyboard b/VoidLink/Base.lproj/iPad.storyboard index e5a293e7..4ce8b453 100644 --- a/VoidLink/Base.lproj/iPad.storyboard +++ b/VoidLink/Base.lproj/iPad.storyboard @@ -1135,6 +1135,26 @@ + + + + + + + + + + + + + + @@ -1182,6 +1202,8 @@ + + @@ -1958,7 +1980,7 @@ - + @@ -1967,13 +1989,13 @@ - + - + - + diff --git a/VoidLink/Base.lproj/iPhone.storyboard b/VoidLink/Base.lproj/iPhone.storyboard index dd035362..eb41ec1d 100644 --- a/VoidLink/Base.lproj/iPhone.storyboard +++ b/VoidLink/Base.lproj/iPhone.storyboard @@ -1868,6 +1868,26 @@ + + + + + + + + + + + + + + @@ -1915,6 +1935,8 @@ + + @@ -1989,19 +2011,19 @@ - + - + - + - + diff --git a/VoidLink/Database/DataManager.h b/VoidLink/Database/DataManager.h index 77029987..d5213527 100644 --- a/VoidLink/Database/DataManager.h +++ b/VoidLink/Database/DataManager.h @@ -76,6 +76,7 @@ typedef NS_ENUM(NSInteger, WidgetSizeTransition) { touchPointerVelocityFactor:(CGFloat)touchPointerVelocityFactor mousePointerVelocityFactor:(CGFloat)mousePointerVelocityFactor gyroSensitivity:(CGFloat)gyroSensitivity + localVolume:(CGFloat)localVolume touchMoveEventInterval:(NSInteger)touchMoveEventInterval reverseMouseWheelDirection:(BOOL)reverseMouseWheelDirection asyncNativeTouchPriority:(NSInteger)asyncNativeTouchPriority diff --git a/VoidLink/Database/DataManager.m b/VoidLink/Database/DataManager.m index 57106b74..15937ac1 100644 --- a/VoidLink/Database/DataManager.m +++ b/VoidLink/Database/DataManager.m @@ -71,6 +71,7 @@ touchPointerVelocityFactor:(CGFloat)touchPointerVelocityFactor mousePointerVelocityFactor:(CGFloat)mousePointerVelocityFactor gyroSensitivity:(CGFloat)gyroSensitivity + localVolume:(CGFloat)localVolume touchMoveEventInterval:(NSInteger)touchMoveEventInterval reverseMouseWheelDirection:(BOOL)reverseMouseWheelDirection asyncNativeTouchPriority:(NSInteger)asyncNativeTouchPriority @@ -121,6 +122,7 @@ settingsToSave.touchPointerVelocityFactor = [NSNumber numberWithFloat:touchPointerVelocityFactor]; settingsToSave.mousePointerVelocityFactor = [NSNumber numberWithFloat:mousePointerVelocityFactor]; settingsToSave.gyroSensitivity = [NSNumber numberWithFloat:gyroSensitivity]; + settingsToSave.localVolume = [NSNumber numberWithFloat:localVolume]; settingsToSave.touchMoveEventInterval = [NSNumber numberWithInteger:touchMoveEventInterval]; settingsToSave.reverseMouseWheelDirection = reverseMouseWheelDirection; settingsToSave.asyncNativeTouchPriority = [NSNumber numberWithInteger:asyncNativeTouchPriority]; diff --git a/VoidLink/Database/TemporarySettings.h b/VoidLink/Database/TemporarySettings.h index 4a5f8d5d..9acfaf83 100644 --- a/VoidLink/Database/TemporarySettings.h +++ b/VoidLink/Database/TemporarySettings.h @@ -33,6 +33,7 @@ @property (nonatomic, retain) NSNumber * touchMoveEventInterval; @property (nonatomic, retain) NSNumber * touchPointerVelocityFactor; @property (nonatomic, retain) NSNumber * gyroSensitivity; +@property (nonatomic, retain) NSNumber * localVolume; @property (nonatomic, retain) NSNumber * emulatedControllerType; @property (nonatomic, retain) NSNumber * mousePointerVelocityFactor; @property (nonatomic, retain) NSNumber * pointerVelocityModeDivider; diff --git a/VoidLink/Database/TemporarySettings.m b/VoidLink/Database/TemporarySettings.m index f40e5277..b5723a5f 100644 --- a/VoidLink/Database/TemporarySettings.m +++ b/VoidLink/Database/TemporarySettings.m @@ -116,6 +116,7 @@ self.touchPointerVelocityFactor = settings.touchPointerVelocityFactor; self.mousePointerVelocityFactor = settings.mousePointerVelocityFactor; self.gyroSensitivity = settings.gyroSensitivity; + self.localVolume = settings.localVolume; self.pointerVelocityModeDivider = settings.pointerVelocityModeDivider; self.unlockDisplayOrientation = settings.unlockDisplayOrientation; self.resolutionSelected = settings.resolutionSelected; diff --git a/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents b/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents index 508ded7a..6befb009 100644 --- a/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents +++ b/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents @@ -44,6 +44,7 @@ + diff --git a/VoidLink/Stream/Connection.h b/VoidLink/Stream/Connection.h index b7327b58..f4e30315 100644 --- a/VoidLink/Stream/Connection.h +++ b/VoidLink/Stream/Connection.h @@ -22,5 +22,6 @@ -(BandwidthTracker *) getBwTracker; -(BOOL) getVideoStats:(video_stats_t*)stats; -(NSString*) getActiveCodecName; ++ (void)setVolume:(float)newVolume; @end diff --git a/VoidLink/Stream/Connection.m b/VoidLink/Stream/Connection.m index 767032cf..3c067525 100644 --- a/VoidLink/Stream/Connection.m +++ b/VoidLink/Stream/Connection.m @@ -44,6 +44,7 @@ static NSLock* videoStatsLock; static SDL_AudioDeviceID audioDevice; static OPUS_MULTISTREAM_CONFIGURATION audioConfig; static void* audioBuffer; +static float volume = 1.0; static int audioFrameSize; static VideoDecoderRenderer* renderer; @@ -302,6 +303,13 @@ void ArCleanup(void) SDL_QuitSubSystem(SDL_INIT_AUDIO); } ++ (void)setVolume:(float)linearVolume{ + if (linearVolume <= 0.0f) linearVolume = 0.0f; + if (linearVolume >= 1.0f) linearVolume = 1.0f; + CGFloat exponent = 2.5; + volume = powf(linearVolume, exponent); +} + void ArDecodeAndPlaySample(char* sampleData, int sampleLength) { int decodeLen; @@ -318,9 +326,20 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength) (float*)audioBuffer, audioConfig.samplesPerFrame, 0); + if (decodeLen > 0) { // Provide backpressure on the queue to ensure too many frames don't build up // in SDL's audio queue. + + float* fbuf = (float*)audioBuffer; + + if(volume != 1.0){ + int totalSamples = decodeLen * audioConfig.channelCount; + for (int i = 0; i < totalSamples; i++) { + fbuf[i] *= volume; + } + } + while (SDL_GetQueuedAudioSize(audioDevice) / audioFrameSize > 10) { [NSThread sleepForTimeInterval:0.001f]; } @@ -470,6 +489,8 @@ void ClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t _streamConfig.supportedVideoFormats = config.supportedVideoFormats; _streamConfig.audioConfiguration = config.audioConfiguration; _streamConfig.redirectMic = config.redirectMic && [MicHandler permissionGranted]; + NSLog(@"config.localVolume %f", config.localVolume); + [Connection setVolume:config.localVolume]; // Since we require iOS 12 or above, we're guaranteed to be running // on a 64-bit device with ARMv8 crypto instructions, so we don't diff --git a/VoidLink/Stream/StreamConfiguration.h b/VoidLink/Stream/StreamConfiguration.h index 5ff686a0..f2019778 100644 --- a/VoidLink/Stream/StreamConfiguration.h +++ b/VoidLink/Stream/StreamConfiguration.h @@ -42,5 +42,6 @@ @property BOOL multiController; @property NSData* serverCert; @property int localMousePointerMode; +@property CGFloat localVolume; @end diff --git a/VoidLink/Stream/StreamConfiguration.m b/VoidLink/Stream/StreamConfiguration.m index aab4f9d7..f3be6778 100644 --- a/VoidLink/Stream/StreamConfiguration.m +++ b/VoidLink/Stream/StreamConfiguration.m @@ -9,5 +9,5 @@ #import "StreamConfiguration.h" @implementation StreamConfiguration -@synthesize host, httpsPort, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, appName, optimizeGameSettings, playAudioOnPC, swapABXYButtons, buttonVisualFeedback, gyroMode, emulatedControllerType, audioConfiguration, supportedVideoFormats, multiController, serverCert, rtspSessionUrl, serverCodecModeSupport, enableYUV444, enablePIP; +@synthesize host, httpsPort, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, appName, optimizeGameSettings, playAudioOnPC, swapABXYButtons, buttonVisualFeedback, gyroMode, emulatedControllerType, audioConfiguration, supportedVideoFormats, multiController, serverCert, rtspSessionUrl, serverCodecModeSupport, enableYUV444, enablePIP, localVolume; @end diff --git a/VoidLink/ViewControllers/MainFrameViewController.m b/VoidLink/ViewControllers/MainFrameViewController.m index 03480b70..e2498048 100644 --- a/VoidLink/ViewControllers/MainFrameViewController.m +++ b/VoidLink/ViewControllers/MainFrameViewController.m @@ -821,6 +821,7 @@ static NSMutableSet* hostList; _streamConfig.optimizeGameSettings = streamSettings.optimizeGames; _streamConfig.playAudioOnPC = streamSettings.playAudioOnPC; _streamConfig.redirectMic = streamSettings.redirectMic; + _streamConfig.localVolume = streamSettings.localVolume.floatValue; _streamConfig.swapABXYButtons = streamSettings.swapABXYButtons; _streamConfig.buttonVisualFeedback = streamSettings.buttonVisualFeedback; _streamConfig.asyncNativeTouchPriority = streamSettings.asyncNativeTouchPriority; // new streamConfig segment diff --git a/VoidLink/ViewControllers/SettingsViewController.h b/VoidLink/ViewControllers/SettingsViewController.h index 675fcb3f..a94be53c 100644 --- a/VoidLink/ViewControllers/SettingsViewController.h +++ b/VoidLink/ViewControllers/SettingsViewController.h @@ -135,6 +135,9 @@ @property (strong, nonatomic) IBOutlet UIStackView *sendDummyEventStack; @property (strong, nonatomic) IBOutlet UISwitch *sendDummyEventSwitch; +@property (strong, nonatomic) IBOutlet UIStackView *localVolumeStack; +@property (strong, nonatomic) IBOutlet UISlider *localVolumeSlider; + @property (nonatomic, strong) MicHandler *micHandler; diff --git a/VoidLink/ViewControllers/SettingsViewController.m b/VoidLink/ViewControllers/SettingsViewController.m index 93b4563f..0a3cdda2 100644 --- a/VoidLink/ViewControllers/SettingsViewController.m +++ b/VoidLink/ViewControllers/SettingsViewController.m @@ -12,6 +12,7 @@ #import "TemporarySettings.h" #import "DataManager.h" #import "ThemeManager.h" +#import "Connection.h" #import "Plot.h" #import @@ -674,6 +675,7 @@ 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.audioConfigStack ofId:@"audioConfigStack" withInfoTag:NO withDynamicLabel:NO to:audioSection]; [audioSection addToParentStack:_parentStack]; @@ -1549,10 +1551,13 @@ BOOL isCustomResolution(int resolutionSelected) { [self.emulatedControllerTypeSelector setSelectedSegmentIndex:[self controllerTypeToSegmentIndex:tempSettings.emulatedControllerType.intValue]]; [self.emulatedControllerTypeSelector addTarget:self action:@selector(emulatedControllerTypeChanged:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. [self emulatedControllerTypeChanged:self.emulatedControllerTypeSelector]; - - - + [self.audioOnPcSwitch setOn:tempSettings.playAudioOnPC]; + + [self.localVolumeSlider setValue:tempSettings.localVolume.floatValue*100]; + [self.localVolumeSlider addTarget:self action:@selector(localVolumeSliderMoved:) forControlEvents:UIControlEventValueChanged]; + [self localVolumeSliderMoved:self.localVolumeSlider]; + [self.redirectMicSwitch setOn:tempSettings.redirectMic]; [self.redirectMicSwitch addTarget:self action:@selector(redirectMicSwitchFlipped:) forControlEvents:UIControlEventValueChanged]; [self redirectMicSwitchFlipped:self.redirectMicSwitch]; @@ -1903,7 +1908,6 @@ BOOL isCustomResolution(int resolutionSelected) { [self presentViewController:self.layoutOnScreenControlsVC animated:YES completion:nil]; } - - (void) pointerVelocityModeDividerSliderMoved:(UISlider* )sender { [self findDynamicLabelFromStack:self.pointerVelocityDividerStack].text = [NSString stringWithFormat:@" | %d%% | %d%% | ", (uint8_t)sender.value, 100-(uint8_t)sender.value]; } @@ -1916,6 +1920,11 @@ BOOL isCustomResolution(int resolutionSelected) { [self findDynamicLabelFromStack:self.gyroSensitivityStack].text = [NSString stringWithFormat:@" %d%% ", (uint16_t)sender.value]; // Update label display } +- (void) localVolumeSliderMoved:(UISlider* )sender { + [self findDynamicLabelFromStack:self.localVolumeStack].text = [NSString stringWithFormat:@" %d%% ", (uint16_t)sender.value]; // Update label display + if(_mainFrameViewController.settingsExpandedInStreamView) [Connection setVolume:sender.value/100]; +} + - (void) backgroundSessionTimerSliderMoved:(UISlider* )sender { NSString* labelString; labelString = [LocalizationHelper localizedStringForKey:@" keep %d min ", (uint16_t)sender.value]; @@ -2464,6 +2473,8 @@ BOOL isCustomResolution(int resolutionSelected) { CGFloat touchPointerVelocityFactor = (CGFloat)(uint16_t)[self map_velocFactorDisplay_fromSliderValue:self.touchPointerVelocityFactorSlider.value]/100; CGFloat mousePointerVelocityFactor = (CGFloat)(uint16_t)[self map_velocFactorDisplay_fromSliderValue:self.mousePointerVelocityFactorSlider.value]/100; CGFloat gyroSensitivity = (CGFloat)(uint16_t)self.gyroSensitivitySlider.value/100; + + CGFloat localVolume = self.localVolumeSlider.value/100; uint16_t touchMoveEventInterval = (uint16_t)self.touchMoveEventIntervalSlider.value; @@ -2517,6 +2528,7 @@ BOOL isCustomResolution(int resolutionSelected) { touchPointerVelocityFactor:touchPointerVelocityFactor mousePointerVelocityFactor:mousePointerVelocityFactor gyroSensitivity:gyroSensitivity + localVolume:localVolume touchMoveEventInterval:touchMoveEventInterval reverseMouseWheelDirection:reverseMouseWheelDirection asyncNativeTouchPriority:asyncNativeTouchPriority diff --git a/VoidLink/mul.lproj/iPad.xcstrings b/VoidLink/mul.lproj/iPad.xcstrings index 1569f104..acb249e2 100644 --- a/VoidLink/mul.lproj/iPad.xcstrings +++ b/VoidLink/mul.lproj/iPad.xcstrings @@ -679,6 +679,36 @@ } } }, + "AeU-kl-XFa.text" : { + "comment" : "Class = \"UILabel\"; text = \"Local Volume\"; ObjectID = \"AeU-kl-XFa\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Local Volume" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "本地音量" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "本地音量" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "本地音量" + } + } + } + }, "aFy-0w-YPe.segmentTitles[0]" : { "comment" : "Class = \"UISegmentedControl\"; aFy-0w-YPe.segmentTitles[0] = \"H.264\"; ObjectID = \"aFy-0w-YPe\";", "extractionState" : "extracted_with_value", diff --git a/VoidLink/mul.lproj/iPhone.xcstrings b/VoidLink/mul.lproj/iPhone.xcstrings index 64dc4126..39ff641f 100644 --- a/VoidLink/mul.lproj/iPhone.xcstrings +++ b/VoidLink/mul.lproj/iPhone.xcstrings @@ -1561,6 +1561,36 @@ } } }, + "GbY-52-itv.text" : { + "comment" : "Class = \"UILabel\"; text = \"Local Volume\"; ObjectID = \"GbY-52-itv\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Local Volume" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "本地音量" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "本地音量" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "本地音量" + } + } + } + }, "ghM-zc-sr6.title" : { "comment" : "Class = \"UIBarButtonItem\"; title = \"Delete\"; ObjectID = \"ghM-zc-sr6\";", "extractionState" : "extracted_with_value",