From 1171bee102b83a3a49b03f5572c16dd049a9a14f Mon Sep 17 00:00:00 2001 From: Kyle Neideck Date: Sat, 28 Oct 2017 18:13:08 +1100 Subject: [PATCH] Refactor non-UI code out of BGMAppVolumes. --- BGMApp/BGMApp.xcodeproj/project.pbxproj | 22 +- BGMApp/BGMApp/BGMAppDelegate.mm | 10 +- BGMApp/BGMApp/BGMAppVolumes.h | 19 +- .../{BGMAppVolumes.mm => BGMAppVolumes.m} | 230 +++++------------- BGMApp/BGMApp/BGMAppVolumesController.h | 41 ++++ BGMApp/BGMApp/BGMAppVolumesController.mm | 195 +++++++++++++++ BGMApp/BGMApp/BGMAudioDeviceManager.h | 15 +- BGMApp/BGMApp/BGMAudioDeviceManager.mm | 19 +- BGMApp/BGMApp/BGMBackgroundMusicDevice.cpp | 4 +- BGMApp/BGMApp/BGMBackgroundMusicDevice.h | 4 +- BGMApp/BGMApp/Music Players/BGMDecibel.m | 2 - BGMApp/BGMApp/Music Players/BGMHermes.m | 2 - BGMApp/BGMApp/Music Players/BGMMusicPlayer.m | 2 - .../BGMApp/Music Players/BGMScriptingBridge.m | 2 - BGMApp/BGMApp/Music Players/BGMSpotify.m | 2 - BGMApp/BGMApp/Music Players/BGMVLC.m | 2 - BGMApp/BGMApp/Music Players/BGMVOX.m | 2 - BGMApp/BGMApp/Music Players/BGMiTunes.m | 2 - BGMApp/BGMApp/Preferences/BGMAboutPanel.m | 2 - BGMApp/BGMXPCHelper/BGMXPCListenerDelegate.m | 2 - BGMApp/BGMXPCHelper/main.m | 2 - BGMApp/BGMXPCHelperTests/BGMXPCHelperTests.m | 7 +- BGMApp/PublicUtility/CADebugger.h | 11 +- BGMDriver/PublicUtility/CADebugMacros.cpp | 8 +- SharedSource/BGM_Utils.h | 2 +- 25 files changed, 392 insertions(+), 217 deletions(-) rename BGMApp/BGMApp/{BGMAppVolumes.mm => BGMAppVolumes.m} (62%) create mode 100644 BGMApp/BGMApp/BGMAppVolumesController.h create mode 100644 BGMApp/BGMApp/BGMAppVolumesController.mm diff --git a/BGMApp/BGMApp.xcodeproj/project.pbxproj b/BGMApp/BGMApp.xcodeproj/project.pbxproj index 1a4bc97..0e2361b 100644 --- a/BGMApp/BGMApp.xcodeproj/project.pbxproj +++ b/BGMApp/BGMApp.xcodeproj/project.pbxproj @@ -36,7 +36,7 @@ 1C3D36721ED90E8600F98E66 /* BGMDeviceControlsList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C3D36701ED90E8600F98E66 /* BGMDeviceControlsList.cpp */; }; 1C3D36731ED90E8600F98E66 /* BGMDeviceControlsList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C3D36701ED90E8600F98E66 /* BGMDeviceControlsList.cpp */; }; 1C3D36741ED90E8600F98E66 /* BGMDeviceControlsList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C3D36701ED90E8600F98E66 /* BGMDeviceControlsList.cpp */; }; - 1C3DB4891BE0885A00EC8160 /* BGMAppVolumes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C3DB4881BE0885A00EC8160 /* BGMAppVolumes.mm */; }; + 1C3DB4891BE0885A00EC8160 /* BGMAppVolumes.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C3DB4881BE0885A00EC8160 /* BGMAppVolumes.m */; }; 1C4699471BD5C0E400F78043 /* BGMiTunes.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C4699461BD5C0E400F78043 /* BGMiTunes.m */; }; 1C46994E1BD7694C00F78043 /* BGMDeviceControlSync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C46994C1BD7694C00F78043 /* BGMDeviceControlSync.cpp */; }; 1C50FF631EC9F4490031A6EA /* BGMAudioDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CF5423A1EAAEE4300445AD8 /* BGMAudioDevice.cpp */; }; @@ -65,6 +65,9 @@ 1CCC4F4E1E581C40008053E4 /* Mock_CAHALAudioObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CCC4F4C1E581C40008053E4 /* Mock_CAHALAudioObject.cpp */; }; 1CCC4F621E584100008053E4 /* BGMAppUITests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CCC4F611E584100008053E4 /* BGMAppUITests.mm */; }; 1CD1FD301BDDEAF2004F7E1B /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CD1FD2F1BDDEAF2004F7E1B /* AudioToolbox.framework */; }; + 1CD410D41F9EDDAD0070A094 /* BGMAppVolumesController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CD410D31F9EDDAD0070A094 /* BGMAppVolumesController.mm */; }; + 1CD410D51F9EDDAD0070A094 /* BGMAppVolumesController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CD410D31F9EDDAD0070A094 /* BGMAppVolumesController.mm */; }; + 1CD410D61F9EDDAD0070A094 /* BGMAppVolumesController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CD410D31F9EDDAD0070A094 /* BGMAppVolumesController.mm */; }; 1CD989341ECFFC9E0014BBBF /* BGM_Utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FB8C2E1DE468320084DB9D /* BGM_Utils.cpp */; }; 1CD989351ECFFC9E0014BBBF /* CACFArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CC1DF7D1BE5068A00FB8FE4 /* CACFArray.cpp */; }; 1CD989361ECFFC9E0014BBBF /* CACFDictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CC1DF7F1BE5068A00FB8FE4 /* CACFDictionary.cpp */; }; @@ -79,7 +82,7 @@ 1CD9893F1ECFFC9E0014BBBF /* CAHALAudioSystemObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C1962F11BCABFC5008A4DF7 /* CAHALAudioSystemObject.cpp */; }; 1CD989401ECFFCC50014BBBF /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CD1FD2F1BDDEAF2004F7E1B /* AudioToolbox.framework */; }; 1CD989411ECFFCD10014BBBF /* BGMAppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CB8B33C1BBA75EF000E2DD1 /* BGMAppDelegate.mm */; }; - 1CD989421ECFFCFC0014BBBF /* BGMAppVolumes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C3DB4881BE0885A00EC8160 /* BGMAppVolumes.mm */; }; + 1CD989421ECFFCFC0014BBBF /* BGMAppVolumes.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C3DB4881BE0885A00EC8160 /* BGMAppVolumes.m */; }; 1CD989431ECFFCFC0014BBBF /* BGMAudioDeviceManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CED616B1C316E1A002CAFCF /* BGMAudioDeviceManager.mm */; }; 1CD989441ECFFCFC0014BBBF /* BGMAutoPauseMenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C457E51CF2BC2600A6C9A6 /* BGMAutoPauseMenuItem.m */; }; 1CD989451ECFFCFC0014BBBF /* BGMAutoPauseMusic.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C1465B71BCC3A73003AEFE6 /* BGMAutoPauseMusic.mm */; }; @@ -240,7 +243,7 @@ 1C2FC31D1EC723A100A76592 /* BGMASOutputDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BGMASOutputDevice.h; path = Scripting/BGMASOutputDevice.h; sourceTree = ""; }; 1C3D36701ED90E8600F98E66 /* BGMDeviceControlsList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BGMDeviceControlsList.cpp; sourceTree = ""; }; 1C3D36711ED90E8600F98E66 /* BGMDeviceControlsList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMDeviceControlsList.h; sourceTree = ""; }; - 1C3DB4881BE0885A00EC8160 /* BGMAppVolumes.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BGMAppVolumes.mm; sourceTree = ""; }; + 1C3DB4881BE0885A00EC8160 /* BGMAppVolumes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BGMAppVolumes.m; sourceTree = ""; }; 1C3DB48A1BE0888500EC8160 /* BGMAppVolumes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMAppVolumes.h; sourceTree = ""; }; 1C4699461BD5C0E400F78043 /* BGMiTunes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BGMiTunes.m; path = "Music Players/BGMiTunes.m"; sourceTree = ""; }; 1C46994C1BD7694C00F78043 /* BGMDeviceControlSync.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BGMDeviceControlSync.cpp; sourceTree = ""; }; @@ -277,6 +280,8 @@ 1CCC4F5F1E5840EF008053E4 /* BGMAppUITests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "BGMAppUITests-Info.plist"; path = "UITests/BGMAppUITests-Info.plist"; sourceTree = ""; }; 1CCC4F611E584100008053E4 /* BGMAppUITests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BGMAppUITests.mm; path = BGMAppTests/UITests/BGMAppUITests.mm; sourceTree = SOURCE_ROOT; }; 1CD1FD2F1BDDEAF2004F7E1B /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + 1CD410D21F9EDDAD0070A094 /* BGMAppVolumesController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BGMAppVolumesController.h; sourceTree = ""; }; + 1CD410D31F9EDDAD0070A094 /* BGMAppVolumesController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = BGMAppVolumesController.mm; sourceTree = ""; }; 1CE7064A1BF1EC0600BFC06D /* BGMOutputDevicePrefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BGMOutputDevicePrefs.h; path = Preferences/BGMOutputDevicePrefs.h; sourceTree = ""; }; 1CE7064B1BF1EC0600BFC06D /* BGMOutputDevicePrefs.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BGMOutputDevicePrefs.mm; path = Preferences/BGMOutputDevicePrefs.mm; sourceTree = ""; }; 1CEACF4E1F34A30000FEC143 /* Mock_CAHALAudioSystemObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mock_CAHALAudioSystemObject.cpp; path = UnitTests/Mock_CAHALAudioSystemObject.cpp; sourceTree = ""; }; @@ -527,7 +532,9 @@ 1C837DD61F6AA1F2004B1E60 /* BGMOutputVolumeMenuItem.h */, 1C837DD71F6AA1F2004B1E60 /* BGMOutputVolumeMenuItem.mm */, 1C3DB48A1BE0888500EC8160 /* BGMAppVolumes.h */, - 1C3DB4881BE0885A00EC8160 /* BGMAppVolumes.mm */, + 1C3DB4881BE0885A00EC8160 /* BGMAppVolumes.m */, + 1CD410D21F9EDDAD0070A094 /* BGMAppVolumesController.h */, + 1CD410D31F9EDDAD0070A094 /* BGMAppVolumesController.mm */, 1CED616A1C316E1A002CAFCF /* BGMAudioDeviceManager.h */, 1CED616B1C316E1A002CAFCF /* BGMAudioDeviceManager.mm */, 1CF5423B1EAAEE4300445AD8 /* BGMAudioDevice.h */, @@ -921,6 +928,7 @@ files = ( 1C86DA6A1F91EE3B000C8CCF /* CAPThread.cpp in Sources */, 1C4699471BD5C0E400F78043 /* BGMiTunes.m in Sources */, + 1CD410D41F9EDDAD0070A094 /* BGMAppVolumesController.mm in Sources */, 1C1962E41BC94E15008A4DF7 /* CARingBuffer.cpp in Sources */, 273F10DF1CC3D0B900C1C6DA /* BGMVOX.m in Sources */, 1CC1DF811BE5068A00FB8FE4 /* CACFArray.cpp in Sources */, @@ -931,7 +939,7 @@ 1C2336DA1BEAB6E7004C1C4E /* BGMMusicPlayer.m in Sources */, 1C1962F61BCABFC5008A4DF7 /* CAHALAudioSystemObject.cpp in Sources */, 1CC1DF821BE5068A00FB8FE4 /* CACFDictionary.cpp in Sources */, - 1C3DB4891BE0885A00EC8160 /* BGMAppVolumes.mm in Sources */, + 1C3DB4891BE0885A00EC8160 /* BGMAppVolumes.m in Sources */, 1C0BD0A51BF1A8E6004F4CF5 /* BGMAutoPauseMusicPrefs.mm in Sources */, 1C1963061BCAF468008A4DF7 /* CAMutex.cpp in Sources */, 1CE7064C1BF1EC0600BFC06D /* BGMOutputDevicePrefs.mm in Sources */, @@ -974,11 +982,12 @@ files = ( 1CACCF3A1F334447007F86CA /* BGMBackgroundMusicDevice.cpp in Sources */, 1CC6593D1F91DEB400B0CCDC /* BGMTermination.mm in Sources */, + 1CD410D51F9EDDAD0070A094 /* BGMAppVolumesController.mm in Sources */, 1CD989571ECFFD250014BBBF /* CAHostTimeBase.cpp in Sources */, 1CD989581ECFFD250014BBBF /* CAMutex.cpp in Sources */, 1CD989591ECFFD250014BBBF /* CAPThread.cpp in Sources */, 1CD9895A1ECFFD250014BBBF /* CARingBuffer.cpp in Sources */, - 1CD989421ECFFCFC0014BBBF /* BGMAppVolumes.mm in Sources */, + 1CD989421ECFFCFC0014BBBF /* BGMAppVolumes.m in Sources */, 1CD989431ECFFCFC0014BBBF /* BGMAudioDeviceManager.mm in Sources */, 1CD989441ECFFCFC0014BBBF /* BGMAutoPauseMenuItem.m in Sources */, 1CD989451ECFFCFC0014BBBF /* BGMAutoPauseMusic.mm in Sources */, @@ -1079,6 +1088,7 @@ 2743CA031D86D41C0089613B /* BGMScriptingBridge.m in Sources */, 1CEACF4F1F34A30000FEC143 /* Mock_CAHALAudioSystemObject.cpp in Sources */, 2743CA041D86D41C0089613B /* BGMMusicPlayer.m in Sources */, + 1CD410D61F9EDDAD0070A094 /* BGMAppVolumesController.mm in Sources */, 2743CA051D86D41C0089613B /* BGMDecibel.m in Sources */, 2743CA061D86D41C0089613B /* BGMSpotify.m in Sources */, 2743CA071D86D41C0089613B /* BGMVLC.m in Sources */, diff --git a/BGMApp/BGMApp/BGMAppDelegate.mm b/BGMApp/BGMApp/BGMAppDelegate.mm index 97dcd10..e1c0d37 100644 --- a/BGMApp/BGMApp/BGMAppDelegate.mm +++ b/BGMApp/BGMApp/BGMAppDelegate.mm @@ -29,7 +29,7 @@ #import "BGMMusicPlayers.h" #import "BGMAutoPauseMusic.h" #import "BGMAutoPauseMenuItem.h" -#import "BGMAppVolumes.h" +#import "BGMAppVolumesController.h" #import "BGMPreferencesMenu.h" #import "BGMXPCListener.h" #import "BGMOutputVolumeMenuItem.h" @@ -55,7 +55,7 @@ static float const kStatusBarIconPadding = 0.25; BGMAutoPauseMusic* autoPauseMusic; BGMAutoPauseMenuItem* autoPauseMenuItem; BGMMusicPlayers* musicPlayers; - BGMAppVolumes* appVolumes; + BGMAppVolumesController* appVolumes; BGMPreferencesMenu* prefsMenu; BGMXPCListener* xpcListener; } @@ -182,9 +182,9 @@ static float const kStatusBarIconPadding = 0.25; atIndex:([self.bgmMenu indexOfItemWithTag:kVolumesHeadingMenuItemTag] + 1)]; - appVolumes = [[BGMAppVolumes alloc] initWithMenu:self.bgmMenu - appVolumeView:self.appVolumeView - audioDevices:audioDevices]; + appVolumes = [[BGMAppVolumesController alloc] initWithMenu:self.bgmMenu + appVolumeView:self.appVolumeView + audioDevices:audioDevices]; prefsMenu = [[BGMPreferencesMenu alloc] initWithBGMMenu:self.bgmMenu audioDevices:audioDevices diff --git a/BGMApp/BGMApp/BGMAppVolumes.h b/BGMApp/BGMApp/BGMAppVolumes.h index bda363a..717a41d 100644 --- a/BGMApp/BGMApp/BGMAppVolumes.h +++ b/BGMApp/BGMApp/BGMAppVolumes.h @@ -17,7 +17,7 @@ // BGMAppVolumes.h // BGMApp // -// Copyright © 2016 Kyle Neideck +// Copyright © 2016, 2017 Kyle Neideck // // Local Includes @@ -26,6 +26,7 @@ // System Includes #import +#pragma clang assume_nonnull begin @interface BGMAppVolumes : NSObject @@ -33,6 +34,15 @@ appVolumeView:(NSView*)view audioDevices:(BGMAudioDeviceManager*)audioDevices; +// Pass -1 for initialVolume or initialPan to leave the volume/pan at its default level. +- (void) insertMenuItemForApp:(NSRunningApplication*)app + initialVolume:(int)volume + initialPan:(int)pan; + +- (void) removeMenuItemForApp:(NSRunningApplication*)app; + +- (void) removeAllAppVolumeMenuItems; + @end // Protocol for the UI custom classes @@ -58,13 +68,16 @@ @interface BGMAVM_VolumeSlider : NSSlider -- (void) setRelativeVolume:(NSNumber*)relativeVolume; +- (void) setRelativeVolume:(int)relativeVolume; @end @interface BGMAVM_PanSlider : NSSlider -- (void) setPanPosition:(NSNumber*)panPosition; +- (void) setPanPosition:(int)panPosition; @end +#pragma clang assume_nonnull end + + diff --git a/BGMApp/BGMApp/BGMAppVolumes.mm b/BGMApp/BGMApp/BGMAppVolumes.m similarity index 62% rename from BGMApp/BGMApp/BGMAppVolumes.mm rename to BGMApp/BGMApp/BGMAppVolumes.m index f06290c..7e97015 100644 --- a/BGMApp/BGMApp/BGMAppVolumes.mm +++ b/BGMApp/BGMApp/BGMAppVolumes.m @@ -30,9 +30,7 @@ #import "BGMAppDelegate.h" // PublicUtility Includes -#import "CACFDictionary.h" -#import "CACFArray.h" -#import "CACFString.h" +#import "CADebugMacros.h" static float const kSlidersSnapWithin = 5; @@ -52,7 +50,9 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; NSInteger numMenuItems; } -- (id) initWithMenu:(NSMenu*)menu appVolumeView:(NSView*)view audioDevices:(BGMAudioDeviceManager*)devices { +- (id) initWithMenu:(NSMenu*)menu + appVolumeView:(NSView*)view + audioDevices:(BGMAudioDeviceManager*)devices { if ((self = [super init])) { bgmMenu = menu; moreAppsMenu = [[NSMenu alloc] initWithTitle:kMoreAppsMenuTitle]; @@ -60,9 +60,6 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; appVolumeViewFullHeight = appVolumeView.frame.size.height; audioDevices = devices; numMenuItems = 0; - - // Create the menu items for controlling app volumes - [self insertMenuItemsForApps:[[NSWorkspace sharedWorkspace] runningApplications]]; // Add the More Apps menu to the main menu. NSMenuItem* moreAppsMenuItem = @@ -79,21 +76,11 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; [bgmMenu insertItem:spacer atIndex:[self lastMenuItemIndex]]; numMenuItems++; - - // Register for notifications when the user opens or closes apps, so we can update the menu - [[NSWorkspace sharedWorkspace] addObserver:self - forKeyPath:@"runningApplications" - options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld - context:nil]; } return self; } -- (void) dealloc { - [[NSWorkspace sharedWorkspace] removeObserver:self forKeyPath:@"runningApplications" context:nil]; -} - // This method allows the Interface Builder Custom Classes for controls (below) to send their values // directly to BGMDevice. Not public to other classes. - (BGMAudioDeviceManager*) audioDevices { @@ -102,37 +89,9 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; #pragma mark UI Modifications -// Adds a volume control menu item for each given app. -- (void) insertMenuItemsForApps:(NSArray*)apps { - NSAssert([NSThread isMainThread], @"insertMenuItemsForApps is not thread safe"); - - // TODO: Handle the C++ exceptions this method can throw. They can cause crashes because this - // method is called in a KVO handler. - - // Get the app volumes currently set on the device - CACFArray appVols([audioDevices bgmDevice].GetAppVolumes(), false); - - for (NSRunningApplication* app in apps) { - if ([self shouldBeIncludedInMenu:app]) { - [self insertMenuItemForApp:app appVolumesOnDevice:appVols]; - } - } -} - -- (BOOL) shouldBeIncludedInMenu:(NSRunningApplication*)app { - // Ignore hidden apps and Background Music itself. - // TODO: Would it be better to only show apps that are registered as HAL clients? - BOOL isHidden = app.activationPolicy != NSApplicationActivationPolicyRegular && - app.activationPolicy != NSApplicationActivationPolicyAccessory; - - NSString* bundleID = app.bundleIdentifier; - BOOL isBGMApp = bundleID && [@kBGMAppBundleID isEqualToString:BGMNN(bundleID)]; - - return !isHidden && !isBGMApp; -} - - (void) insertMenuItemForApp:(NSRunningApplication*)app - appVolumesOnDevice:(const CACFArray&)appVols { + initialVolume:(int)volume + initialPan:(int)pan { NSMenuItem* appVolItem = [self createBlankAppVolumeMenuItem]; // Look through the menu item's subviews for the ones we want to set up @@ -148,7 +107,7 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; appVolItem.representedObject = app; // Set the slider to the volume for this app if we got one from the driver - [self setVolumeOfMenuItem:appVolItem fromAppVolumes:appVols]; + [self setVolumeOfMenuItem:appVolItem relativeVolume:volume panPosition:pan]; // NSMenuItem didn't implement NSAccessibility before OS X SDK 10.12. #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 // MAC_OS_X_VERSION_10_12 @@ -180,6 +139,19 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; return menuItem; } +- (void) setVolumeOfMenuItem:(NSMenuItem*)menuItem relativeVolume:(int)volume panPosition:(int)pan { + // Update the sliders. + for (NSView* subview in menuItem.view.subviews) { + if (volume != -1 && [subview isKindOfClass:[BGMAVM_VolumeSlider class]]) { + [(BGMAVM_VolumeSlider*)subview setRelativeVolume:volume]; + } + + if (pan != -1 && [subview isKindOfClass:[BGMAVM_PanSlider class]]) { + [(BGMAVM_PanSlider*)subview setPanPosition:pan]; + } + } +} + - (NSInteger) firstMenuItemIndex { return [self lastMenuItemIndex] - numMenuItems + 1; } @@ -188,81 +160,34 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; return [bgmMenu indexOfItemWithTag:kSeparatorBelowVolumesMenuItemTag] - 1; } -- (void) removeMenuItemsForApps:(NSArray*)apps { - NSAssert([NSThread isMainThread], @"removeMenuItemsForApps is not thread safe"); - +- (void) removeMenuItemForApp:(NSRunningApplication*)app { // Subtract two extra positions to skip the More Apps menu and the spacer menu item above it. NSInteger lastAppVolumeMenuItemIndex = [self lastMenuItemIndex] - 2; - // Check each app volume menu item, removing the items that control one of the given apps - for (NSRunningApplication* appToBeRemoved in apps) { - BOOL didRemoveItem = NO; + // Check each app volume menu item and remove the item that controls the given app. - // Look through the main menu. - for (NSInteger i = [self firstMenuItemIndex]; i <= lastAppVolumeMenuItemIndex; i++) { - NSMenuItem* item = [bgmMenu itemAtIndex:i]; - NSRunningApplication* itemApp = item.representedObject; - BGMAssert(itemApp, "!itemApp for %s", item.title.UTF8String); + // Look through the main menu. + for (NSInteger i = [self firstMenuItemIndex]; i <= lastAppVolumeMenuItemIndex; i++) { + NSMenuItem* item = [bgmMenu itemAtIndex:i]; + NSRunningApplication* itemApp = item.representedObject; + BGMAssert(itemApp, "!itemApp for %s", item.title.UTF8String); - if ([itemApp isEqual:appToBeRemoved]) { - [bgmMenu removeItem:item]; - numMenuItems--; - - didRemoveItem = YES; - break; - } - } - - // Look through the More Apps menu. - if (!didRemoveItem) { - for (NSInteger i = 0; i < [moreAppsMenu numberOfItems]; i++) { - NSMenuItem* item = [moreAppsMenu itemAtIndex:i]; - NSRunningApplication* itemApp = item.representedObject; - BGMAssert(itemApp, "!itemApp for %s", item.title.UTF8String); - - if ([itemApp isEqual:appToBeRemoved]) { - [moreAppsMenu removeItem:item]; - break; - } - } + if ([itemApp isEqual:app]) { + [bgmMenu removeItem:item]; + numMenuItems--; + return; } } -} -- (void) setVolumeOfMenuItem:(NSMenuItem*)menuItem fromAppVolumes:(const CACFArray&)appVolumes { - // Set menuItem's volume slider to the volume of the app in appVolumes that menuItem represents - // Leaves menuItem unchanged if it doesn't match any of the apps in appVolumes - NSRunningApplication* representedApp = menuItem.representedObject; - - for (UInt32 i = 0; i < appVolumes.GetNumberItems(); i++) { - CACFDictionary appVolume(false); - appVolumes.GetCACFDictionary(i, appVolume); - - // Match the app to the menu item by pid or bundle id - CACFString bundleID; - bundleID.DontAllowRelease(); - appVolume.GetCACFString(CFSTR(kBGMAppVolumesKey_BundleID), bundleID); - - pid_t pid; - appVolume.GetSInt32(CFSTR(kBGMAppVolumesKey_ProcessID), pid); - - if ((representedApp.processIdentifier == pid) || - [representedApp.bundleIdentifier isEqualToString:(__bridge NSString*)bundleID.GetCFString()]) { - CFTypeRef relativeVolume; - appVolume.GetCFType(CFSTR(kBGMAppVolumesKey_RelativeVolume), relativeVolume); - - CFTypeRef panPosition; - appVolume.GetCFType(CFSTR(kBGMAppVolumesKey_PanPosition), panPosition); - - // Update the slider - for (NSView* subview in menuItem.view.subviews) { - if ([subview respondsToSelector:@selector(setRelativeVolume:)]) { - [subview performSelector:@selector(setRelativeVolume:) withObject:(__bridge NSNumber*)relativeVolume]; - } - if ([subview respondsToSelector:@selector(setPanPosition:)]) { - [subview performSelector:@selector(setPanPosition:) withObject:(__bridge NSNumber*)panPosition]; - } - } + // Look through the More Apps menu. + for (NSInteger i = 0; i < [moreAppsMenu numberOfItems]; i++) { + NSMenuItem* item = [moreAppsMenu itemAtIndex:i]; + NSRunningApplication* itemApp = item.representedObject; + BGMAssert(itemApp, "!itemApp for %s", item.title.UTF8String); + + if ([itemApp isEqual:app]) { + [moreAppsMenu removeItem:item]; + return; } } } @@ -281,8 +206,9 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; #if DEBUG const char* appName = [((NSRunningApplication*)menuItem.representedObject).localizedName UTF8String]; #endif - - auto nearEnough = [](CGFloat x, CGFloat y) { // Shouldn't be necessary, but just in case. + + // Using this function (instead of just ==) shouldn't be necessary, but just in case. + BOOL(^nearEnough)(CGFloat x, CGFloat y) = ^BOOL(CGFloat x, CGFloat y) { return fabs(x - y) < 0.01; // We don't need much precision. }; @@ -293,7 +219,7 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; BGMAssert(nearEnough(height, appVolumeViewFullHeight), "Extra controls were already hidden"); // Make the menu item shorter to hide the extra controls. Keep the width unchanged. - menuItem.view.frameSize = { width, kAppVolumeViewInitialHeight }; + menuItem.view.frameSize = NSMakeSize(width, kAppVolumeViewInitialHeight); // Turn the button upside down so the arrowhead points down. button.frameCenterRotation = 180.0; // Move the button up slightly so it aligns with the volume slider. @@ -315,7 +241,7 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; BGMAssert(nearEnough(height, kAppVolumeViewInitialHeight), "Extra controls were already shown"); // Make the menu item taller to show the extra controls. Keep the width unchanged. - menuItem.view.frameSize = { width, appVolumeViewFullHeight }; + menuItem.view.frameSize = NSMakeSize(width, appVolumeViewFullHeight); // Turn the button rightside up so the arrowhead points up. button.frameCenterRotation = 0.0; // Move the button down slightly, back to it's original position. @@ -328,38 +254,16 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; } } -#pragma mark KVO - -- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ - #pragma unused (object, context) - - // KVO callback for the apps currently running on the system. Adds/removes the associated menu items. - if ([keyPath isEqualToString:@"runningApplications"]) { - NSArray* newApps = change[NSKeyValueChangeNewKey]; - NSArray* oldApps = change[NSKeyValueChangeOldKey]; - - int changeKind = [[change valueForKey:NSKeyValueChangeKindKey] intValue]; - switch (changeKind) { - case NSKeyValueChangeInsertion: - [self insertMenuItemsForApps:newApps]; - break; - - case NSKeyValueChangeRemoval: - [self removeMenuItemsForApps:oldApps]; - break; - - case NSKeyValueChangeReplacement: - [self removeMenuItemsForApps:oldApps]; - [self insertMenuItemsForApps:newApps]; - break; - - case NSKeyValueChangeSetting: - [bgmMenu removeAllItems]; - [self insertMenuItemsForApps:newApps]; - break; - } +- (void) removeAllAppVolumeMenuItems { + // Remove all of the menu items this class adds to the menu except for the last two, which are + // the More Apps menu item and the invisible spacer above it. + while (numMenuItems > 2) { + [bgmMenu removeItemAtIndex:[self firstMenuItemIndex]]; + numMenuItems--; } + + // The More Apps menu only contains app volume menu items, so we can just remove everything. + [moreAppsMenu removeAllItems]; } @end @@ -429,7 +333,7 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; @implementation BGMAVM_VolumeSlider { // Will be set to -1 for apps without a pid pid_t appProcessID; - NSString* appBundleID; + NSString* __nullable appBundleID; BGMAppVolumes* context; } @@ -459,14 +363,14 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; // changes how the slider looks. - (void) snap { // Snap to the 50% point. - float midPoint = static_cast((self.maxValue + self.minValue) / 2); + float midPoint = (float)((self.maxValue + self.minValue) / 2); if (self.floatValue > (midPoint - kSlidersSnapWithin) && self.floatValue < (midPoint + kSlidersSnapWithin)) { self.floatValue = midPoint; } } -- (void) setRelativeVolume:(NSNumber*)relativeVolume { - self.intValue = relativeVolume.intValue; +- (void) setRelativeVolume:(int)relativeVolume { + self.intValue = relativeVolume; [self snap]; } @@ -479,9 +383,9 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; // The values from our sliders are in // [kAppRelativeVolumeMinRawValue, kAppRelativeVolumeMaxRawValue] already. - context.audioDevices.bgmDevice.SetAppVolume(self.intValue, - appProcessID, - (__bridge_retained CFStringRef)appBundleID); + [context.audioDevices setVolume:self.intValue + forAppWithProcessID:appProcessID + bundleID:appBundleID]; } @end @@ -489,7 +393,7 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; @implementation BGMAVM_PanSlider { // Will be set to -1 for apps without a pid pid_t appProcessID; - NSString* appBundleID; + NSString* __nullable appBundleID; BGMAppVolumes* context; } @@ -515,8 +419,8 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; } } -- (void) setPanPosition:(NSNumber *)panPosition { - self.intValue = panPosition.intValue; +- (void) setPanPosition:(int)panPosition { + self.intValue = panPosition; } - (void) appPanPositionChanged { @@ -525,9 +429,9 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps"; DebugMsg("BGMAppVolumes::appPanPositionChanged: App pan position for %s changed to %d", appBundleID.UTF8String, self.intValue); // The values from our sliders are in [kAppPanLeftRawValue, kAppPanRightRawValue] already. - context.audioDevices.bgmDevice.SetAppPanPosition(self.intValue, - appProcessID, - (__bridge_retained CFStringRef)appBundleID); + [context.audioDevices setPanPosition:self.intValue + forAppWithProcessID:appProcessID + bundleID:appBundleID]; } @end diff --git a/BGMApp/BGMApp/BGMAppVolumesController.h b/BGMApp/BGMApp/BGMAppVolumesController.h new file mode 100644 index 0000000..dc2aff9 --- /dev/null +++ b/BGMApp/BGMApp/BGMAppVolumesController.h @@ -0,0 +1,41 @@ +// This file is part of Background Music. +// +// Background Music is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 2 of the +// License, or (at your option) any later version. +// +// Background Music is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Background Music. If not, see . + +// +// BGMAppVolumesController.h +// BGMApp +// +// Copyright © 2017 Kyle Neideck +// + +// Local Includes +#import "BGMAudioDeviceManager.h" + +// System Includes +#import + + +#pragma clang assume_nonnull begin + +@interface BGMAppVolumesController : NSObject + +- (id) initWithMenu:(NSMenu*)menu + appVolumeView:(NSView*)view + audioDevices:(BGMAudioDeviceManager*)audioDevices; + +@end + +#pragma clang assume_nonnull end + diff --git a/BGMApp/BGMApp/BGMAppVolumesController.mm b/BGMApp/BGMApp/BGMAppVolumesController.mm new file mode 100644 index 0000000..4fbf109 --- /dev/null +++ b/BGMApp/BGMApp/BGMAppVolumesController.mm @@ -0,0 +1,195 @@ +// This file is part of Background Music. +// +// Background Music is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 2 of the +// License, or (at your option) any later version. +// +// Background Music is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Background Music. If not, see . + +// +// BGMAppVolumesController.mm +// BGMApp +// +// Copyright © 2017 Kyle Neideck +// Copyright © 2017 Andrew Tonner +// + +// Self Include +#import "BGMAppVolumesController.h" + +// Local Includes +#import "BGM_Types.h" +#import "BGM_Utils.h" +#import "BGMAppVolumes.h" + +// PublicUtility Includes +#import "CACFArray.h" +#import "CACFDictionary.h" +#import "CACFString.h" + + +#pragma clang assume_nonnull begin + +typedef struct BGMAppVolumeAndPan { + int volume; + int pan; +} BGMAppVolumeAndPan; + +@implementation BGMAppVolumesController { + // The App Volumes UI. + BGMAppVolumes* appVolumes; + BGMAudioDeviceManager* audioDevices; +} + +- (id) initWithMenu:(NSMenu*)menu + appVolumeView:(NSView*)view + audioDevices:(BGMAudioDeviceManager*)devices { + if ((self = [super init])) { + audioDevices = devices; + appVolumes = [[BGMAppVolumes alloc] initWithMenu:menu + appVolumeView:view + audioDevices:devices]; + + // Create the menu items for controlling app volumes. + NSArray* apps = [[NSWorkspace sharedWorkspace] runningApplications]; + [self insertMenuItemsForApps:apps]; + + // Register for notifications when the user opens or closes apps, so we can update the menu. + auto opts = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld; + [[NSWorkspace sharedWorkspace] addObserver:self + forKeyPath:@"runningApplications" + options:opts + context:nil]; + } + + return self; +} + +- (void) dealloc { + [[NSWorkspace sharedWorkspace] removeObserver:self + forKeyPath:@"runningApplications" + context:nil]; +} + +// Adds a volume control menu item for each given app. +- (void) insertMenuItemsForApps:(NSArray*)apps { + NSAssert([NSThread isMainThread], @"insertMenuItemsForApps is not thread safe"); + + // TODO: Handle the C++ exceptions this method can throw. They can cause crashes because this + // method is called in a KVO handler. + + // Get the app volumes currently set on the device + CACFArray volumesFromBGMDevice([audioDevices bgmDevice].GetAppVolumes(), false); + + for (NSRunningApplication* app in apps) { + if ([self shouldBeIncludedInMenu:app]) { + BGMAppVolumeAndPan initial = [self getVolumeAndPanForApp:app + fromVolumes:volumesFromBGMDevice]; + [appVolumes insertMenuItemForApp:app + initialVolume:initial.volume + initialPan:initial.pan]; + } + } +} + +- (BGMAppVolumeAndPan) getVolumeAndPanForApp:(NSRunningApplication*)app + fromVolumes:(const CACFArray&)volumes { + BGMAppVolumeAndPan volumeAndPan = { + .volume = -1, + .pan = -1 + }; + + for (UInt32 i = 0; i < volumes.GetNumberItems(); i++) { + CACFDictionary appVolume(false); + volumes.GetCACFDictionary(i, appVolume); + + // Match the app to the volume/pan by pid or bundle ID. + CACFString bundleID; + bundleID.DontAllowRelease(); + appVolume.GetCACFString(CFSTR(kBGMAppVolumesKey_BundleID), bundleID); + + pid_t pid; + appVolume.GetSInt32(CFSTR(kBGMAppVolumesKey_ProcessID), pid); + + if ((app.processIdentifier == pid) || + [app.bundleIdentifier isEqualToString:(__bridge NSString*)bundleID.GetCFString()]) { + // Found a match, so read the volume and pan. + appVolume.GetSInt32(CFSTR(kBGMAppVolumesKey_RelativeVolume), volumeAndPan.volume); + appVolume.GetSInt32(CFSTR(kBGMAppVolumesKey_PanPosition), volumeAndPan.pan); + break; + } + } + + return volumeAndPan; +} + +- (BOOL) shouldBeIncludedInMenu:(NSRunningApplication*)app { + // Ignore hidden apps and Background Music itself. + // TODO: Would it be better to only show apps that are registered as HAL clients? + BOOL isHidden = app.activationPolicy != NSApplicationActivationPolicyRegular && + app.activationPolicy != NSApplicationActivationPolicyAccessory; + + NSString* bundleID = app.bundleIdentifier; + BOOL isBGMApp = bundleID && [@kBGMAppBundleID isEqualToString:BGMNN(bundleID)]; + + return !isHidden && !isBGMApp; +} + +- (void) removeMenuItemsForApps:(NSArray*)apps { + NSAssert([NSThread isMainThread], @"removeMenuItemsForApps is not thread safe"); + + for (NSRunningApplication* app in apps) { + [appVolumes removeMenuItemForApp:app]; + } +} + +#pragma mark KVO + +- (void) observeValueForKeyPath:(NSString* __nullable)keyPath + ofObject:(id __nullable)object + change:(NSDictionary* __nullable)change + context:(void* __nullable)context +{ + #pragma unused (object, context) + + // KVO callback for the apps currently running on the system. Adds/removes the associated menu + // items. + if (keyPath && change && [keyPath isEqualToString:@"runningApplications"]) { + NSArray* newApps = change[NSKeyValueChangeNewKey]; + NSArray* oldApps = change[NSKeyValueChangeOldKey]; + + int changeKind = [change[NSKeyValueChangeKindKey] intValue]; + + switch (changeKind) { + case NSKeyValueChangeInsertion: + [self insertMenuItemsForApps:newApps]; + break; + + case NSKeyValueChangeRemoval: + [self removeMenuItemsForApps:oldApps]; + break; + + case NSKeyValueChangeReplacement: + [self removeMenuItemsForApps:oldApps]; + [self insertMenuItemsForApps:newApps]; + break; + + case NSKeyValueChangeSetting: + [appVolumes removeAllAppVolumeMenuItems]; + [self insertMenuItemsForApps:newApps]; + break; + } + } +} + +@end + +#pragma clang assume_nonnull end + diff --git a/BGMApp/BGMApp/BGMAudioDeviceManager.h b/BGMApp/BGMApp/BGMAudioDeviceManager.h index 9033607..d01e47e 100644 --- a/BGMApp/BGMApp/BGMAudioDeviceManager.h +++ b/BGMApp/BGMApp/BGMAudioDeviceManager.h @@ -26,7 +26,7 @@ #if defined(__cplusplus) // Local Includes -#include "BGMBackgroundMusicDevice.h" +#import "BGMBackgroundMusicDevice.h" // PublicUtility Includes #import "CAHALAudioDevice.h" @@ -40,9 +40,9 @@ #pragma clang assume_nonnull begin -const int kBGMErrorCode_BGMDeviceNotFound = 1; -const int kBGMErrorCode_OutputDeviceNotFound = 2; -const int kBGMErrorCode_ReturningEarly = 3; +static const int kBGMErrorCode_BGMDeviceNotFound = 1; +static const int kBGMErrorCode_OutputDeviceNotFound = 2; +static const int kBGMErrorCode_ReturningEarly = 3; @interface BGMAudioDeviceManager : NSObject @@ -62,6 +62,13 @@ const int kBGMErrorCode_ReturningEarly = 3; - (CAHALAudioDevice) outputDevice; #endif +- (void) setVolume:(SInt32)volume +forAppWithProcessID:(pid_t)processID + bundleID:(NSString* __nullable)bundleID; +- (void) setPanPosition:(SInt32)pan + forAppWithProcessID:(pid_t)processID + bundleID:(NSString* __nullable)bundleID; + - (BOOL) isOutputDevice:(AudioObjectID)deviceID; - (BOOL) isOutputDataSource:(UInt32)dataSourceID; diff --git a/BGMApp/BGMApp/BGMAudioDeviceManager.mm b/BGMApp/BGMApp/BGMAudioDeviceManager.mm index 63c5e16..9f9a844 100644 --- a/BGMApp/BGMApp/BGMAudioDeviceManager.mm +++ b/BGMApp/BGMApp/BGMAudioDeviceManager.mm @@ -36,6 +36,8 @@ #include "CAAutoDisposer.h" +#pragma clang assume_nonnull begin + @implementation BGMAudioDeviceManager { BGMBackgroundMusicDevice bgmDevice; BGMAudioDevice outputDevice; @@ -52,7 +54,7 @@ #pragma mark Construction/Destruction -- (instancetype) initWithError:(NSError**)error { +- (instancetype) initWithError:(NSError** __nullable)error { if ((self = [super init])) { stateLock = [NSRecursiveLock new]; bgmXPCHelperConnection = nil; @@ -238,6 +240,18 @@ return outputDevice; } +- (void) setVolume:(SInt32)volume +forAppWithProcessID:(pid_t)processID + bundleID:(NSString* __nullable)bundleID { + bgmDevice.SetAppVolume(volume, processID, (__bridge_retained CFStringRef)bundleID); +} + +- (void) setPanPosition:(SInt32)pan + forAppWithProcessID:(pid_t)processID + bundleID:(NSString* __nullable)bundleID { + bgmDevice.SetAppPanPosition(pan, processID, (__bridge_retained CFStringRef)bundleID); +} + - (BOOL) isOutputDevice:(AudioObjectID)deviceID { @try { [stateLock lock]; @@ -503,3 +517,6 @@ @end +#pragma clang assume_nonnull end + + diff --git a/BGMApp/BGMApp/BGMBackgroundMusicDevice.cpp b/BGMApp/BGMApp/BGMBackgroundMusicDevice.cpp index 76efebc..030e55c 100644 --- a/BGMApp/BGMApp/BGMBackgroundMusicDevice.cpp +++ b/BGMApp/BGMApp/BGMBackgroundMusicDevice.cpp @@ -149,7 +149,7 @@ void BGMBackgroundMusicDevice::SetAppVolume(SInt32 inVolume, void BGMBackgroundMusicDevice::SetAppPanPosition(SInt32 inPanPosition, pid_t inAppProcessID, - CFStringRef inAppBundleID) + CFStringRef __nullable inAppBundleID) { BGMAssert((kAppPanLeftRawValue <= inPanPosition) && (inPanPosition <= kAppPanRightRawValue), "BGMBackgroundMusicDevice::SetAppPanPosition: Pan position out of bounds"); @@ -167,7 +167,7 @@ void BGMBackgroundMusicDevice::SetAppPanPosition(SInt32 inPanPosition, void BGMBackgroundMusicDevice::SendAppVolumeOrPanToBGMDevice(SInt32 inNewValue, CFStringRef inVolumeTypeKey, pid_t inAppProcessID, - CFStringRef inAppBundleID) + CFStringRef __nullable inAppBundleID) { CACFArray appVolumeChanges(true); diff --git a/BGMApp/BGMApp/BGMBackgroundMusicDevice.h b/BGMApp/BGMApp/BGMBackgroundMusicDevice.h index c605dab..c62556d 100644 --- a/BGMApp/BGMApp/BGMBackgroundMusicDevice.h +++ b/BGMApp/BGMApp/BGMBackgroundMusicDevice.h @@ -118,13 +118,13 @@ public: */ void SetAppPanPosition(SInt32 inPanPosition, pid_t inAppProcessID, - CFStringRef inAppBundleID); + CFStringRef __nullable inAppBundleID); private: void SendAppVolumeOrPanToBGMDevice(SInt32 inNewValue, CFStringRef inVolumeTypeKey, pid_t inAppProcessID, - CFStringRef inAppBundleID); + CFStringRef __nullable inAppBundleID); static std::vector ResponsibleBundleIDsOf(CACFString inParentBundleID); diff --git a/BGMApp/BGMApp/Music Players/BGMDecibel.m b/BGMApp/BGMApp/Music Players/BGMDecibel.m index 87ebe44..2993a45 100644 --- a/BGMApp/BGMApp/Music Players/BGMDecibel.m +++ b/BGMApp/BGMApp/Music Players/BGMDecibel.m @@ -31,8 +31,6 @@ #import "BGMScriptingBridge.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" diff --git a/BGMApp/BGMApp/Music Players/BGMHermes.m b/BGMApp/BGMApp/Music Players/BGMHermes.m index bc7af6e..9d6f7c9 100644 --- a/BGMApp/BGMApp/Music Players/BGMHermes.m +++ b/BGMApp/BGMApp/Music Players/BGMHermes.m @@ -30,8 +30,6 @@ #import "BGMScriptingBridge.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" diff --git a/BGMApp/BGMApp/Music Players/BGMMusicPlayer.m b/BGMApp/BGMApp/Music Players/BGMMusicPlayer.m index 8d41abe..fac99a5 100644 --- a/BGMApp/BGMApp/Music Players/BGMMusicPlayer.m +++ b/BGMApp/BGMApp/Music Players/BGMMusicPlayer.m @@ -24,8 +24,6 @@ #import "BGMMusicPlayer.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" diff --git a/BGMApp/BGMApp/Music Players/BGMScriptingBridge.m b/BGMApp/BGMApp/Music Players/BGMScriptingBridge.m index b38a276..8b84153 100644 --- a/BGMApp/BGMApp/Music Players/BGMScriptingBridge.m +++ b/BGMApp/BGMApp/Music Players/BGMScriptingBridge.m @@ -24,8 +24,6 @@ #import "BGMScriptingBridge.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" diff --git a/BGMApp/BGMApp/Music Players/BGMSpotify.m b/BGMApp/BGMApp/Music Players/BGMSpotify.m index bd40600..0642e93 100644 --- a/BGMApp/BGMApp/Music Players/BGMSpotify.m +++ b/BGMApp/BGMApp/Music Players/BGMSpotify.m @@ -33,8 +33,6 @@ #import "BGMScriptingBridge.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" diff --git a/BGMApp/BGMApp/Music Players/BGMVLC.m b/BGMApp/BGMApp/Music Players/BGMVLC.m index d585f83..afa9c66 100644 --- a/BGMApp/BGMApp/Music Players/BGMVLC.m +++ b/BGMApp/BGMApp/Music Players/BGMVLC.m @@ -31,8 +31,6 @@ #import "BGMScriptingBridge.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" diff --git a/BGMApp/BGMApp/Music Players/BGMVOX.m b/BGMApp/BGMApp/Music Players/BGMVOX.m index a812e37..de37fa2 100644 --- a/BGMApp/BGMApp/Music Players/BGMVOX.m +++ b/BGMApp/BGMApp/Music Players/BGMVOX.m @@ -30,8 +30,6 @@ #import "BGMScriptingBridge.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" diff --git a/BGMApp/BGMApp/Music Players/BGMiTunes.m b/BGMApp/BGMApp/Music Players/BGMiTunes.m index ef0141d..c2f91b9 100644 --- a/BGMApp/BGMApp/Music Players/BGMiTunes.m +++ b/BGMApp/BGMApp/Music Players/BGMiTunes.m @@ -30,8 +30,6 @@ #import "BGMScriptingBridge.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" diff --git a/BGMApp/BGMApp/Preferences/BGMAboutPanel.m b/BGMApp/BGMApp/Preferences/BGMAboutPanel.m index 0178cb2..43cbf6a 100644 --- a/BGMApp/BGMApp/Preferences/BGMAboutPanel.m +++ b/BGMApp/BGMApp/Preferences/BGMAboutPanel.m @@ -27,8 +27,6 @@ #import "BGM_Types.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" diff --git a/BGMApp/BGMXPCHelper/BGMXPCListenerDelegate.m b/BGMApp/BGMXPCHelper/BGMXPCListenerDelegate.m index dccf8ff..ffb84c1 100644 --- a/BGMApp/BGMXPCHelper/BGMXPCListenerDelegate.m +++ b/BGMApp/BGMXPCHelper/BGMXPCListenerDelegate.m @@ -27,8 +27,6 @@ #import "BGMXPCHelperService.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" // System Includes diff --git a/BGMApp/BGMXPCHelper/main.m b/BGMApp/BGMXPCHelper/main.m index bf057f9..be79f29 100644 --- a/BGMApp/BGMXPCHelper/main.m +++ b/BGMApp/BGMXPCHelper/main.m @@ -48,8 +48,6 @@ #import "BGMXPCListenerDelegate.h" // PublicUtility Includes -#undef CoreAudio_ThreadStampMessages -#define CoreAudio_ThreadStampMessages 0 // Requires C++ #include "CADebugMacros.h" // System Includes diff --git a/BGMApp/BGMXPCHelperTests/BGMXPCHelperTests.m b/BGMApp/BGMXPCHelperTests/BGMXPCHelperTests.m index 8b160b2..8a25aab 100644 --- a/BGMApp/BGMXPCHelperTests/BGMXPCHelperTests.m +++ b/BGMApp/BGMXPCHelperTests/BGMXPCHelperTests.m @@ -57,7 +57,7 @@ - (void) testStartOutputDeviceWithoutBGMAppConnected { dispatch_semaphore_t replySemaphore = dispatch_semaphore_create(0); - + // Unregister BGMXPCHelper's connection to BGMApp in case BGMApp didn't shutdown cleanly the last time it ran. [[connection remoteObjectProxy] unregisterAsBGMApp]; @@ -68,8 +68,9 @@ dispatch_semaphore_signal(replySemaphore); } forUISoundsDevice:NO]; - - if (0 != dispatch_semaphore_wait(replySemaphore, dispatch_time(DISPATCH_TIME_NOW, kStartIOTimeoutNsec))) { + + // Very long timeout to make it less likely to fail on Travis CI when there's high contention. + if (0 != dispatch_semaphore_wait(replySemaphore, dispatch_time(DISPATCH_TIME_NOW, 5 * 60 * NSEC_PER_SEC))) { XCTFail(@"Timed out waiting for BGMXPCHelper"); } } diff --git a/BGMApp/PublicUtility/CADebugger.h b/BGMApp/PublicUtility/CADebugger.h index 9391f01..c53392a 100644 --- a/BGMApp/PublicUtility/CADebugger.h +++ b/BGMApp/PublicUtility/CADebugger.h @@ -61,9 +61,18 @@ // CADebugger //============================================================================= +// BGM edit: Added extern "C" so CADebugger (and headers that include it) can be used in Obj-C. +#ifdef __cplusplus +extern "C" { +#endif + #if TARGET_API_MAC_OSX extern bool CAIsDebuggerAttached(void); #endif -extern void CADebuggerStop(void); +extern void CADebuggerStop(void); + +#ifdef __cplusplus +} +#endif #endif diff --git a/BGMDriver/PublicUtility/CADebugMacros.cpp b/BGMDriver/PublicUtility/CADebugMacros.cpp index 94eeb39..70a7d9d 100644 --- a/BGMDriver/PublicUtility/CADebugMacros.cpp +++ b/BGMDriver/PublicUtility/CADebugMacros.cpp @@ -68,7 +68,7 @@ void LogError(const char *fmt, ...) va_list args; va_start(args, fmt); // BGM edit: vprintf leaves args in an undefined state, which can cause a crash in - // vsyslog. Also added CADebuggerStop(). Original code commented out below. + // vsyslog. Also added __ASSERT_STOP. Original code commented out below. //#if DEBUG // vprintf(fmt, args); //#endif @@ -83,7 +83,7 @@ void LogError(const char *fmt, ...) vsyslog(LOG_ERR, fmt, args); #endif #if DEBUG - CADebuggerStop(); + __ASSERT_STOP; #endif // BGM edit end va_end(args); @@ -94,7 +94,7 @@ void LogWarning(const char *fmt, ...) va_list args; va_start(args, fmt); // BGM edit: vprintf leaves args in an undefined state, which can cause a crash in - // vsyslog. Also added CADebuggerStop(). Original code commented out below. + // vsyslog. Also added __ASSERT_STOP. Original code commented out below. //#if DEBUG // vprintf(fmt, args); //#endif @@ -109,7 +109,7 @@ void LogWarning(const char *fmt, ...) vsyslog(LOG_WARNING, fmt, args); #endif #if DEBUG - //CADebuggerStop(); // TODO: Add a toggle for this to the project file (under "Preprocessor Macros"). Default to off. + //__ASSERT_STOP; // TODO: Add a toggle for this to the project file (under "Preprocessor Macros"). Default to off. #endif // BGM edit end va_end(args); diff --git a/SharedSource/BGM_Utils.h b/SharedSource/BGM_Utils.h index 3fef789..bcabe97 100644 --- a/SharedSource/BGM_Utils.h +++ b/SharedSource/BGM_Utils.h @@ -131,7 +131,7 @@ #pragma mark C Utility Functions -dispatch_queue_t BGMGetDispatchQueue_PriorityUserInteractive(); +dispatch_queue_t BGMGetDispatchQueue_PriorityUserInteractive(void); #if defined(__cplusplus)