Fixed bug not displaying system volume when muted
This commit is contained in:
parent
5940962b26
commit
a64ad6af92
|
|
@ -241,7 +241,7 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
|
|||
static NSString * const kHelperBundleIDSuffix = @"Helper";
|
||||
|
||||
- (NSString *)helperBundleID {
|
||||
return [[[NSBundle mainBundle] bundleIdentifier] stringByAppendingString:kHelperBundleIDSuffix];
|
||||
return [[[NSBundle mainBundle] bundleIdentifier] stringByAppendingString:kHelperBundleIDSuffix];
|
||||
}
|
||||
|
||||
- (IBAction)terminate:(id)sender
|
||||
|
|
@ -285,58 +285,58 @@ static NSString * const kHelperBundleIDSuffix = @"Helper";
|
|||
|
||||
- (void)updateStartAtLoginMenuItem
|
||||
{
|
||||
BOOL enabled = [self StartAtLogin];
|
||||
NSMenuItem* menuItem = [self.statusMenu itemWithTag:START_AT_LOGIN_ID];
|
||||
[menuItem setState:enabled ? NSControlStateValueOn : NSControlStateValueOff];
|
||||
BOOL enabled = [self StartAtLogin];
|
||||
NSMenuItem* menuItem = [self.statusMenu itemWithTag:START_AT_LOGIN_ID];
|
||||
[menuItem setState:enabled ? NSControlStateValueOn : NSControlStateValueOff];
|
||||
}
|
||||
|
||||
|
||||
- (void)setStartAtLogin:(BOOL)enabled savePreferences:(BOOL)savePreferences
|
||||
{
|
||||
NSString *helperBundleID = @"io.alberti42.VolumeControlHelper";
|
||||
NSString *helperBundleID = @"io.alberti42.VolumeControlHelper";
|
||||
|
||||
if (@available(macOS 13.0, *)) {
|
||||
SMAppService *service = [SMAppService loginItemServiceWithIdentifier:helperBundleID];
|
||||
NSError *error = nil;
|
||||
if (@available(macOS 13.0, *)) {
|
||||
SMAppService *service = [SMAppService loginItemServiceWithIdentifier:helperBundleID];
|
||||
NSError *error = nil;
|
||||
|
||||
if (enabled) {
|
||||
if (service.status != SMAppServiceStatusEnabled) {
|
||||
if (![service registerAndReturnError:&error]) {
|
||||
NSLog(@"[Volume Control] Error registering login item: %@", error.localizedDescription);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (service.status != SMAppServiceStatusNotRegistered) {
|
||||
if (![service unregisterAndReturnError:&error]) {
|
||||
NSLog(@"[Volume Control] Error unregistering login item: %@", error.localizedDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Legacy fallback (macOS 12 and older)
|
||||
if (!SMLoginItemSetEnabled((__bridge CFStringRef)helperBundleID, enabled)) {
|
||||
NSLog(@"[Volume Control] SMLoginItemSetEnabled failed.");
|
||||
}
|
||||
}
|
||||
if (enabled) {
|
||||
if (service.status != SMAppServiceStatusEnabled) {
|
||||
if (![service registerAndReturnError:&error]) {
|
||||
NSLog(@"[Volume Control] Error registering login item: %@", error.localizedDescription);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (service.status != SMAppServiceStatusNotRegistered) {
|
||||
if (![service unregisterAndReturnError:&error]) {
|
||||
NSLog(@"[Volume Control] Error unregistering login item: %@", error.localizedDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Legacy fallback (macOS 12 and older)
|
||||
if (!SMLoginItemSetEnabled((__bridge CFStringRef)helperBundleID, enabled)) {
|
||||
NSLog(@"[Volume Control] SMLoginItemSetEnabled failed.");
|
||||
}
|
||||
}
|
||||
|
||||
if (savePreferences) {
|
||||
[preferences setBool:enabled forKey:@"StartAtLoginPreference"];
|
||||
}
|
||||
if (savePreferences) {
|
||||
[preferences setBool:enabled forKey:@"StartAtLoginPreference"];
|
||||
}
|
||||
|
||||
[self updateStartAtLoginMenuItem];
|
||||
[self updateStartAtLoginMenuItem];
|
||||
}
|
||||
|
||||
- (bool)StartAtLogin
|
||||
{
|
||||
NSString *helperBundleID = @"io.alberti42.VolumeControlHelper";
|
||||
NSString *helperBundleID = @"io.alberti42.VolumeControlHelper";
|
||||
|
||||
if (@available(macOS 13.0, *)) {
|
||||
SMAppService *service = [SMAppService loginItemServiceWithIdentifier:helperBundleID];
|
||||
return (service.status == SMAppServiceStatusEnabled ||
|
||||
service.status == SMAppServiceStatusRequiresApproval);
|
||||
} else {
|
||||
return [preferences boolForKey:@"StartAtLoginPreference"];
|
||||
}
|
||||
if (@available(macOS 13.0, *)) {
|
||||
SMAppService *service = [SMAppService loginItemServiceWithIdentifier:helperBundleID];
|
||||
return (service.status == SMAppServiceStatusEnabled ||
|
||||
service.status == SMAppServiceStatusRequiresApproval);
|
||||
} else {
|
||||
return [preferences boolForKey:@"StartAtLoginPreference"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)wasAuthorized
|
||||
|
|
@ -490,8 +490,11 @@ static NSString * const kHelperBundleIDSuffix = @"Helper";
|
|||
else if (runningPlayerPtr == doppler)
|
||||
[self setSpotifyVolume:[runningPlayerPtr currentVolume]];
|
||||
|
||||
if (_LockSystemAndPlayerVolume || runningPlayerPtr == systemAudio)
|
||||
[self setSystemVolume:[runningPlayerPtr currentVolume]];
|
||||
// Update system UI if system volume is affected or when locked
|
||||
if (_LockSystemAndPlayerVolume || runningPlayerPtr == systemAudio) {
|
||||
[self setSystemVolume:[systemAudio currentVolume]];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -785,9 +788,9 @@ static NSString * const kHelperBundleIDSuffix = @"Helper";
|
|||
|
||||
- (IBAction)toggleStartAtLogin:(id)sender
|
||||
{
|
||||
BOOL currentlyEnabled = [self StartAtLogin];
|
||||
[self setStartAtLogin:!currentlyEnabled savePreferences:YES];
|
||||
[self updateStartAtLoginMenuItem];
|
||||
BOOL currentlyEnabled = [self StartAtLogin];
|
||||
[self setStartAtLogin:!currentlyEnabled savePreferences:YES];
|
||||
[self updateStartAtLoginMenuItem];
|
||||
}
|
||||
|
||||
- (void) setUseAppleCMDModifier:(bool)enabled
|
||||
|
|
|
|||
|
|
@ -17,136 +17,155 @@
|
|||
|
||||
-(AudioDeviceID) getDefaultOutputDevice
|
||||
{
|
||||
AudioObjectPropertyAddress getDefaultOutputDevicePropertyAddress = {
|
||||
kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
AudioDeviceID defaultOutputDeviceID;
|
||||
UInt32 volumedataSize = sizeof(defaultOutputDeviceID);
|
||||
OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
||||
&getDefaultOutputDevicePropertyAddress,
|
||||
0, NULL,
|
||||
&volumedataSize, &defaultOutputDeviceID);
|
||||
|
||||
if(kAudioHardwareNoError != result)
|
||||
{
|
||||
NSLog(@"Cannot find default output device!");
|
||||
}
|
||||
|
||||
return defaultOutputDeviceID;
|
||||
AudioObjectPropertyAddress getDefaultOutputDevicePropertyAddress = {
|
||||
kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
AudioDeviceID defaultOutputDeviceID;
|
||||
UInt32 volumedataSize = sizeof(defaultOutputDeviceID);
|
||||
OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
||||
&getDefaultOutputDevicePropertyAddress,
|
||||
0, NULL,
|
||||
&volumedataSize, &defaultOutputDeviceID);
|
||||
|
||||
if(kAudioHardwareNoError != result)
|
||||
{
|
||||
NSLog(@"Cannot find default output device!");
|
||||
}
|
||||
|
||||
return defaultOutputDeviceID;
|
||||
}
|
||||
|
||||
- (void)setCurrentVolume:(double)currentVolume
|
||||
{
|
||||
AudioDeviceID defaultOutputDeviceID = [self getDefaultOutputDevice];
|
||||
AudioDeviceID defaultOutputDeviceID = [self getDefaultOutputDevice];
|
||||
|
||||
AudioObjectPropertyAddress volumePropertyAddress = {
|
||||
kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
AudioObjectPropertyAddress volumePropertyAddress = {
|
||||
kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
AudioObjectPropertyAddress mutePropertyAddress = {
|
||||
kAudioDevicePropertyMute,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
AudioObjectPropertyAddress mutePropertyAddress = {
|
||||
kAudioDevicePropertyMute,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
Float32 volume = (Float32)(currentVolume / 100.);
|
||||
UInt32 dataSize;
|
||||
Float32 volume = (Float32)(currentVolume / 100.);
|
||||
UInt32 dataSize;
|
||||
|
||||
if (volume == 0) {
|
||||
// Mute the device
|
||||
UInt32 mute = 1;
|
||||
dataSize = sizeof(mute);
|
||||
OSStatus result = AudioObjectSetPropertyData(defaultOutputDeviceID,
|
||||
&mutePropertyAddress,
|
||||
0, NULL,
|
||||
dataSize, &mute);
|
||||
if (result != noErr) {
|
||||
NSLog(@"Failed to mute device 0x%0x", defaultOutputDeviceID);
|
||||
}
|
||||
} else {
|
||||
// Unmute the device
|
||||
UInt32 mute = 0;
|
||||
dataSize = sizeof(mute);
|
||||
AudioObjectSetPropertyData(defaultOutputDeviceID,
|
||||
&mutePropertyAddress,
|
||||
0, NULL,
|
||||
dataSize, &mute);
|
||||
if (volume == 0) {
|
||||
// Mute the device
|
||||
UInt32 mute = 1;
|
||||
dataSize = sizeof(mute);
|
||||
OSStatus result = AudioObjectSetPropertyData(defaultOutputDeviceID,
|
||||
&mutePropertyAddress,
|
||||
0, NULL,
|
||||
dataSize, &mute);
|
||||
if (result != noErr) {
|
||||
NSLog(@"Failed to mute device 0x%0x", defaultOutputDeviceID);
|
||||
}
|
||||
} else {
|
||||
// Unmute the device
|
||||
UInt32 mute = 0;
|
||||
dataSize = sizeof(mute);
|
||||
AudioObjectSetPropertyData(defaultOutputDeviceID,
|
||||
&mutePropertyAddress,
|
||||
0, NULL,
|
||||
dataSize, &mute);
|
||||
|
||||
// Set the volume
|
||||
dataSize = sizeof(volume);
|
||||
OSStatus result = AudioObjectSetPropertyData(defaultOutputDeviceID,
|
||||
&volumePropertyAddress,
|
||||
0, NULL,
|
||||
dataSize, &volume);
|
||||
if (result != noErr) {
|
||||
NSLog(@"Failed to set volume for device 0x%0x", defaultOutputDeviceID);
|
||||
}
|
||||
}
|
||||
// Set the volume
|
||||
dataSize = sizeof(volume);
|
||||
OSStatus result = AudioObjectSetPropertyData(defaultOutputDeviceID,
|
||||
&volumePropertyAddress,
|
||||
0, NULL,
|
||||
dataSize, &volume);
|
||||
if (result != noErr) {
|
||||
NSLog(@"Failed to set volume for device 0x%0x", defaultOutputDeviceID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (bool) isMuted
|
||||
{
|
||||
AudioDeviceID defaultOutputDeviceID = [self getDefaultOutputDevice];
|
||||
|
||||
AudioObjectPropertyAddress volumePropertyAddress = {
|
||||
kAudioDevicePropertyMute,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
UInt32 muteVal;
|
||||
UInt32 muteValSize = sizeof(muteVal);
|
||||
OSStatus result = AudioObjectGetPropertyData(defaultOutputDeviceID,
|
||||
&volumePropertyAddress,
|
||||
0, NULL,
|
||||
&muteValSize, &muteVal);
|
||||
|
||||
if (result != kAudioHardwareNoError) {
|
||||
NSLog(@"No volume reported for device 0x%0x", defaultOutputDeviceID);
|
||||
}
|
||||
|
||||
return muteVal;
|
||||
}
|
||||
AudioDeviceID defaultOutputDeviceID = [self getDefaultOutputDevice];
|
||||
|
||||
AudioObjectPropertyAddress volumePropertyAddress = {
|
||||
kAudioDevicePropertyMute,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
UInt32 muteVal;
|
||||
UInt32 muteValSize = sizeof(muteVal);
|
||||
OSStatus result = AudioObjectGetPropertyData(defaultOutputDeviceID,
|
||||
&volumePropertyAddress,
|
||||
0, NULL,
|
||||
&muteValSize, &muteVal);
|
||||
|
||||
if (result != kAudioHardwareNoError) {
|
||||
NSLog(@"No volume reported for device 0x%0x", defaultOutputDeviceID);
|
||||
}
|
||||
|
||||
return muteVal;
|
||||
}
|
||||
|
||||
- (double) currentVolume
|
||||
{
|
||||
AudioDeviceID defaultOutputDeviceID = [self getDefaultOutputDevice];
|
||||
|
||||
AudioObjectPropertyAddress volumePropertyAddress = {
|
||||
kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
Float32 volume;
|
||||
UInt32 volumedataSize = sizeof(volume);
|
||||
OSStatus result = AudioObjectGetPropertyData(defaultOutputDeviceID,
|
||||
&volumePropertyAddress,
|
||||
0, NULL,
|
||||
&volumedataSize, &volume);
|
||||
|
||||
if (result != kAudioHardwareNoError) {
|
||||
NSLog(@"No volume reported for device 0x%0x", defaultOutputDeviceID);
|
||||
}
|
||||
|
||||
return ((double)volume)*100.;
|
||||
AudioDeviceID defaultOutputDeviceID = [self getDefaultOutputDevice];
|
||||
|
||||
// First, check mute state
|
||||
AudioObjectPropertyAddress mutePropertyAddress = {
|
||||
kAudioDevicePropertyMute,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
UInt32 muteVal = 0;
|
||||
UInt32 muteValSize = sizeof(muteVal);
|
||||
OSStatus muteResult = AudioObjectGetPropertyData(defaultOutputDeviceID,
|
||||
&mutePropertyAddress,
|
||||
0, NULL,
|
||||
&muteValSize, &muteVal);
|
||||
|
||||
if (muteResult == kAudioHardwareNoError && muteVal == 1) {
|
||||
return 0.0; // Treat mute as 0%
|
||||
}
|
||||
|
||||
// Otherwise, get the real volume
|
||||
AudioObjectPropertyAddress volumePropertyAddress = {
|
||||
kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
Float32 volume = 0;
|
||||
UInt32 volumedataSize = sizeof(volume);
|
||||
OSStatus result = AudioObjectGetPropertyData(defaultOutputDeviceID,
|
||||
&volumePropertyAddress,
|
||||
0, NULL,
|
||||
&volumedataSize, &volume);
|
||||
|
||||
if (result != kAudioHardwareNoError) {
|
||||
NSLog(@"No volume reported for device 0x%0x", defaultOutputDeviceID);
|
||||
}
|
||||
|
||||
return ((double)volume) * 100.0;
|
||||
}
|
||||
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
}
|
||||
|
||||
-(id)init{
|
||||
if (self = [super init]) {
|
||||
[self setOldVolume:[self currentVolume]];
|
||||
}
|
||||
return self;
|
||||
if (self = [super init]) {
|
||||
[self setOldVolume:[self currentVolume]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -19,17 +19,22 @@
|
|||
"build_systems": [
|
||||
{
|
||||
"name": "Build with xcodebuild for debug+x86_64",
|
||||
"shell_cmd": "source ./build_config.env && xcrun xcodebuild -project 'Volume Control.xcodeproj' -scheme 'Volume Control' -configuration Debug -destination 'platform=macOS,arch=x86_64' BUILD_DIR=\"\\${BUILD_DIR}\" CONFIGURATION_BUILD_DIR=\"\\${CONFIGURATION_BUILD_DIR}\" build | xcpretty",
|
||||
"shell_cmd": "source ./build_config.env && xcrun xcodebuild -project 'Volume Control.xcodeproj' -scheme 'Volume Control' -configuration Debug -destination 'platform=macOS,arch=x86_64' BUILD_DIR=\"\\${BUILD_DIR}/debug\" CONFIGURATION_BUILD_DIR=\"\\${CONFIGURATION_BUILD_DIR}/debug\" build | xcpretty",
|
||||
"working_dir": "${project_path}",
|
||||
},
|
||||
{
|
||||
"name": "Distribute",
|
||||
"shell_cmd": "source ./build_config.env && xcrun xcodebuild -project 'Volume Control.xcodeproj' -scheme 'Volume Control' -configuration Release ARCHS=\"arm64 x86_64\" ONLY_ACTIVE_ARCH=NO BUILD_DIR=\"\\${BUILD_DIR}/release\" CONFIGURATION_BUILD_DIR=\"\\${CONFIGURATION_BUILD_DIR}/release\" build | xcpretty",
|
||||
"working_dir": "${project_path}",
|
||||
},
|
||||
{
|
||||
"name": "Clean with xcodebuild for debug+x86_64",
|
||||
"shell_cmd": "source ./build_config.env && xcrun xcodebuild -project 'Volume Control.xcodeproj' -scheme 'Volume Control' -configuration Debug -destination 'platform=macOS,arch=x86_64' BUILD_DIR=\"\\${BUILD_DIR}\" CONFIGURATION_BUILD_DIR=\"\\${CONFIGURATION_BUILD_DIR}\" clean | xcpretty",
|
||||
"shell_cmd": "source ./build_config.env && xcrun xcodebuild -project 'Volume Control.xcodeproj' -scheme 'Volume Control' -configuration Debug -destination 'platform=macOS,arch=x86_64' BUILD_DIR=\"\\${BUILD_DIR}/debug\" CONFIGURATION_BUILD_DIR=\"\\${CONFIGURATION_BUILD_DIR}/debug\" clean | xcpretty",
|
||||
"working_dir": "${project_path}",
|
||||
},
|
||||
{
|
||||
"name": "Run App for debug",
|
||||
"shell_cmd": "source ./build_config.env && open \"\\${CONFIGURATION_BUILD_DIR}/Volume Control.app\"",
|
||||
"shell_cmd": "source ./build_config.env && open \"\\${CONFIGURATION_BUILD_DIR}/debug/Volume Control.app\"",
|
||||
"working_dir": "${project_path}"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# build_config.env: define build variables once
|
||||
|
||||
export BUILD_DIR="$(dirname "$0")/build"
|
||||
export CONFIGURATION_BUILD_DIR="${BUILD_DIR}/target/debug"
|
||||
export CONFIGURATION_BUILD_DIR="${BUILD_DIR}/target"
|
||||
|
|
|
|||
Loading…
Reference in New Issue