The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .editorconfig
├── .github
    ├── ISSUE_TEMPLATE
    │   ├── bug_report.md
    │   └── other.md
    └── workflows
    │   └── build-test-release.yml
├── .gitignore
├── BGM.xcworkspace
    └── contents.xcworkspacedata
├── BGMApp
    ├── BGMApp.xcodeproj
    │   ├── project.pbxproj
    │   └── xcshareddata
    │   │   └── xcschemes
    │   │       ├── BGMXPCHelper.xcscheme
    │   │       └── Background Music.xcscheme
    ├── BGMApp
    │   ├── BGMApp-Debug.entitlements
    │   ├── BGMApp.entitlements
    │   ├── BGMAppDelegate.h
    │   ├── BGMAppDelegate.mm
    │   ├── BGMAppVolumes.h
    │   ├── BGMAppVolumes.m
    │   ├── BGMAppVolumesController.h
    │   ├── BGMAppVolumesController.mm
    │   ├── BGMAppWatcher.h
    │   ├── BGMAppWatcher.m
    │   ├── BGMAudioDevice.cpp
    │   ├── BGMAudioDevice.h
    │   ├── BGMAudioDeviceManager.h
    │   ├── BGMAudioDeviceManager.mm
    │   ├── BGMAutoPauseMenuItem.h
    │   ├── BGMAutoPauseMenuItem.m
    │   ├── BGMAutoPauseMusic.h
    │   ├── BGMAutoPauseMusic.mm
    │   ├── BGMBackgroundMusicDevice.cpp
    │   ├── BGMBackgroundMusicDevice.h
    │   ├── BGMDebugLoggingMenuItem.h
    │   ├── BGMDebugLoggingMenuItem.m
    │   ├── BGMDeviceControlSync.cpp
    │   ├── BGMDeviceControlSync.h
    │   ├── BGMDeviceControlsList.cpp
    │   ├── BGMDeviceControlsList.h
    │   ├── BGMOutputDeviceMenuSection.h
    │   ├── BGMOutputDeviceMenuSection.mm
    │   ├── BGMOutputVolumeMenuItem.h
    │   ├── BGMOutputVolumeMenuItem.mm
    │   ├── BGMPlayThrough.cpp
    │   ├── BGMPlayThrough.h
    │   ├── BGMPlayThroughRTLogger.cpp
    │   ├── BGMPlayThroughRTLogger.h
    │   ├── BGMPreferredOutputDevices.h
    │   ├── BGMPreferredOutputDevices.mm
    │   ├── BGMStatusBarItem.h
    │   ├── BGMStatusBarItem.mm
    │   ├── BGMSystemSoundsVolume.h
    │   ├── BGMSystemSoundsVolume.mm
    │   ├── BGMTermination.h
    │   ├── BGMTermination.mm
    │   ├── BGMUserDefaults.h
    │   ├── BGMUserDefaults.m
    │   ├── BGMVolumeChangeListener.cpp
    │   ├── BGMVolumeChangeListener.h
    │   ├── BGMXPCListener.h
    │   ├── BGMXPCListener.mm
    │   ├── Base.lproj
    │   │   └── MainMenu.xib
    │   ├── Images.xcassets
    │   │   ├── AirPlayIcon.imageset
    │   │   │   ├── AirPlay.pdf
    │   │   │   └── Contents.json
    │   │   ├── AppIcon.appiconset
    │   │   │   ├── Contents.json
    │   │   │   ├── appicon_1024.png
    │   │   │   ├── appicon_128.png
    │   │   │   ├── appicon_16.png
    │   │   │   ├── appicon_256.png
    │   │   │   ├── appicon_32.png
    │   │   │   ├── appicon_512.png
    │   │   │   └── appicon_64.png
    │   │   ├── Contents.json
    │   │   ├── FermataIcon.imageset
    │   │   │   ├── Contents.json
    │   │   │   └── FermataIcon.pdf
    │   │   ├── Volume0.imageset
    │   │   │   ├── Contents.json
    │   │   │   └── Volume0.pdf
    │   │   ├── Volume1.imageset
    │   │   │   ├── Contents.json
    │   │   │   └── Volume1.pdf
    │   │   ├── Volume2.imageset
    │   │   │   ├── Contents.json
    │   │   │   └── Volume2.pdf
    │   │   └── Volume3.imageset
    │   │   │   ├── Contents.json
    │   │   │   └── Volume3.pdf
    │   ├── Info.plist
    │   ├── LICENSE
    │   ├── Music Players
    │   │   ├── BGMDecibel.h
    │   │   ├── BGMDecibel.m
    │   │   ├── BGMGooglePlayMusicDesktopPlayer.h
    │   │   ├── BGMGooglePlayMusicDesktopPlayer.m
    │   │   ├── BGMGooglePlayMusicDesktopPlayerConnection.h
    │   │   ├── BGMGooglePlayMusicDesktopPlayerConnection.m
    │   │   ├── BGMHermes.h
    │   │   ├── BGMHermes.m
    │   │   ├── BGMMusic.h
    │   │   ├── BGMMusic.m
    │   │   ├── BGMMusicPlayer.h
    │   │   ├── BGMMusicPlayer.m
    │   │   ├── BGMMusicPlayers.h
    │   │   ├── BGMMusicPlayers.mm
    │   │   ├── BGMScriptingBridge.h
    │   │   ├── BGMScriptingBridge.m
    │   │   ├── BGMSpotify.h
    │   │   ├── BGMSpotify.m
    │   │   ├── BGMSwinsian.h
    │   │   ├── BGMSwinsian.m
    │   │   ├── BGMVLC.h
    │   │   ├── BGMVLC.m
    │   │   ├── BGMVOX.h
    │   │   ├── BGMVOX.m
    │   │   ├── BGMiTunes.h
    │   │   ├── BGMiTunes.m
    │   │   ├── Decibel.h
    │   │   ├── GooglePlayMusicDesktopPlayer.js
    │   │   ├── Hermes.h
    │   │   ├── Music.h
    │   │   ├── Spotify.h
    │   │   ├── Swinsian.h
    │   │   ├── VLC.h
    │   │   ├── VOX.h
    │   │   └── iTunes.h
    │   ├── Preferences
    │   │   ├── BGMAboutPanel.h
    │   │   ├── BGMAboutPanel.m
    │   │   ├── BGMAutoPauseMusicPrefs.h
    │   │   ├── BGMAutoPauseMusicPrefs.mm
    │   │   ├── BGMPreferencesMenu.h
    │   │   └── BGMPreferencesMenu.mm
    │   ├── Scripting
    │   │   ├── BGMASApplication.h
    │   │   ├── BGMASApplication.m
    │   │   ├── BGMASOutputDevice.h
    │   │   ├── BGMASOutputDevice.mm
    │   │   ├── BGMApp.sdef
    │   │   ├── BGMAppDelegate+AppleScript.h
    │   │   └── BGMAppDelegate+AppleScript.mm
    │   ├── SystemPreferences.h
    │   ├── _uninstall-non-interactive.sh
    │   └── main.m
    ├── BGMAppTests
    │   ├── UITests
    │   │   ├── BGMApp.h
    │   │   ├── BGMAppUITests-Info.plist
    │   │   ├── BGMAppUITests.mm
    │   │   └── skip-ui-tests.py
    │   └── UnitTests
    │   │   ├── BGMAppUnitTests-Info.plist
    │   │   ├── BGMMusicPlayersUnitTests.mm
    │   │   ├── BGMPlayThroughRTLoggerTests.mm
    │   │   ├── BGMPlayThroughTests.mm
    │   │   └── Mocks
    │   │       ├── MockAudioDevice.cpp
    │   │       ├── MockAudioDevice.h
    │   │       ├── MockAudioObject.cpp
    │   │       ├── MockAudioObject.h
    │   │       ├── MockAudioObjects.cpp
    │   │       ├── MockAudioObjects.h
    │   │       ├── Mock_CAHALAudioDevice.cpp
    │   │       ├── Mock_CAHALAudioObject.cpp
    │   │       └── Mock_CAHALAudioSystemObject.cpp
    ├── BGMThreadSafetyAnalysis.h
    ├── BGMXPCHelper
    │   ├── BGMXPCHelperService.h
    │   ├── BGMXPCHelperService.mm
    │   ├── BGMXPCListenerDelegate.h
    │   ├── BGMXPCListenerDelegate.m
    │   ├── Info.plist
    │   ├── com.bearisdriving.BGM.XPCHelper.plist.template
    │   ├── main.m
    │   ├── post_install.sh
    │   └── safe_install_dir.sh
    ├── BGMXPCHelperTests
    │   ├── BGMXPCHelperTests-Info.plist
    │   └── BGMXPCHelperTests.m
    ├── OptimizationProfiles
    │   └── BGMApp.profdata
    └── PublicUtility
    │   ├── BGMDebugLogging.c
    │   ├── BGMDebugLogging.h
    │   ├── CAAtomic.h
    │   ├── CAAutoDisposer.h
    │   ├── CABitOperations.h
    │   ├── CACFArray.cpp
    │   ├── CACFArray.h
    │   ├── CACFDictionary.cpp
    │   ├── CACFDictionary.h
    │   ├── CACFNumber.cpp
    │   ├── CACFNumber.h
    │   ├── CACFString.cpp
    │   ├── CACFString.h
    │   ├── CADebugMacros.cpp
    │   ├── CADebugMacros.h
    │   ├── CADebugPrintf.cpp
    │   ├── CADebugPrintf.h
    │   ├── CADebugger.cpp
    │   ├── CADebugger.h
    │   ├── CAException.h
    │   ├── CAHALAudioDevice.cpp
    │   ├── CAHALAudioDevice.h
    │   ├── CAHALAudioObject.cpp
    │   ├── CAHALAudioObject.h
    │   ├── CAHALAudioStream.cpp
    │   ├── CAHALAudioStream.h
    │   ├── CAHALAudioSystemObject.cpp
    │   ├── CAHALAudioSystemObject.h
    │   ├── CAHostTimeBase.cpp
    │   ├── CAHostTimeBase.h
    │   ├── CAMutex.cpp
    │   ├── CAMutex.h
    │   ├── CAPThread.cpp
    │   ├── CAPThread.h
    │   ├── CAPropertyAddress.h
    │   ├── CARingBuffer.cpp
    │   └── CARingBuffer.h
├── BGMDriver
    ├── BGMDriver.xcodeproj
    │   ├── project.pbxproj
    │   └── xcshareddata
    │   │   └── xcschemes
    │   │       ├── Background Music Device.xcscheme
    │   │       └── PublicUtility.xcscheme
    ├── BGMDriver
    │   ├── BGM_AbstractDevice.cpp
    │   ├── BGM_AbstractDevice.h
    │   ├── BGM_AudibleState.cpp
    │   ├── BGM_AudibleState.h
    │   ├── BGM_Control.cpp
    │   ├── BGM_Control.h
    │   ├── BGM_Device.cpp
    │   ├── BGM_Device.h
    │   ├── BGM_MuteControl.cpp
    │   ├── BGM_MuteControl.h
    │   ├── BGM_NullDevice.cpp
    │   ├── BGM_NullDevice.h
    │   ├── BGM_Object.cpp
    │   ├── BGM_Object.h
    │   ├── BGM_PlugIn.cpp
    │   ├── BGM_PlugIn.h
    │   ├── BGM_PlugInInterface.cpp
    │   ├── BGM_Stream.cpp
    │   ├── BGM_Stream.h
    │   ├── BGM_TaskQueue.cpp
    │   ├── BGM_TaskQueue.h
    │   ├── BGM_VolumeControl.cpp
    │   ├── BGM_VolumeControl.h
    │   ├── BGM_WrappedAudioEngine.cpp
    │   ├── BGM_WrappedAudioEngine.h
    │   ├── BGM_XPCHelper.h
    │   ├── BGM_XPCHelper.m
    │   ├── DeviceClients
    │   │   ├── BGM_Client.cpp
    │   │   ├── BGM_Client.h
    │   │   ├── BGM_ClientMap.cpp
    │   │   ├── BGM_ClientMap.h
    │   │   ├── BGM_ClientTasks.h
    │   │   ├── BGM_Clients.cpp
    │   │   └── BGM_Clients.h
    │   ├── DeviceIcon.icns
    │   ├── Info.plist
    │   └── quick_install.sh
    ├── BGMDriverTests
    │   ├── BGM_ClientMapTests.mm
    │   ├── BGM_ClientsTests.mm
    │   ├── BGM_DeviceTests.mm
    │   └── Info.plist
    └── PublicUtility
    │   ├── CAAtomic.h
    │   ├── CAAtomicStack.h
    │   ├── CAAutoDisposer.h
    │   ├── CABitOperations.h
    │   ├── CACFArray.cpp
    │   ├── CACFArray.h
    │   ├── CACFDictionary.cpp
    │   ├── CACFDictionary.h
    │   ├── CACFNumber.cpp
    │   ├── CACFNumber.h
    │   ├── CACFString.cpp
    │   ├── CACFString.h
    │   ├── CADebugMacros.cpp
    │   ├── CADebugMacros.h
    │   ├── CADebugPrintf.cpp
    │   ├── CADebugPrintf.h
    │   ├── CADebugger.cpp
    │   ├── CADebugger.h
    │   ├── CADispatchQueue.cpp
    │   ├── CADispatchQueue.h
    │   ├── CAException.h
    │   ├── CAHostTimeBase.cpp
    │   ├── CAHostTimeBase.h
    │   ├── CAMutex.cpp
    │   ├── CAMutex.h
    │   ├── CAPThread.cpp
    │   ├── CAPThread.h
    │   ├── CAPropertyAddress.h
    │   ├── CARingBuffer.cpp
    │   ├── CARingBuffer.h
    │   ├── CAVolumeCurve.cpp
    │   └── CAVolumeCurve.h
├── CONTRIBUTING.md
├── DEVELOPING.md
├── Images
    ├── FermataIcon.pdf
    ├── FermataIcon.tex
    ├── README
    │   ├── FermataIcon.png
    │   ├── Screenshot.png
    │   └── pkg-icon.png
    ├── VolumeIcons.tex
    ├── generate_icon_pngs.sh
    └── iconizer.sh
├── LICENSE
├── LICENSE-Apple-Sample-Code
├── MANUAL-INSTALL.md
├── MANUAL-UNINSTALL.md
├── README.md
├── SharedSource
    ├── BGMXPCProtocols.h
    ├── BGM_TestUtils.h
    ├── BGM_Types.h
    ├── BGM_Utils.cpp
    ├── BGM_Utils.h
    └── Scripts
    │   └── set-version.sh
├── TODO.md
├── build_and_install.sh
├── package.sh
├── pkg
    ├── Distribution.xml.template
    ├── ListInputDevices.swift
    ├── README.md
    ├── pkgbuild.plist
    ├── postinstall
    └── preinstall
└── uninstall.sh


/.editorconfig:
--------------------------------------------------------------------------------
 1 | # This file was added to get GitHub to display our source code correctly when
 2 | # it has mixed tabs and spaces. (I didn't realise the sample code BGMDriver is
 3 | # based on used tabs and it's too late to fix it now.)
 4 | #
 5 | # See http://editorconfig.org.
 6 | 
 7 | # This is the top-most .editorconfig file.
 8 | root = true
 9 | 
10 | # Set tabs to the width of 4 spaces in C, C++, Objective-C and Objective-C++
11 | # source files.
12 | [*.{h,c,cpp,m,mm}]
13 | tab_width = 4
14 | 
15 | 
16 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: Bug report
 3 | about: Create a report to help us improve
 4 | title: ''
 5 | labels: bug
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | ## Example bug report template
11 | 
12 | > Don't worry if you have trouble getting some of this info. Just leave it out.
13 | 
14 | **Description of the bug**
15 | > Please don't just say it's "not working".
16 | 
17 | **Steps to reproduce**
18 | > Steps to reproduce the bug. This usually doesn't need to be super detailed.
19 | 1. Go to '...'
20 | 2. Click on '...'
21 | 3. See error message '...'
22 | 
23 | **Versions**
24 | > Please complete the following information.
25 |  - Background Music: [e.g. "0.4.3" or "0.4.0-SNAPSHOT-c0ab98b". `Preferences > About Background Music`]
26 |  - macOS: [e.g. "11.3 Beta (20E5172i)" or "Big Sur". ` > About This Mac`]
27 | 
28 | **Hardware**
29 | > Delete this part if you think it's probably not necessary.
30 |  - Computer: [e.g. "MacBook Pro (13-inch, 2016, Four Thunderbolt 3 Ports)". ` > About This Mac`]
31 |  - Audio Device: [e.g. "Built-in Output. Manufacturer: Apple Inc. Output Channels: 2 [...]". `System Information app > Hardware > Audio`]
32 | 
33 | **Debug logs**
34 | > If you think the developers might not be able to reproduce the bug on their computers, e.g. because an important feature is completely broken and they would have noticed, it can help to include [debug logs](https://github.com/kyleneideck/BackgroundMusic/wiki/Getting-Debug-Logs). This takes a little effort, so feel free to leave it out at first.
35 | 
36 | [Debug logs attached here](https://github.com/example/background-music-debug-logs.txt)
37 | 
38 | **Other info**
39 | > Anything else you want to add?
40 | 
41 | ---
42 | 
43 | > Tips
44 | > (Delete this section before posting.)
45 | >  - https://github.com/kyleneideck/BackgroundMusic#troubleshooting
46 | >  - Try the latest SNAPSHOT version from https://github.com/kyleneideck/BackgroundMusic/releases (if it's newer than the latest non-SNAPSHOT release).
47 | >  - If your bug is one of these common issues, consider leaving a comment or a +1 (👍) on an existing issue:
48 | >     - Background Music currently only supports audio devices with two channels. Bluetooth devices often only have one.
49 | >     - Volumes having no effect for certain apps: Microsoft Teams ([workaround](https://github.com/kyleneideck/BackgroundMusic/issues/268#issuecomment-604977210)), Zoom ([workaround](https://github.com/kyleneideck/BackgroundMusic/issues/396#issuecomment-741992157)), Discord ([workaround](https://github.com/kyleneideck/BackgroundMusic/issues/210#issuecomment-507048957), [see also](https://github.com/kyleneideck/BackgroundMusic/issues/267#issuecomment-617327850)), Chrome (sometimes)
50 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/other.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: Other
 3 | about: Feature request, question, support request or anything else
 4 | title: ''
 5 | labels: ''
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | > There's no template for this issue type. I just wanted to make it clear that it's OK to submit other types of issues.
11 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | .DS_Store
 2 | .*.swp
 3 | /BGMDriver/BGMDriver/quick_install.conf
 4 | /build_and_install.log
 5 | .idea/
 6 | tags
 7 | cmake-build-debug/
 8 | /Background-Music-*/
 9 | BGM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
10 | Images/*.aux
11 | Images/*.log
12 | /archives/
13 | 
14 | # Everything below is from https://github.com/github/gitignore/blob/master/Objective-C.gitignore
15 | 
16 | ## Build generated
17 | build/
18 | DerivedData
19 | 
20 | ## Various settings
21 | *.pbxuser
22 | !default.pbxuser
23 | *.mode1v3
24 | !default.mode1v3
25 | *.mode2v3
26 | !default.mode2v3
27 | *.perspectivev3
28 | !default.perspectivev3
29 | xcuserdata
30 | 
31 | ## Other
32 | *.xccheckout
33 | *.moved-aside
34 | *.xcuserstate
35 | *.xcscmblueprint
36 | 
37 | ## Obj-C/Swift specific
38 | *.hmap
39 | *.ipa
40 | 


--------------------------------------------------------------------------------
/BGM.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <Workspace
 3 |    version = "1.0">
 4 |    <FileRef
 5 |       location = "group:BGMDriver/BGMDriver.xcodeproj">
 6 |    </FileRef>
 7 |    <FileRef
 8 |       location = "group:BGMApp/BGMApp.xcodeproj">
 9 |    </FileRef>
10 |    <FileRef
11 |       location = "group:README.md">
12 |    </FileRef>
13 |    <FileRef
14 |       location = "group:MANUAL-INSTALL.md">
15 |    </FileRef>
16 |    <FileRef
17 |       location = "group:MANUAL-UNINSTALL.md">
18 |    </FileRef>
19 |    <FileRef
20 |       location = "group:TODO.md">
21 |    </FileRef>
22 |    <FileRef
23 |       location = "group:DEVELOPING.md">
24 |    </FileRef>
25 |    <FileRef
26 |       location = "group:CONTRIBUTING.md">
27 |    </FileRef>
28 |    <FileRef
29 |       location = "group:LICENSE">
30 |    </FileRef>
31 |    <FileRef
32 |       location = "group:LICENSE-Apple-Sample-Code">
33 |    </FileRef>
34 |    <FileRef
35 |       location = "group:build_and_install.sh">
36 |    </FileRef>
37 |    <FileRef
38 |       location = "group:uninstall.sh">
39 |    </FileRef>
40 |    <FileRef
41 |       location = "group:package.sh">
42 |    </FileRef>
43 |    <FileRef
44 |       location = "group:pkg">
45 |    </FileRef>
46 |    <FileRef
47 |       location = "group:Images">
48 |    </FileRef>
49 | </Workspace>
50 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMApp-Debug.entitlements:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>com.apple.security.automation.apple-events</key>
 6 | 	<true/>
 7 | 	<key>com.apple.security.device.audio-input</key>
 8 | 	<true/>
 9 |     <!--
10 |     Without this key, AddressSanitizer and the UI tests would only work when BGMApp is code signed.
11 |     -->
12 | 	<key>com.apple.security.cs.disable-library-validation</key>
13 | 	<true/>
14 | </dict>
15 | </plist>
16 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMApp.entitlements:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>com.apple.security.automation.apple-events</key>
 6 | 	<true/>
 7 | 	<key>com.apple.security.device.audio-input</key>
 8 | 	<true/>
 9 | </dict>
10 | </plist>
11 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMAppDelegate.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMAppDelegate.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016, 2017, 2020 Kyle Neideck
21 | //  Copyright © 2021 Marcus Wu
22 | //
23 | //  Sets up and tears down the app.
24 | //
25 | 
26 | // System Includes
27 | #import <Cocoa/Cocoa.h>
28 | 
29 | @class BGMAudioDeviceManager;
30 | @class BGMAppVolumesController;
31 | 
32 | // Tags for UI elements in MainMenu.xib
33 | static NSInteger const kVolumesHeadingMenuItemTag = 3;
34 | static NSInteger const kSeparatorBelowVolumesMenuItemTag = 4;
35 | 
36 | @interface BGMAppDelegate : NSObject <NSApplicationDelegate, NSMenuDelegate>
37 | 
38 | @property (weak) IBOutlet NSMenu* bgmMenu;
39 | 
40 | @property (weak) IBOutlet NSView* outputVolumeView;
41 | @property (weak) IBOutlet NSTextField* outputVolumeLabel;
42 | @property (weak) IBOutlet NSSlider* outputVolumeSlider;
43 | 
44 | @property (weak) IBOutlet NSView* systemSoundsView;
45 | @property (weak) IBOutlet NSSlider* systemSoundsSlider;
46 | 
47 | @property (weak) IBOutlet NSView* appVolumeView;
48 | 
49 | @property (weak) IBOutlet NSPanel* aboutPanel;
50 | @property (unsafe_unretained) IBOutlet NSTextView* aboutPanelLicenseView;
51 | 
52 | @property (weak) IBOutlet NSMenuItem* autoPauseMenuItemUnwrapped;
53 | @property (weak) IBOutlet NSMenuItem* debugLoggingMenuItemUnwrapped;
54 | 
55 | @property (readonly) BGMAudioDeviceManager* audioDevices;
56 | @property BGMAppVolumesController* appVolumes;
57 | 
58 | @end
59 | 
60 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMAppVolumes.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMAppVolumes.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016, 2017 Kyle Neideck
21 | //  Copyright © 2021 Marcus Wu
22 | //
23 | 
24 | // Local Includes
25 | #import "BGMAppVolumesController.h"
26 | 
27 | // System Includes
28 | #import <Cocoa/Cocoa.h>
29 | 
30 | 
31 | #pragma clang assume_nonnull begin
32 | 
33 | @interface BGMAppVolumes : NSObject
34 | 
35 | - (id) initWithController:(BGMAppVolumesController*)inController
36 |                   bgmMenu:(NSMenu*)inMenu
37 |             appVolumeView:(NSView*)inView;
38 | 
39 | // Pass -1 for initialVolume or kAppPanNoValue for initialPan to leave the volume/pan at its default level.
40 | - (void) insertMenuItemForApp:(NSRunningApplication*)app
41 |                 initialVolume:(int)volume
42 |                    initialPan:(int)pan;
43 | 
44 | - (void) removeMenuItemForApp:(NSRunningApplication*)app;
45 | 
46 | - (void) removeAllAppVolumeMenuItems;
47 | 
48 | - (BGMAppVolumeAndPan) getVolumeAndPanForApp:(NSRunningApplication*)app;
49 | - (void) setVolumeAndPan:(BGMAppVolumeAndPan)volumeAndPan forApp:(NSRunningApplication*)app;
50 | 
51 | @end
52 | 
53 | // Protocol for the UI custom classes
54 | 
55 | @protocol BGMAppVolumeMenuItemSubview <NSObject>
56 | 
57 | - (void) setUpWithApp:(NSRunningApplication*)app
58 |               context:(BGMAppVolumes*)ctx
59 |            controller:(BGMAppVolumesController*)ctrl
60 |              menuItem:(NSMenuItem*)item;
61 | 
62 | @end
63 | 
64 | // Custom classes for the UI elements in the app volume menu items
65 | 
66 | @interface BGMAVM_AppIcon : NSImageView <BGMAppVolumeMenuItemSubview>
67 | @end
68 | 
69 | @interface BGMAVM_AppNameLabel : NSTextField <BGMAppVolumeMenuItemSubview>
70 | @end
71 | 
72 | @interface BGMAVM_ShowMoreControlsButton : NSButton <BGMAppVolumeMenuItemSubview>
73 | @end
74 | 
75 | @interface BGMAVM_VolumeSlider : NSSlider <BGMAppVolumeMenuItemSubview>
76 | 
77 | - (void) setRelativeVolume:(int)relativeVolume;
78 | 
79 | @end
80 | 
81 | @interface BGMAVM_PanSlider : NSSlider <BGMAppVolumeMenuItemSubview>
82 | 
83 | - (void) setPanPosition:(int)panPosition;
84 | 
85 | @end
86 | 
87 | #pragma clang assume_nonnull end
88 | 
89 | 
90 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMAppVolumesController.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMAppVolumesController.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2017 Kyle Neideck
21 | //  Copyright © 2021 Marcus Wu
22 | //
23 | 
24 | // Local Includes
25 | #import "BGMAudioDeviceManager.h"
26 | 
27 | // System Includes
28 | #import <Cocoa/Cocoa.h>
29 | 
30 | 
31 | #pragma clang assume_nonnull begin
32 | 
33 | typedef struct BGMAppVolumeAndPan {
34 |     int volume;
35 |     int pan;
36 | } BGMAppVolumeAndPan;
37 | 
38 | @interface BGMAppVolumesController : NSObject
39 | 
40 | - (id) initWithMenu:(NSMenu*)menu
41 |       appVolumeView:(NSView*)view
42 |        audioDevices:(BGMAudioDeviceManager*)audioDevices;
43 | 
44 | // See BGMBackgroundMusicDevice::SetAppVolume.
45 | - (void)  setVolume:(SInt32)volume
46 | forAppWithProcessID:(pid_t)processID
47 |            bundleID:(NSString* __nullable)bundleID;
48 | 
49 | // See BGMBackgroundMusicDevice::SetPanVolume.
50 | - (void) setPanPosition:(SInt32)pan
51 |     forAppWithProcessID:(pid_t)processID
52 |                bundleID:(NSString* __nullable)bundleID;
53 | 
54 | - (BGMAppVolumeAndPan) getVolumeAndPanForApp:(NSRunningApplication *)app;
55 | - (void) setVolumeAndPan:(BGMAppVolumeAndPan)volumeAndPan forApp:(NSRunningApplication*)app;
56 | 
57 | @end
58 | 
59 | #pragma clang assume_nonnull end
60 | 
61 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMAppWatcher.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMAppWatcher.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2019 Kyle Neideck
21 | //
22 | //  Calls callback functions when a given application is launched or terminated. Starts watching
23 | //  after being initialised, stops after being destroyed.
24 | //
25 | 
26 | // System Includes
27 | #import <Foundation/Foundation.h>
28 | 
29 | 
30 | #pragma clang assume_nonnull begin
31 | 
32 | @interface BGMAppWatcher : NSObject
33 | 
34 | // appLaunched will be called when the application is launched and appTerminated will be called when
35 | // it's terminated. Background apps, status bar apps, etc. are ignored.
36 | - (instancetype) initWithBundleID:(NSString*)bundleID
37 |                       appLaunched:(void(^)(void))appLaunched
38 |                     appTerminated:(void(^)(void))appTerminated;
39 | 
40 | // With this constructor, when an application is launched or terminated, isMatchingBundleID will be
41 | // called first to decide whether or not the callback should be called.
42 | - (instancetype) initWithAppLaunched:(void(^)(void))appLaunched
43 |                        appTerminated:(void(^)(void))appTerminated
44 |                   isMatchingBundleID:(BOOL(^)(NSString* appBundleID))isMatchingBundleID;
45 | 
46 | @end
47 | 
48 | #pragma clang assume_nonnull end
49 | 
50 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMAutoPauseMenuItem.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMAutoPauseMenuItem.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Local Includes
24 | #import "BGMAutoPauseMusic.h"
25 | #import "BGMMusicPlayers.h"
26 | #import "BGMUserDefaults.h"
27 | 
28 | // System Includes
29 | #import <Cocoa/Cocoa.h>
30 | 
31 | 
32 | #pragma clang assume_nonnull begin
33 | 
34 | @interface BGMAutoPauseMenuItem : NSObject
35 | 
36 | - (instancetype) initWithMenuItem:(NSMenuItem*)item
37 |                    autoPauseMusic:(BGMAutoPauseMusic*)autoPause
38 |                      musicPlayers:(BGMMusicPlayers*)players
39 |                      userDefaults:(BGMUserDefaults*)defaults;
40 | 
41 | // Handle events passed along by the delegate (NSMenuDelegate) of the menu containing this menu item.
42 | - (void) parentMenuNeedsUpdate;
43 | - (void) parentMenuItemWillHighlight:(NSMenuItem* __nullable)item;
44 | 
45 | @end
46 | 
47 | #pragma clang assume_nonnull end
48 | 
49 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMAutoPauseMusic.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMAutoPauseMusic.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | //  When enabled, BGMAutoPauseMusic listens for notifications from BGMDevice to tell when music is playing and
23 | //  pauses the music player if other audio starts.
24 | //
25 | 
26 | // Local Includes
27 | #import "BGMAudioDeviceManager.h"
28 | #import "BGMMusicPlayers.h"
29 | #import "BGMUserDefaults.h"
30 | 
31 | // System Includes
32 | #import <Foundation/Foundation.h>
33 | 
34 | 
35 | #pragma clang assume_nonnull begin
36 | 
37 | @interface BGMAutoPauseMusic : NSObject
38 | 
39 | - (id) initWithAudioDevices:(BGMAudioDeviceManager*)inAudioDevices musicPlayers:(BGMMusicPlayers*)inMusicPlayers userDefaults:(BGMUserDefaults*)inUserDefaults;
40 | 
41 | - (void) enable;
42 | - (void) disable;
43 | 
44 | @end
45 | 
46 | #pragma clang assume_nonnull end
47 | 
48 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMDebugLoggingMenuItem.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMDebugLoggingMenuItem.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2020 Kyle Neideck
21 | //
22 | //  A menu item in the main menu that enables/disables debug logging. Only visible if you hold the
23 | //  option down when you click the status bar icon to reveal the main menu.
24 | //
25 | //  TODO: It would be better to have this menu item in the Preferences menu (maybe in an Advanced
26 | //        section) and always visible, but first we'd need to add something that tells the user how
27 | //        to view the log messages. Or better yet, something that automatically opens them.
28 | //
29 | 
30 | // System Includes
31 | #import <Cocoa/Cocoa.h>
32 | 
33 | 
34 | #pragma clang assume_nonnull begin
35 | 
36 | @interface BGMDebugLoggingMenuItem : NSObject
37 | 
38 | - (instancetype) initWithMenuItem:(NSMenuItem*)menuItem;
39 | 
40 | // True if the main menu is showing hidden items/options because the user held the option key when
41 | // they clicked the icon. This class makes the debug logging menu item visible if this property has
42 | // been set true or if debug logging is enabled.
43 | @property (nonatomic) BOOL menuShowingExtraOptions;
44 | 
45 | @end
46 | 
47 | #pragma clang assume_nonnull end
48 | 
49 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMDebugLoggingMenuItem.m:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMDebugLoggingMenuItem.m
18 | //  BGMApp
19 | //
20 | //  Copyright © 2020 Kyle Neideck
21 | //
22 | 
23 | // Self Include
24 | #import "BGMDebugLoggingMenuItem.h"
25 | 
26 | // PublicUtility Includes
27 | #import "BGMDebugLogging.h"
28 | #import "CADebugMacros.h"
29 | 
30 | 
31 | #pragma clang assume_nonnull begin
32 | 
33 | @implementation BGMDebugLoggingMenuItem {
34 |     NSMenuItem* _menuItem;
35 |     BOOL _menuShowingExtraOptions;
36 | }
37 | 
38 | - (instancetype) initWithMenuItem:(NSMenuItem*)menuItem {
39 |     if ((self = [super init])) {
40 |         _menuItem = menuItem;
41 |         _menuItem.state =
42 |                 BGMDebugLoggingIsEnabled() ? NSControlStateValueOn : NSControlStateValueOff;
43 | 
44 |         [self setMenuShowingExtraOptions:NO];
45 | 
46 |         // Enable/disable debug logging when the menu item is clicked.
47 |         menuItem.target = self;
48 |         menuItem.action = @selector(toggleDebugLogging);
49 |     }
50 | 
51 |     return self;
52 | }
53 | 
54 | - (void) setMenuShowingExtraOptions:(BOOL)showingExtra {
55 |     _menuShowingExtraOptions = showingExtra;
56 |     _menuItem.hidden = !BGMDebugLoggingIsEnabled() && !showingExtra;
57 | 
58 |     DebugMsg("BGMDebugLoggingMenuItem::menuShowingExtraOptions: %s the menu item",
59 |              _menuItem.hidden ? "Hiding" : "Showing");
60 | }
61 | 
62 | - (void) toggleDebugLogging {
63 |     BGMSetDebugLoggingEnabled(!BGMDebugLoggingIsEnabled());
64 |     _menuItem.state = BGMDebugLoggingIsEnabled() ? NSControlStateValueOn : NSControlStateValueOff;
65 | 
66 |     DebugMsg("BGMDebugLoggingMenuItem::toggleDebugLogging: Debug logging %s",
67 |              BGMDebugLoggingIsEnabled() ? "enabled" : "disabled");
68 | }
69 | 
70 | @end
71 | 
72 | #pragma clang assume_nonnull end
73 | 
74 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMOutputDeviceMenuSection.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMOutputDeviceMenuSection.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016, 2018 Kyle Neideck
21 | //
22 | 
23 | // Local Includes
24 | #import "BGMAudioDeviceManager.h"
25 | #import "BGMPreferredOutputDevices.h"
26 | 
27 | // System Includes
28 | #import <AppKit/AppKit.h>
29 | 
30 | 
31 | #pragma clang assume_nonnull begin
32 | 
33 | @interface BGMOutputDeviceMenuSection : NSObject
34 | 
35 | - (instancetype) initWithBGMMenu:(NSMenu*)inBGMMenu
36 |                     audioDevices:(BGMAudioDeviceManager*)inAudioDevices
37 |                 preferredDevices:(BGMPreferredOutputDevices*)inPreferredDevices;
38 | 
39 | // To be called when BGMApp has been set to use a different output device. For example, when a new
40 | // device is connected and BGMPreferredOutputDevices decides BGMApp should switch to it.
41 | - (void) outputDeviceDidChange;
42 | 
43 | @end
44 | 
45 | #pragma clang assume_nonnull end
46 | 
47 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMOutputVolumeMenuItem.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMOutputVolumeMenuItem.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2017 Kyle Neideck
21 | //
22 | 
23 | // Local Includes
24 | #import "BGMAudioDeviceManager.h"
25 | 
26 | // System Includes
27 | #import <Cocoa/Cocoa.h>
28 | 
29 | 
30 | #pragma clang assume_nonnull begin
31 | 
32 | @interface BGMOutputVolumeMenuItem : NSMenuItem
33 | 
34 | // A menu item with a slider for controlling the volume of the output device. Similar to the one in
35 | // macOS's Volume menu extra.
36 | //
37 | // view, slider and deviceLabel are the UI elements from MainMenu.xib.
38 | - (instancetype) initWithAudioDevices:(BGMAudioDeviceManager*)devices
39 |                                  view:(NSView*)view
40 |                                slider:(NSSlider*)slider
41 |                           deviceLabel:(NSTextField*)label;
42 | 
43 | - (void) outputDeviceDidChange;
44 | 
45 | @end
46 | 
47 | #pragma clang assume_nonnull end
48 | 
49 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMPreferredOutputDevices.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMPreferredOutputDevices.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2018 Kyle Neideck
21 | //
22 | //  Tries to change BGMApp's output device when the user plugs in or unplugs an audio device, in the
23 | //  same way macOS would change its default device if Background Music wasn't running.
24 | //
25 | //  For example, if you plug in some USB headphones, make them your default device and then unplug
26 | //  them, macOS will change its default device to the previous default device. Then, if you plug
27 | //  them back in, macOS will make them the default device again.
28 | //
29 | //  This class isn't always able to figure out what macOS would do, in which case it leaves BGMApp's
30 | //  output device as it is.
31 | //
32 | 
33 | // Local Includes
34 | #import "BGMAudioDeviceManager.h"
35 | #import "BGMUserDefaults.h"
36 | 
37 | // System Includes
38 | #import <CoreAudio/AudioHardwareBase.h>
39 | #import <Foundation/Foundation.h>
40 | 
41 | 
42 | #pragma clang assume_nonnull begin
43 | 
44 | @interface BGMPreferredOutputDevices : NSObject
45 | 
46 | // Starts responding to device connections/disconnections immediately. Stops if/when the instance is
47 | // deallocated.
48 | - (instancetype) initWithDevices:(BGMAudioDeviceManager*)devices
49 |                     userDefaults:(BGMUserDefaults*)userDefaults;
50 | 
51 | // Returns the most-preferred device that's currently connected. If no preferred devices are
52 | // connected, returns the current output device. If the current output device has been disconnected,
53 | // returns an arbitrary device.
54 | //
55 | // If none of the connected devices can be used as the output device, or if it can't find a device
56 | // to use because the HAL returned errors when queried, returns kAudioObjectUnknown.
57 | - (AudioObjectID) findPreferredDevice;
58 | 
59 | - (void) userChangedOutputDeviceTo:(AudioObjectID)device;
60 | 
61 | @end
62 | 
63 | #pragma clang assume_nonnull end
64 | 
65 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMStatusBarItem.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMStatusBarItem.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2019, 2020 Kyle Neideck
21 | //
22 | //  The button in the system status bar (the bar with volume, battery, clock, etc.) to show the main
23 | //  menu for the app. These are called "menu bar extras" in the Human Interface Guidelines.
24 | //
25 | 
26 | // Local Includes
27 | #import "BGMAudioDeviceManager.h"
28 | #import "BGMDebugLoggingMenuItem.h"
29 | 
30 | // System Includes
31 | #import <Cocoa/Cocoa.h>
32 | 
33 | // Forward Declarations
34 | @class BGMUserDefaults;
35 | 
36 | 
37 | #pragma clang assume_nonnull begin
38 | 
39 | typedef NS_ENUM(NSInteger, BGMStatusBarIcon) {
40 |     BGMFermataStatusBarIcon = 0,
41 |     BGMVolumeStatusBarIcon
42 | };
43 | 
44 | static BGMStatusBarIcon const kBGMStatusBarIconMinValue     = BGMFermataStatusBarIcon;
45 | static BGMStatusBarIcon const kBGMStatusBarIconMaxValue     = BGMVolumeStatusBarIcon;
46 | static BGMStatusBarIcon const kBGMStatusBarIconDefaultValue = BGMFermataStatusBarIcon;
47 | 
48 | @interface BGMStatusBarItem : NSObject
49 | 
50 | - (instancetype) initWithMenu:(NSMenu*)bgmMenu
51 |                  audioDevices:(BGMAudioDeviceManager*)devices
52 |                  userDefaults:(BGMUserDefaults*)defaults;
53 | 
54 | // Set this to BGMFermataStatusBarIcon to change the icon to the Background Music logo.
55 | //
56 | // Set this to BGMFermataStatusBarIcon to change the icon to a volume icon. This icon has the
57 | // advantage of indicating the volume level, but we can't make it the default because it looks the
58 | // same as the icon for the macOS volume status bar item.
59 | @property BGMStatusBarIcon icon;
60 | 
61 | // If the user holds down the option key when they click the status bar icon, this menu item will be
62 | // shown in the main menu.
63 | - (void) setDebugLoggingMenuItem:(BGMDebugLoggingMenuItem*)menuItem;
64 | 
65 | @end
66 | 
67 | #pragma clang assume_nonnull end
68 | 
69 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMSystemSoundsVolume.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMSystemSoundsVolume.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2017 Kyle Neideck
21 | //
22 | //  The menu item with the volume slider that controls system-related sounds. The slider is used to
23 | //  set the volume of the instance of BGMDevice that system sounds are played on, i.e. the audio
24 | //  device returned by BGMBackgroundMusicDevice::GetUISoundsBGMDeviceInstance.
25 | //
26 | //  System sounds are any sounds played using the audio device macOS is set to use as the device
27 | //  "for system related sound from the alert sound to digital call progress". See
28 | //  kAudioHardwarePropertyDefaultSystemOutputDevice in AudioHardware.h. They can be played by any
29 | //  app, though most apps use systemsoundserverd to play their system sounds, which means BGMDriver
30 | //  can't tell which app is actually playing the sounds.
31 | //
32 | 
33 | // Local Includes
34 | #import "BGMAudioDevice.h"
35 | 
36 | // System Includes
37 | #import <Cocoa/Cocoa.h>
38 | 
39 | 
40 | #pragma clang assume_nonnull begin
41 | 
42 | @interface BGMSystemSoundsVolume : NSObject
43 | 
44 | // The volume level of uiSoundsDevice will be used to set the slider's initial position and will be
45 | // updated when the user moves the slider. view and slider are the UI elements from MainMenu.xib.
46 | - (instancetype) initWithUISoundsDevice:(BGMAudioDevice)uiSoundsDevice
47 |                                    view:(NSView*)view
48 |                                  slider:(NSSlider*)slider;
49 | 
50 | // The menu item with the volume slider for system sounds.
51 | @property (readonly) NSMenuItem* menuItem;
52 | 
53 | @end
54 | 
55 | #pragma clang assume_nonnull end
56 | 
57 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMSystemSoundsVolume.mm:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMSystemSoundsVolume.mm
18 | //  BGMApp
19 | //
20 | //  Copyright © 2017 Kyle Neideck
21 | //
22 | 
23 | // Self Include
24 | #import "BGMSystemSoundsVolume.h"
25 | 
26 | // Local Includes
27 | #import "BGM_Types.h"
28 | #import "BGM_Utils.h"
29 | 
30 | 
31 | #pragma clang assume_nonnull begin
32 | 
33 | // TODO: It's a bit confusing that this slider's default position is all the way right, but the App
34 | //       Volumes sliders default to 50%. After you move the slider there's no way to tell how to put
35 | //       it back to its normal position.
36 | 
37 | NSString* const kMenuItemToolTip =
38 |     @"Alerts, notification sounds, etc. Usually short. Can be played by any app.";
39 | 
40 | @implementation BGMSystemSoundsVolume {
41 |     BGMAudioDevice uiSoundsDevice;
42 |     NSSlider* volumeSlider;
43 | }
44 | 
45 | - (instancetype) initWithUISoundsDevice:(BGMAudioDevice)inUISoundsDevice
46 |                                    view:(NSView*)inView
47 |                                  slider:(NSSlider*)inSlider {
48 |     if ((self = [super init])) {
49 |         uiSoundsDevice = inUISoundsDevice;
50 |         volumeSlider = inSlider;
51 | 
52 |         _menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
53 |         _menuItem.toolTip = kMenuItemToolTip;
54 | 
55 |         // Apply our custom view from MainMenu.xib. It's very similar to the one for app volumes.
56 |         _menuItem.view = inView;
57 | 
58 |         try {
59 |             volumeSlider.floatValue =
60 |                 uiSoundsDevice.GetVolumeControlScalarValue(kAudioObjectPropertyScopeOutput,
61 |                                                            kMasterChannel);
62 |         } catch (const CAException& e) {
63 |             BGMLogException(e);
64 |             volumeSlider.floatValue = 1.0f;  // Full volume
65 |         }
66 | 
67 |         volumeSlider.target = self;
68 |         volumeSlider.action = @selector(systemSoundsSliderChanged:);
69 |     }
70 | 
71 |     return self;
72 | }
73 | 
74 | - (void) systemSoundsSliderChanged:(id)sender {
75 |     #pragma unused(sender)
76 | 
77 |     float sliderLevel = volumeSlider.floatValue;
78 | 
79 |     BGMAssert((sliderLevel >= 0.0f) && (sliderLevel <= 1.0f), "Invalid value from slider");
80 |     DebugMsg("BGMSystemSoundsVolume::systemSoundsSliderChanged: UI sounds volume: %f", sliderLevel);
81 | 
82 |     BGMLogAndSwallowExceptions("BGMSystemSoundsVolume::systemSoundsSliderChanged", ([&] {
83 |         uiSoundsDevice.SetVolumeControlScalarValue(kAudioObjectPropertyScopeOutput,
84 |                                                    kMasterChannel,
85 |                                                    sliderLevel);
86 |     }));
87 | }
88 | 
89 | @end
90 | 
91 | #pragma clang assume_nonnull end
92 | 
93 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMTermination.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMTermination.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2017 Kyle Neideck
21 | //
22 | //  Cleans up if BGMApp crashes because of an uncaught C++ or Objective-C exception, or is sent
23 | //  SIGINT/SIGTERM/SIGQUIT. Currently, it just changes the default output device from BGMDevice to
24 | //  the real output device and records debug info for some types of crashes.
25 | //
26 | //  BGMXPCHelper also changes the default device if BGMApp disconnects and leaves BGMDevice as the
27 | //  default. This handles cases like segfaults where it wouldn't be safe to clean up from the
28 | //  crashing process.
29 | //
30 | 
31 | #ifndef BGMApp__BGMTermination
32 | #define BGMApp__BGMTermination
33 | 
34 | // Local Includes
35 | #import "BGMAudioDeviceManager.h"
36 | 
37 | // PublicUtility Includes
38 | #import "CAPThread.h"
39 | 
40 | // STL Includes
41 | #import <exception>
42 | 
43 | 
44 | #pragma clang assume_nonnull begin
45 | 
46 | class BGMTermination
47 | {
48 | 
49 | public:
50 |     /*!
51 |      Starts a thread that will clean up before exiting if BGMApp receives SIGINT, SIGTERM or
52 |      SIGQUIT. Sets a similar clean up function to run if BGMApp terminates due to an uncaught
53 |      exception.
54 |      */
55 |     static void                      SetUpTerminationCleanUp(BGMAudioDeviceManager* inAudioDevices);
56 | 
57 |     /*! Some commented out ways to have BGMApp crash for testing. Does nothing if unmodified. */
58 |     static void                      TestCrash() __attribute__((noinline));
59 | 
60 | private:
61 |     static void                      StartExitSignalsThread();
62 | 
63 |     static void                      CleanUpAudioDevices();
64 | 
65 |     /*! Adds some info about the uncaught exception that caused a crash to the crash report. */
66 |     static void                      AddCurrentExceptionToCrashReport();
67 | 
68 |     /*! The entry point for sExitSignalsThread. */
69 |     static void* __nullable          ExitSignalsProc(void* __nullable ignored);
70 | 
71 |     /*! The thread that handles SIGQUIT, SIGTERM and SIGINT. Never destroyed. */
72 |     static CAPThread* const          sExitSignalsThread;
73 |     static sigset_t                  sExitSignals;
74 | 
75 |     /*! The function that handles std::terminate by default. */
76 |     static std::terminate_handler    sOriginalTerminateHandler;
77 | 
78 |     /*! The audio device manager. (Must be static to be accessed in our std::terminate_handler.) */
79 |     static BGMAudioDeviceManager* __nullable sAudioDevices;
80 | 
81 | };
82 | 
83 | #pragma clang assume_nonnull end
84 | 
85 | #endif /* BGMApp__BGMTermination */
86 | 
87 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMUserDefaults.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMUserDefaults.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016-2019 Kyle Neideck
21 | //
22 | //  A simple wrapper around our use of NSUserDefaults. Used to store the preferences/state that only
23 | //  apply to BGMApp. The others are stored by BGMDriver.
24 | //
25 | //  Private data will be stored in the user's keychain instead of user defaults.
26 | //
27 | 
28 | // Local Includes
29 | #import "BGMStatusBarItem.h"
30 | 
31 | // System Includes
32 | #import <Cocoa/Cocoa.h>
33 | 
34 | 
35 | #pragma clang assume_nonnull begin
36 | 
37 | @interface BGMUserDefaults : NSObject
38 | 
39 | // If inDefaults is nil, settings are not loaded from or saved to disk, which is useful for testing.
40 | - (instancetype) initWithDefaults:(NSUserDefaults* __nullable)inDefaults;
41 | 
42 | // The musicPlayerID (see BGMMusicPlayer.h), as a string, of the music player selected by the user.
43 | // Must be either null or a string that can be parsed by NSUUID.
44 | @property NSString* __nullable selectedMusicPlayerID;
45 | 
46 | @property BOOL autoPauseMusicEnabled;
47 | 
48 | // The UIDs of the output devices most recently selected by the user. The most-recently selected
49 | // device is at index 0. See BGMPreferredOutputDevices.
50 | @property NSArray<NSString*>* preferredDeviceUIDs;
51 | 
52 | // The (type of) icon to show in the button in the status bar. (The button the user clicks to open
53 | // BGMApp's main menu.)
54 | @property BGMStatusBarIcon statusBarIcon;
55 | 
56 | // The auth code we're required to send when connecting to GPMDP. Stored in the keychain. Reading
57 | // this property is thread-safe, but writing it isn't.
58 | //
59 | // Returns nil if no code is found or if reading fails. If writing fails, an error is logged, but no
60 | // exception is thrown.
61 | @property NSString* __nullable googlePlayMusicDesktopPlayerPermanentAuthCode;
62 | 
63 | // Auto-pause delay settings in milliseconds. These control how long to wait before pausing/unpausing
64 | // music when other audio starts/stops playing.
65 | @property NSUInteger pauseDelayMS;
66 | @property NSUInteger maxUnpauseDelayMS;
67 | 
68 | @end
69 | 
70 | #pragma clang assume_nonnull end
71 | 
72 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMVolumeChangeListener.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMVolumeChangeListener.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2019 Kyle Neideck
21 | //
22 | 
23 | // Local Includes
24 | #include "BGMBackgroundMusicDevice.h"
25 | 
26 | // PublicUtility Includes
27 | #import "CAPropertyAddress.h"
28 | 
29 | // STL Includes
30 | #include <functional>
31 | 
32 | // System Includes
33 | #include <CoreAudio/CoreAudio.h>
34 | 
35 | 
36 | #pragma clang assume_nonnull begin
37 | 
38 | class BGMVolumeChangeListener
39 | {
40 | 
41 | public:
42 |     /*!
43 |      * @param device Listens for notifications about this device.
44 |      * @param handler The function to call when the device's volume (or mute) changes. Called on the
45 |      *                main queue.
46 |      */
47 |     BGMVolumeChangeListener(BGMAudioDevice device, std::function<void(void)> handler);
48 |     virtual ~BGMVolumeChangeListener();
49 |     BGMVolumeChangeListener(const BGMVolumeChangeListener&) = delete;
50 |     BGMVolumeChangeListener& operator=(const BGMVolumeChangeListener&) = delete;
51 | 
52 | private:
53 |     AudioObjectPropertyListenerBlock     mListenerBlock;
54 |     BGMAudioDevice                       mDevice;
55 | 
56 | };
57 | 
58 | #pragma clang assume_nonnull end
59 | 
60 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/BGMXPCListener.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMXPCListener.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | //  Connects to BGMXPCHelper via XPC. When BGMDriver wants BGMApp to do something it can call one of BGMHelper's
23 | //  XPC methods, which passes the request along to this class.
24 | //
25 | 
26 | // Local Includes
27 | #import "BGMAudioDeviceManager.h"
28 | #import "BGMXPCProtocols.h"
29 | 
30 | // System Includes
31 | #import <Foundation/Foundation.h>
32 | 
33 | 
34 | #pragma clang assume_nonnull begin
35 | 
36 | @interface BGMXPCListener : NSObject <BGMAppXPCProtocol, NSXPCListenerDelegate>
37 | 
38 | - (id) initWithAudioDevices:(BGMAudioDeviceManager*)devices helperConnectionErrorHandler:(void (^)(NSError* error))errorHandler;
39 | 
40 | - (void) initHelperConnection;
41 | 
42 | @end
43 | 
44 | #pragma clang assume_nonnull end
45 | 
46 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AirPlayIcon.imageset/AirPlay.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/AirPlayIcon.imageset/AirPlay.pdf


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AirPlayIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "idiom" : "universal",
 5 |       "filename" : "AirPlay.pdf",
 6 |       "scale" : "1x"
 7 |     },
 8 |     {
 9 |       "idiom" : "universal",
10 |       "scale" : "2x"
11 |     },
12 |     {
13 |       "idiom" : "universal",
14 |       "scale" : "3x"
15 |     }
16 |   ],
17 |   "info" : {
18 |     "version" : 1,
19 |     "author" : "xcode"
20 |   }
21 | }


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "size" : "16x16",
 5 |       "idiom" : "mac",
 6 |       "filename" : "appicon_16.png",
 7 |       "scale" : "1x"
 8 |     },
 9 |     {
10 |       "size" : "16x16",
11 |       "idiom" : "mac",
12 |       "filename" : "appicon_32.png",
13 |       "scale" : "2x"
14 |     },
15 |     {
16 |       "size" : "32x32",
17 |       "idiom" : "mac",
18 |       "filename" : "appicon_32.png",
19 |       "scale" : "1x"
20 |     },
21 |     {
22 |       "size" : "32x32",
23 |       "idiom" : "mac",
24 |       "filename" : "appicon_64.png",
25 |       "scale" : "2x"
26 |     },
27 |     {
28 |       "size" : "128x128",
29 |       "idiom" : "mac",
30 |       "filename" : "appicon_128.png",
31 |       "scale" : "1x"
32 |     },
33 |     {
34 |       "size" : "128x128",
35 |       "idiom" : "mac",
36 |       "filename" : "appicon_256.png",
37 |       "scale" : "2x"
38 |     },
39 |     {
40 |       "size" : "256x256",
41 |       "idiom" : "mac",
42 |       "filename" : "appicon_256.png",
43 |       "scale" : "1x"
44 |     },
45 |     {
46 |       "size" : "256x256",
47 |       "idiom" : "mac",
48 |       "filename" : "appicon_512.png",
49 |       "scale" : "2x"
50 |     },
51 |     {
52 |       "size" : "512x512",
53 |       "idiom" : "mac",
54 |       "filename" : "appicon_512.png",
55 |       "scale" : "1x"
56 |     },
57 |     {
58 |       "size" : "512x512",
59 |       "idiom" : "mac",
60 |       "filename" : "appicon_1024.png",
61 |       "scale" : "2x"
62 |     }
63 |   ],
64 |   "info" : {
65 |     "version" : 1,
66 |     "author" : "xcode"
67 |   }
68 | }


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_1024.png


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_128.png


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_16.png


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_256.png


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_32.png


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_512.png


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/appicon_64.png


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 |   "info" : {
3 |     "version" : 1,
4 |     "author" : "xcode"
5 |   }
6 | }


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/FermataIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "idiom" : "mac",
 5 |       "filename" : "FermataIcon.pdf"
 6 |     }
 7 |   ],
 8 |   "info" : {
 9 |     "version" : 1,
10 |     "author" : "xcode"
11 |   }
12 | }


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/FermataIcon.imageset/FermataIcon.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/FermataIcon.imageset/FermataIcon.pdf


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/Volume0.imageset/Contents.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "idiom" : "mac",
 5 |       "filename" : "Volume0.pdf"
 6 |     }
 7 |   ],
 8 |   "info" : {
 9 |     "version" : 1,
10 |     "author" : "xcode"
11 |   }
12 | }
13 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/Volume0.imageset/Volume0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/Volume0.imageset/Volume0.pdf


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/Volume1.imageset/Contents.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "idiom" : "mac",
 5 |       "filename" : "Volume1.pdf"
 6 |     }
 7 |   ],
 8 |   "info" : {
 9 |     "version" : 1,
10 |     "author" : "xcode"
11 |   }
12 | }
13 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/Volume1.imageset/Volume1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/Volume1.imageset/Volume1.pdf


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/Volume2.imageset/Contents.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "idiom" : "mac",
 5 |       "filename" : "Volume2.pdf"
 6 |     }
 7 |   ],
 8 |   "info" : {
 9 |     "version" : 1,
10 |     "author" : "xcode"
11 |   }
12 | }
13 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/Volume2.imageset/Volume2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/Volume2.imageset/Volume2.pdf


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/Volume3.imageset/Contents.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "idiom" : "mac",
 5 |       "filename" : "Volume3.pdf"
 6 |     }
 7 |   ],
 8 |   "info" : {
 9 |     "version" : 1,
10 |     "author" : "xcode"
11 |   }
12 | }
13 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Images.xcassets/Volume3.imageset/Volume3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/BGMApp/Images.xcassets/Volume3.imageset/Volume3.pdf


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>AudioHardwarePowerHint</key>
 6 | 	<string>None</string>
 7 | 	<key>CFBundleDevelopmentRegion</key>
 8 | 	<string>en</string>
 9 | 	<key>CFBundleExecutable</key>
10 | 	<string>$(EXECUTABLE_NAME)</string>
11 | 	<key>CFBundleIdentifier</key>
12 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13 | 	<key>CFBundleInfoDictionaryVersion</key>
14 | 	<string>6.0</string>
15 | 	<key>CFBundleName</key>
16 | 	<string>$(PRODUCT_NAME)</string>
17 | 	<key>CFBundlePackageType</key>
18 | 	<string>APPL</string>
19 | 	<key>CFBundleShortVersionString</key>
20 | 	<string>0.4.3</string>
21 | 	<key>CFBundleSignature</key>
22 | 	<string>????</string>
23 | 	<key>CFBundleVersion</key>
24 | 	<string>1.0.0</string>
25 | 	<key>LSApplicationCategoryType</key>
26 | 	<string>public.app-category.utilities</string>
27 | 	<key>LSMinimumSystemVersion</key>
28 | 	<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
29 | 	<key>LSUIElement</key>
30 | 	<true/>
31 | 	<key>NSAppleEventsUsageDescription</key>
32 | 	<string>Background Music needs to control your music player app if you want it to automatically pause your music.</string>
33 | 	<key>NSAppleScriptEnabled</key>
34 | 	<true/>
35 | 	<key>NSHumanReadableCopyright</key>
36 | 	<string>Copyright © 2016-2024 Background Music contributors</string>
37 | 	<key>NSMainNibFile</key>
38 | 	<string>MainMenu</string>
39 | 	<key>NSMicrophoneUsageDescription</key>
40 | 	<string>The &quot;Background Music&quot; virtual audio device sends system audio to Background Music (the app) through a virtual input device.</string>
41 | 	<key>NSPrincipalClass</key>
42 | 	<string>NSApplication</string>
43 | 	<key>NSServices</key>
44 | 	<array>
45 | 		<dict/>
46 | 	</array>
47 | 	<key>OSAScriptingDefinition</key>
48 | 	<string>BGMApp.sdef</string>
49 |     <!--
50 |     Hopefully this will keep Background Music from using the discrete GPU on multi-GPU systems,
51 |     which wastes energy. I don't have any hardware I could easily test this on, so it's untested.
52 |     -->
53 | 	<key>NSSupportsAutomaticGraphicsSwitching</key>
54 | 	<true/>
55 | </dict>
56 | </plist>
57 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMDecibel.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMDecibel.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Superclass/Protocol Import
24 | #import "BGMMusicPlayer.h"
25 | 
26 | 
27 | @interface BGMDecibel : BGMMusicPlayerBase<BGMMusicPlayer>
28 | 
29 | @end
30 | 
31 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMDecibel.m:
--------------------------------------------------------------------------------
  1 | // This file is part of Background Music.
  2 | //
  3 | // Background Music is free software: you can redistribute it and/or
  4 | // modify it under the terms of the GNU General Public License as
  5 | // published by the Free Software Foundation, either version 2 of the
  6 | // License, or (at your option) any later version.
  7 | //
  8 | // Background Music is distributed in the hope that it will be useful,
  9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11 | // GNU General Public License for more details.
 12 | //
 13 | // You should have received a copy of the GNU General Public License
 14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
 15 | 
 16 | //
 17 | //  BGMDecibel.m
 18 | //  BGMApp
 19 | //
 20 | //  Copyright © 2016-2018 Kyle Neideck
 21 | //  Copyright © 2016 Tanner Hoke
 22 | //
 23 | 
 24 | // Self Include
 25 | #import "BGMDecibel.h"
 26 | 
 27 | // Auto-generated Scripting Bridge header
 28 | #import "Decibel.h"
 29 | 
 30 | // Local Includes
 31 | #import "BGMScriptingBridge.h"
 32 | 
 33 | // PublicUtility Includes
 34 | #import "CADebugMacros.h"
 35 | 
 36 | 
 37 | #pragma clang assume_nonnull begin
 38 | 
 39 | @implementation BGMDecibel {
 40 |     BGMScriptingBridge* scriptingBridge;
 41 | }
 42 | 
 43 | - (instancetype) init {
 44 |     if ((self = [super initWithMusicPlayerID:[BGMMusicPlayerBase makeID:@"A9790CD5-4886-47C7-9FFC-DD70743CF2BF"]
 45 |                                         name:@"Decibel"
 46 |                                     bundleID:@"org.sbooth.Decibel"])) {
 47 |         scriptingBridge = [[BGMScriptingBridge alloc] initWithMusicPlayer:self];
 48 |     }
 49 |     
 50 |     return self;
 51 | }
 52 | 
 53 | - (DecibelApplication* __nullable) decibel {
 54 |     return (DecibelApplication* __nullable)scriptingBridge.application;
 55 | }
 56 | 
 57 | - (void) wasSelected {
 58 |     [super wasSelected];
 59 |     [scriptingBridge ensurePermission];
 60 | }
 61 | 
 62 | - (BOOL) isRunning {
 63 |     return self.decibel.running;
 64 | }
 65 | 
 66 | - (BOOL) isPlaying {
 67 |     return self.running && self.decibel.playing;
 68 | }
 69 | 
 70 | - (BOOL) isPaused {
 71 |     // We don't want to return true when Decibel is stopped, rather than paused. At least for me, Decibel
 72 |     // returns -1 for playbackTime and playbackPosition when it's neither playing nor paused.
 73 |     BOOL probablyNotStopped =
 74 |         self.decibel.playbackTime >= 0 || self.decibel.playbackPosition >= 0;
 75 |     
 76 |     return self.running && !self.decibel.playing && probablyNotStopped;
 77 | }
 78 | 
 79 | - (BOOL) pause {
 80 |     // isPlaying checks isRunning, so we don't need to check it here and waste an Apple event
 81 |     BOOL wasPlaying = self.playing;
 82 |     
 83 |     if (wasPlaying) {
 84 |         DebugMsg("BGMDecibel::pause: Pausing Decibel");
 85 |         [self.decibel pause];
 86 |     }
 87 |     
 88 |     return wasPlaying;
 89 | }
 90 | 
 91 | - (BOOL) unpause {
 92 |     // isPaused checks isRunning, so we don't need to check it here and waste an Apple event
 93 |     BOOL wasPaused = self.paused;
 94 |     
 95 |     if (wasPaused) {
 96 |         DebugMsg("BGMDecibel::unpause: Unpausing Decibel");
 97 |         [self.decibel play];
 98 |     }
 99 |     
100 |     return wasPaused;
101 | }
102 | 
103 | @end
104 | 
105 | #pragma clang assume_nonnull end
106 | 
107 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMGooglePlayMusicDesktopPlayer.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMGooglePlayMusicDesktopPlayer.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2019 Kyle Neideck
21 | //
22 | //  We have a lot more code for GPMDP than most music players largely because GPMDP has a WebSockets
23 | //  API and because the user has to enter a code from GPMDP to allow BGMApp to control it.
24 | //  Currently, the other music players all have AppleScript APIs, so for them the OS asks the user
25 | //  for permission on our behalf automatically and handles the whole process for us.
26 | //
27 | //  This class implements the usual BGMMusicPlayer methods and handles the UI for authenticating
28 | //  with GPMDP. BGMGooglePlayMusicDesktopPlayerConnection manages the connection to GPMDP and hides
29 | //  the details of its API.
30 | //
31 | 
32 | // Superclass/Protocol Import
33 | #import "BGMMusicPlayer.h"
34 | 
35 | 
36 | #pragma clang assume_nonnull begin
37 | 
38 | API_AVAILABLE(macos(10.10))
39 | @interface BGMGooglePlayMusicDesktopPlayer : BGMMusicPlayerBase<BGMMusicPlayer>
40 | 
41 | + (NSArray<id<BGMMusicPlayer>>*) createInstancesWithDefaults:(BGMUserDefaults*)userDefaults;
42 | 
43 | @end
44 | 
45 | #pragma clang assume_nonnull end
46 | 
47 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMGooglePlayMusicDesktopPlayerConnection.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMGooglePlayMusicDesktopPlayerConnection.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2019 Kyle Neideck
21 | //
22 | 
23 | // Local Includes
24 | #import "BGMUserDefaults.h"
25 | 
26 | // System Includes
27 | #import <Cocoa/Cocoa.h>
28 | #import <WebKit/WebKit.h>
29 | 
30 | 
31 | #pragma clang assume_nonnull begin
32 | 
33 | API_AVAILABLE(macos(10.10))
34 | @interface BGMGooglePlayMusicDesktopPlayerConnection : NSObject<WKScriptMessageHandler>
35 | 
36 | // authRequiredHandler: A UI callback that asks the user for the auth code GPMDP will display.
37 | //                      Returns the auth code they entered, or nil.
38 | // connectionErrorHandler: A UI callback that shows a connection error message.
39 | // apiVersionMismatchHandler: A UI callback that shows a warning dialog explaining that GPMDP
40 | //                            reported an API version that we don't support yet.
41 | - (instancetype) initWithUserDefaults:(BGMUserDefaults*)defaults
42 |                   authRequiredHandler:(NSString* __nullable (^)(void))authHandler
43 |                connectionErrorHandler:(void (^)(void))errorHandler
44 |             apiVersionMismatchHandler:(void (^)(NSString* reportedAPIVersion))apiVersionHandler;
45 | 
46 | // Returns before the connection has been fully established. The playing and paused properties will
47 | // remain false until the connection is complete, but playPause can be called at any time after
48 | // calling this method.
49 | //
50 | // If the connection fails, it will be retried after a one second delay, up to the number of times
51 | // given.
52 | - (void) connectWithRetries:(int)retries;
53 | - (void) disconnect;
54 | 
55 | // Tell GPMDP to play if it's paused or pause if it's playing.
56 | - (void) playPause;
57 | 
58 | @property (readonly) BOOL playing;
59 | @property (readonly) BOOL paused;
60 | 
61 | @end
62 | 
63 | #pragma clang assume_nonnull end
64 | 
65 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMHermes.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMHermes.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Superclass/Protocol Import
24 | #import "BGMMusicPlayer.h"
25 | 
26 | 
27 | @interface BGMHermes : BGMMusicPlayerBase<BGMMusicPlayer>
28 | 
29 | @end
30 | 
31 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMHermes.m:
--------------------------------------------------------------------------------
  1 | // This file is part of Background Music.
  2 | //
  3 | // Background Music is free software: you can redistribute it and/or
  4 | // modify it under the terms of the GNU General Public License as
  5 | // published by the Free Software Foundation, either version 2 of the
  6 | // License, or (at your option) any later version.
  7 | //
  8 | // Background Music is distributed in the hope that it will be useful,
  9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11 | // GNU General Public License for more details.
 12 | //
 13 | // You should have received a copy of the GNU General Public License
 14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
 15 | 
 16 | //
 17 | //  BGMHermes.m
 18 | //  BGMApp
 19 | //
 20 | //  Copyright © 2016-2018 Kyle Neideck
 21 | //
 22 | 
 23 | // Self Include
 24 | #import "BGMHermes.h"
 25 | 
 26 | // Auto-generated Scripting Bridge header
 27 | #import "Hermes.h"
 28 | 
 29 | // Local Includes
 30 | #import "BGMScriptingBridge.h"
 31 | 
 32 | // PublicUtility Includes
 33 | #import "CADebugMacros.h"
 34 | 
 35 | 
 36 | #pragma clang assume_nonnull begin
 37 | 
 38 | @implementation BGMHermes {
 39 |     BGMScriptingBridge* scriptingBridge;
 40 | }
 41 | 
 42 | - (instancetype) init {
 43 |     // If you're copying this class, replace the ID string with a new one generated by uuidgen. (Command line tool.)
 44 |     if ((self = [super initWithMusicPlayerID:[BGMMusicPlayerBase makeID:@"0CDC67B0-56D3-4D94-BC06-6E380D8F5E34"]
 45 |                                         name:@"Hermes"
 46 |                                     bundleID:@"com.alexcrichton.Hermes"])) {
 47 |         scriptingBridge = [[BGMScriptingBridge alloc] initWithMusicPlayer:self];
 48 |     }
 49 |     
 50 |     return self;
 51 | }
 52 | 
 53 | - (HermesApplication* __nullable) hermes {
 54 |     return (HermesApplication* __nullable)scriptingBridge.application;
 55 | }
 56 | 
 57 | - (void) wasSelected {
 58 |     [super wasSelected];
 59 |     [scriptingBridge ensurePermission];
 60 | }
 61 | 
 62 | - (BOOL) isRunning {
 63 |     // Note that this will return NO if is self.hermes is nil (i.e. Hermes isn't running).
 64 |     return self.hermes.running;
 65 | }
 66 | 
 67 | // isPlaying and isPaused check self.running first just in case Hermes is closed but self.hermes hasn't become
 68 | // nil yet. In that case, reading self.hermes.playerState could make Scripting Bridge open Hermes.
 69 | 
 70 | - (BOOL) isPlaying {
 71 |     return self.running && (self.hermes.playbackState == HermesPlayerStatesPlaying);
 72 | }
 73 | 
 74 | - (BOOL) isPaused {
 75 |     return self.running && (self.hermes.playbackState == HermesPlayerStatesPaused);
 76 | }
 77 | 
 78 | - (BOOL) pause {
 79 |     // isPlaying checks isRunning, so we don't need to check it here and waste an Apple event
 80 |     BOOL wasPlaying = self.playing;
 81 |     
 82 |     if (wasPlaying) {
 83 |         DebugMsg("BGMHermes::pause: Pausing Hermes");
 84 |         [self.hermes pause];
 85 |     }
 86 |     
 87 |     return wasPlaying;
 88 | }
 89 | 
 90 | - (BOOL) unpause {
 91 |     // isPaused checks isRunning, so we don't need to check it here and waste an Apple event
 92 |     BOOL wasPaused = self.paused;
 93 |     
 94 |     if (wasPaused) {
 95 |         DebugMsg("BGMHermes::unpause: Unpausing Hermes");
 96 |         [self.hermes play];
 97 |     }
 98 |     
 99 |     return wasPaused;
100 | }
101 | 
102 | @end
103 | 
104 | #pragma clang assume_nonnull end
105 | 
106 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMMusic.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMMusic.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016, 2019 Kyle Neideck
21 | //  Copyright © 2019 theLMGN
22 | //
23 | 
24 | // Superclass/Protocol Import
25 | #import "BGMMusicPlayer.h"
26 | 
27 | 
28 | #pragma clang assume_nonnull begin
29 | 
30 | @interface BGMMusic : BGMMusicPlayerBase<BGMMusicPlayer>
31 | 
32 | @end
33 | 
34 | #pragma clang assume_nonnull end
35 | 
36 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMMusic.m:
--------------------------------------------------------------------------------
  1 | // This file is part of Background Music.
  2 | //
  3 | // Background Music is free software: you can redistribute it and/or
  4 | // modify it under the terms of the GNU General Public License as
  5 | // published by the Free Software Foundation, either version 2 of the
  6 | // License, or (at your option) any later version.
  7 | //
  8 | // Background Music is distributed in the hope that it will be useful,
  9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11 | // GNU General Public License for more details.
 12 | //
 13 | // You should have received a copy of the GNU General Public License
 14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
 15 | 
 16 | //
 17 | //  BGMMusic.m
 18 | //  BGMApp
 19 | //
 20 | //  Copyright © 2016-2019 Kyle Neideck, theLMGN
 21 | //
 22 | 
 23 | // Self Include
 24 | #import "BGMMusic.h"
 25 | 
 26 | // Auto-generated Scripting Bridge header
 27 | #import "Music.h"
 28 | 
 29 | // Local Includes
 30 | #import "BGMScriptingBridge.h"
 31 | 
 32 | // PublicUtility Includes
 33 | #import "CADebugMacros.h"
 34 | 
 35 | 
 36 | #pragma clang assume_nonnull begin
 37 | 
 38 | @implementation BGMMusic {
 39 |     BGMScriptingBridge* scriptingBridge;
 40 | }
 41 | 
 42 | + (NSUUID*) sharedMusicPlayerID {
 43 |     NSUUID* __nullable musicPlayerID =
 44 |             [[NSUUID alloc] initWithUUIDString:@"829B8069-8BD2-481D-BD40-54AB8CDAE228"];
 45 |     NSAssert(musicPlayerID, @"BGMMusic::sharedMusicPlayerID: !musicPlayerID");
 46 |     return (NSUUID*)musicPlayerID;
 47 | }
 48 | 
 49 | - (instancetype) init {
 50 |     if ((self = [super initWithMusicPlayerID:[BGMMusic sharedMusicPlayerID]
 51 |                                         name:@"Music"
 52 |                                     bundleID:@"com.apple.Music"])) {
 53 |         scriptingBridge = [[BGMScriptingBridge alloc] initWithMusicPlayer:self];
 54 |     }
 55 |     
 56 |     return self;
 57 | }
 58 | 
 59 | - (MusicApplication* __nullable) music {
 60 |     return (MusicApplication*)scriptingBridge.application;
 61 | }
 62 | 
 63 | - (void) wasSelected {
 64 |     [super wasSelected];
 65 |     [scriptingBridge ensurePermission];
 66 | }
 67 | 
 68 | - (BOOL) isRunning {
 69 |     return self.music.running;
 70 | }
 71 | 
 72 | // isPlaying and isPaused check self.running first just in case Music is closed but self.music
 73 | // hasn't become nil yet. In that case, reading self.music.playerState could make Scripting Bridge
 74 | // open Music.
 75 | 
 76 | - (BOOL) isPlaying {
 77 |     return self.running && (self.music.playerState == MusicEPlSPlaying);
 78 | }
 79 | 
 80 | - (BOOL) isPaused {
 81 |     return self.running && (self.music.playerState == MusicEPlSPaused);
 82 | }
 83 | 
 84 | - (BOOL) pause {
 85 |     // isPlaying checks isRunning, so we don't need to check it here and waste an Apple event
 86 |     BOOL wasPlaying = self.playing;
 87 |     
 88 |     if (wasPlaying) {
 89 |         DebugMsg("BGMMusic::pause: Pausing Music");
 90 |         [self.music pause];
 91 |     }
 92 |     
 93 |     return wasPlaying;
 94 | }
 95 | 
 96 | - (BOOL) unpause {
 97 |     // isPaused checks isRunning, so we don't need to check it here and waste an Apple event
 98 |     BOOL wasPaused = self.paused;
 99 |     
100 |     if (wasPaused) {
101 |         DebugMsg("BGMMusic::unpause: Unpausing Music");
102 |         [self.music playpause];
103 |     }
104 |     
105 |     return wasPaused;
106 | }
107 | 
108 | @end
109 | 
110 | #pragma clang assume_nonnull end
111 | 
112 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMMusicPlayers.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMMusicPlayers.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016, 2019 Kyle Neideck
21 | //
22 | //  Holds the music players (i.e. BGMMusicPlayer objects) available in BGMApp. Also keeps track of
23 | //  which music player is currently selected by the user.
24 | //
25 | 
26 | // Local Includes
27 | #import "BGMAudioDeviceManager.h"
28 | #import "BGMMusicPlayer.h"
29 | #import "BGMUserDefaults.h"
30 | 
31 | // System Includes
32 | #import <Foundation/Foundation.h>
33 | 
34 | 
35 | #pragma clang assume_nonnull begin
36 | 
37 | @interface BGMMusicPlayers : NSObject
38 | 
39 | // Calls initWithAudioDevices:musicPlayers: with sensible defaults.
40 | - (instancetype) initWithAudioDevices:(BGMAudioDeviceManager*)devices
41 |                          userDefaults:(BGMUserDefaults*)defaults;
42 | 
43 | // defaultMusicPlayerID is the musicPlayerID (see BGMMusicPlayer.h) of the music player that should be
44 | // selected by default.
45 | //
46 | // The createInstancesWithDefaults method of each class in musicPlayerClasses will be called and
47 | // the results will be stored in the musicPlayers property.
48 | - (instancetype) initWithAudioDevices:(BGMAudioDeviceManager*)devices
49 |                  defaultMusicPlayerID:(NSUUID*)defaultMusicPlayerID
50 |                    musicPlayerClasses:(NSArray<Class<BGMMusicPlayer>>*)musicPlayerClasses
51 |                          userDefaults:(BGMUserDefaults*)defaults;
52 | 
53 | @property (readonly) NSArray<id<BGMMusicPlayer>>* musicPlayers;
54 | 
55 | // The music player currently selected in the preferences menu. BGMDevice is informed when this property
56 | // is changed.
57 | @property id<BGMMusicPlayer> selectedMusicPlayer;
58 | 
59 | @end
60 | 
61 | #pragma clang assume_nonnull end
62 | 
63 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMScriptingBridge.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMScriptingBridge.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016, 2018 Kyle Neideck
21 | //
22 | //  A wrapper around Scripting Bridge's SBApplication that tries to avoid ever launching the application.
23 | //
24 | //  We use Scripting Bridge to communicate with music player apps, which we never want to launch
25 | //  ourselves. But creating an SBApplication for an app, or sending messages/events to an existing one,
26 | //  can launch the app.
27 | //
28 | //  As a workaround, this class has an SBApplication property, application (see below), which is nil
29 | //  unless the music player app is running. That way messages sent while the app is closed are ignored.
30 | //
31 | 
32 | // Local Includes
33 | #import "BGMMusicPlayer.h"
34 | 
35 | // System Includes
36 | #import <Cocoa/Cocoa.h>
37 | #import <ScriptingBridge/ScriptingBridge.h>
38 | 
39 | 
40 | #pragma clang assume_nonnull begin
41 | 
42 | @interface BGMScriptingBridge : NSObject <SBApplicationDelegate>
43 | 
44 | // Only keeps a weak ref to musicPlayer.
45 | - (instancetype) initWithMusicPlayer:(id<BGMMusicPlayer>)musicPlayer;
46 | 
47 | // If the music player application is running, this property is the Scripting Bridge object representing
48 | // it. If not, it's set to nil. Used to send Apple events to the music player app.
49 | @property (readonly) __kindof SBApplication* __nullable application;
50 | 
51 | // macOS 10.14 requires the user's permission to send Apple Events. If the music player that owns
52 | // this object (i.e. the one passed to initWithMusicPlayer) is currently the selected music player
53 | // and the user hasn't already given us permission to send it Apple Events, this method asks the
54 | // user for permission.
55 | - (void) ensurePermission;
56 | 
57 | // SBApplicationDelegate
58 | 
59 | // On 10.11, SBApplicationDelegate.h declares eventDidFail with a non-null return type, but the docs
60 | // specifically say that returning nil is allowed.
61 | #pragma clang diagnostic push
62 | #pragma clang diagnostic ignored "-Wnullability"
63 | - (id __nullable) eventDidFail:(const AppleEvent*)event withError:(NSError*)error;
64 | #pragma clang diagnostic pop
65 | 
66 | @end
67 | 
68 | #pragma clang assume_nonnull end
69 | 
70 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMSpotify.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMSpotify.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Superclass/Protocol Import
24 | #import "BGMMusicPlayer.h"
25 | 
26 | 
27 | @interface BGMSpotify : BGMMusicPlayerBase<BGMMusicPlayer>
28 | 
29 | @end
30 | 
31 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMSwinsian.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMSwinsian.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2018 Kyle Neideck
21 | //
22 | 
23 | // Superclass/Protocol Import
24 | #import "BGMMusicPlayer.h"
25 | 
26 | 
27 | #pragma clang assume_nonnull begin
28 | 
29 | @interface BGMSwinsian : BGMMusicPlayerBase<BGMMusicPlayer>
30 | 
31 | @end
32 | 
33 | #pragma clang assume_nonnull end
34 | 
35 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMSwinsian.m:
--------------------------------------------------------------------------------
  1 | // This file is part of Background Music.
  2 | //
  3 | // Background Music is free software: you can redistribute it and/or
  4 | // modify it under the terms of the GNU General Public License as
  5 | // published by the Free Software Foundation, either version 2 of the
  6 | // License, or (at your option) any later version.
  7 | //
  8 | // Background Music is distributed in the hope that it will be useful,
  9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11 | // GNU General Public License for more details.
 12 | //
 13 | // You should have received a copy of the GNU General Public License
 14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
 15 | 
 16 | //
 17 | //  BGMSwinsian.m
 18 | //  BGMApp
 19 | //
 20 | //  Copyright © 2018 Kyle Neideck
 21 | //
 22 | 
 23 | // Self Include
 24 | #import "BGMSwinsian.h"
 25 | 
 26 | // Auto-generated Scripting Bridge header
 27 | #import "Swinsian.h"
 28 | 
 29 | // Local Includes
 30 | #import "BGMScriptingBridge.h"
 31 | 
 32 | // PublicUtility Includes
 33 | #import "CADebugMacros.h"
 34 | 
 35 | 
 36 | #pragma clang assume_nonnull begin
 37 | 
 38 | @implementation BGMSwinsian {
 39 |     BGMScriptingBridge* scriptingBridge;
 40 | }
 41 | 
 42 | - (instancetype) init {
 43 |     // If you're copying this class, replace the ID string with a new one generated by uuidgen (the
 44 |     // command line tool).
 45 |     NSUUID* musicPlayerID = [BGMMusicPlayerBase makeID:@"B74D18F6-DFF7-4D88-B719-429CFF98CFFA"];
 46 | 
 47 |     if ((self = [super initWithMusicPlayerID:musicPlayerID
 48 |                                         name:@"Swinsian"
 49 |                                     bundleID:@"com.swinsian.Swinsian"])) {
 50 |         scriptingBridge = [[BGMScriptingBridge alloc] initWithMusicPlayer:self];
 51 |     }
 52 |     
 53 |     return self;
 54 | }
 55 | 
 56 | - (SwinsianApplication* __nullable) swinsian {
 57 |     return (SwinsianApplication* __nullable)scriptingBridge.application;
 58 | }
 59 | 
 60 | - (void) wasSelected {
 61 |     [super wasSelected];
 62 |     [scriptingBridge ensurePermission];
 63 | }
 64 | 
 65 | - (BOOL) isRunning {
 66 |     // Note that this will return NO if is self.swinsian is nil (i.e. Swinsian isn't running).
 67 |     return self.swinsian.running;
 68 | }
 69 | 
 70 | // isPlaying and isPaused check self.running first just in case Swinsian is closed but self.swinsian
 71 | // hasn't become nil yet. In that case, reading self.swinsian.playerState could make Scripting
 72 | // Bridge open Swinsian.
 73 | 
 74 | - (BOOL) isPlaying {
 75 |     return self.running && (self.swinsian.playerState == SwinsianPlayerStatePlaying);
 76 | }
 77 | 
 78 | - (BOOL) isPaused {
 79 |     return self.running && (self.swinsian.playerState == SwinsianPlayerStatePaused);
 80 | }
 81 | 
 82 | - (BOOL) pause {
 83 |     // isPlaying checks isRunning, so we don't need to check it here and waste an Apple event.
 84 |     BOOL wasPlaying = self.playing;
 85 |     
 86 |     if (wasPlaying) {
 87 |         DebugMsg("BGMSwinsian::pause: Pausing Swinsian");
 88 |         [self.swinsian pause];
 89 |     }
 90 |     
 91 |     return wasPlaying;
 92 | }
 93 | 
 94 | - (BOOL) unpause {
 95 |     // isPaused checks isRunning, so we don't need to check it here and waste an Apple event.
 96 |     BOOL wasPaused = self.paused;
 97 |     
 98 |     if (wasPaused) {
 99 |         DebugMsg("BGMSwinsian::unpause: Unpausing Swinsian");
100 |         [self.swinsian play];
101 |     }
102 |     
103 |     return wasPaused;
104 | }
105 | 
106 | @end
107 | 
108 | #pragma clang assume_nonnull end
109 | 
110 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMVLC.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMVLC.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Superclass/Protocol Import
24 | #import "BGMMusicPlayer.h"
25 | 
26 | 
27 | @interface BGMVLC : BGMMusicPlayerBase<BGMMusicPlayer>
28 | 
29 | @end
30 | 
31 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMVOX.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMVOX.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Superclass/Protocol Import
24 | #import "BGMMusicPlayer.h"
25 | 
26 | 
27 | @interface BGMVOX : BGMMusicPlayerBase<BGMMusicPlayer>
28 | 
29 | @end
30 | 
31 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMVOX.m:
--------------------------------------------------------------------------------
  1 | // This file is part of Background Music.
  2 | //
  3 | // Background Music is free software: you can redistribute it and/or
  4 | // modify it under the terms of the GNU General Public License as
  5 | // published by the Free Software Foundation, either version 2 of the
  6 | // License, or (at your option) any later version.
  7 | //
  8 | // Background Music is distributed in the hope that it will be useful,
  9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11 | // GNU General Public License for more details.
 12 | //
 13 | // You should have received a copy of the GNU General Public License
 14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
 15 | 
 16 | //
 17 | //  BGMVOX.m
 18 | //  BGMApp
 19 | //
 20 | //  Copyright © 2016-2018 Kyle Neideck
 21 | //
 22 | 
 23 | // Self Include
 24 | #import "BGMVOX.h"
 25 | 
 26 | // Auto-generated Scripting Bridge header
 27 | #import "VOX.h"
 28 | 
 29 | // Local Includes
 30 | #import "BGMScriptingBridge.h"
 31 | 
 32 | // PublicUtility Includes
 33 | #import "CADebugMacros.h"
 34 | 
 35 | 
 36 | #pragma clang assume_nonnull begin
 37 | 
 38 | @implementation BGMVOX {
 39 |     BGMScriptingBridge* scriptingBridge;
 40 | }
 41 | 
 42 | - (instancetype) init {
 43 |     if ((self = [super initWithMusicPlayerID:[BGMMusicPlayerBase makeID:@"26498C5D-C18B-4689-8B41-9DA91A78FFAD"]
 44 |                                         name:@"VOX"
 45 |                                     bundleID:@"com.coppertino.Vox"])) {
 46 |         scriptingBridge = [[BGMScriptingBridge alloc] initWithMusicPlayer:self];
 47 |     }
 48 |     
 49 |     return self;
 50 | }
 51 | 
 52 | - (VoxApplication* __nullable) vox {
 53 |     return (VoxApplication*)scriptingBridge.application;
 54 | }
 55 | 
 56 | - (void) wasSelected {
 57 |     [super wasSelected];
 58 |     [scriptingBridge ensurePermission];
 59 | }
 60 | 
 61 | - (BOOL) isRunning {
 62 |     return self.vox.running;
 63 | }
 64 | 
 65 | // isPlaying and isPaused check self.running first just in case VOX is closed but self.vox hasn't become
 66 | // nil yet. In that case, reading self.vox.playerState could make Scripting Bridge open VOX.
 67 | //
 68 | // VOX's comment for its playerState property says "playing = 1, paused = 0".
 69 | 
 70 | - (BOOL) isPlaying {
 71 |     return self.running && (self.vox.playerState == 1);
 72 | }
 73 | 
 74 | - (BOOL) isPaused {
 75 |     return self.running && (self.vox.playerState == 0);
 76 | }
 77 | 
 78 | - (BOOL) pause {
 79 |     // isPlaying checks isRunning, so we don't need to check it here and waste an Apple event
 80 |     BOOL wasPlaying = self.playing;
 81 |     
 82 |     if (wasPlaying) {
 83 |         DebugMsg("BGMVOX::pause: Pausing VOX");
 84 |         [self.vox pause];
 85 |     }
 86 |     
 87 |     return wasPlaying;
 88 | }
 89 | 
 90 | - (BOOL) unpause {
 91 |     // isPaused checks isRunning, so we don't need to check it here and waste an Apple event
 92 |     BOOL wasPaused = self.paused;
 93 |     
 94 |     if (wasPaused) {
 95 |         DebugMsg("BGMVOX::unpause: Unpausing VOX");
 96 |         [self.vox playpause];
 97 |     }
 98 |     
 99 |     return wasPaused;
100 | }
101 | 
102 | @end
103 | 
104 | #pragma clang assume_nonnull end
105 | 
106 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMiTunes.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMiTunes.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Superclass/Protocol Import
24 | #import "BGMMusicPlayer.h"
25 | 
26 | 
27 | @interface BGMiTunes : BGMMusicPlayerBase<BGMMusicPlayer>
28 | 
29 | // The music player ID (see BGMMusicPlayer.h) used by BGMiTunes instances. (Though BGMApp only ever creates one instance of
30 | // BGMiTunes, sharedMusicPlayerID is exposed so iTunes can be set as the default music player.)
31 | + (NSUUID*) sharedMusicPlayerID;
32 | 
33 | @end
34 | 
35 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/BGMiTunes.m:
--------------------------------------------------------------------------------
  1 | // This file is part of Background Music.
  2 | //
  3 | // Background Music is free software: you can redistribute it and/or
  4 | // modify it under the terms of the GNU General Public License as
  5 | // published by the Free Software Foundation, either version 2 of the
  6 | // License, or (at your option) any later version.
  7 | //
  8 | // Background Music is distributed in the hope that it will be useful,
  9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11 | // GNU General Public License for more details.
 12 | //
 13 | // You should have received a copy of the GNU General Public License
 14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
 15 | 
 16 | //
 17 | //  BGMiTunes.m
 18 | //  BGMApp
 19 | //
 20 | //  Copyright © 2016-2018 Kyle Neideck
 21 | //
 22 | 
 23 | // Self Include
 24 | #import "BGMiTunes.h"
 25 | 
 26 | // Auto-generated Scripting Bridge header
 27 | #import "iTunes.h"
 28 | 
 29 | // Local Includes
 30 | #import "BGMScriptingBridge.h"
 31 | 
 32 | // PublicUtility Includes
 33 | #import "CADebugMacros.h"
 34 | 
 35 | 
 36 | #pragma clang assume_nonnull begin
 37 | 
 38 | @implementation BGMiTunes {
 39 |     BGMScriptingBridge* scriptingBridge;
 40 | }
 41 | 
 42 | + (NSUUID*) sharedMusicPlayerID {
 43 |     NSUUID* __nullable musicPlayerID = [[NSUUID alloc] initWithUUIDString:@"7B62B5BF-CF90-4938-84E3-F16DEDC3F608"];
 44 |     NSAssert(musicPlayerID, @"BGMiTunes::sharedMusicPlayerID: !musicPlayerID");
 45 |     return (NSUUID*)musicPlayerID;
 46 | }
 47 | 
 48 | - (instancetype) init {
 49 |     if ((self = [super initWithMusicPlayerID:[BGMiTunes sharedMusicPlayerID]
 50 |                                         name:@"iTunes"
 51 |                                     bundleID:@"com.apple.iTunes"])) {
 52 |         scriptingBridge = [[BGMScriptingBridge alloc] initWithMusicPlayer:self];
 53 |     }
 54 |     
 55 |     return self;
 56 | }
 57 | 
 58 | - (iTunesApplication* __nullable) iTunes {
 59 |     return (iTunesApplication*)scriptingBridge.application;
 60 | }
 61 | 
 62 | - (void) wasSelected {
 63 |     [super wasSelected];
 64 |     [scriptingBridge ensurePermission];
 65 | }
 66 | 
 67 | - (BOOL) isRunning {
 68 |     return self.iTunes.running;
 69 | }
 70 | 
 71 | // isPlaying and isPaused check self.running first just in case iTunes is closed but self.iTunes hasn't become
 72 | // nil yet. In that case, reading self.iTunes.playerState could make Scripting Bridge open iTunes.
 73 | 
 74 | - (BOOL) isPlaying {
 75 |     return self.running && (self.iTunes.playerState == iTunesEPlSPlaying);
 76 | }
 77 | 
 78 | - (BOOL) isPaused {
 79 |     return self.running && (self.iTunes.playerState == iTunesEPlSPaused);
 80 | }
 81 | 
 82 | - (BOOL) pause {
 83 |     // isPlaying checks isRunning, so we don't need to check it here and waste an Apple event
 84 |     BOOL wasPlaying = self.playing;
 85 |     
 86 |     if (wasPlaying) {
 87 |         DebugMsg("BGMiTunes::pause: Pausing iTunes");
 88 |         [self.iTunes pause];
 89 |     }
 90 |     
 91 |     return wasPlaying;
 92 | }
 93 | 
 94 | - (BOOL) unpause {
 95 |     // isPaused checks isRunning, so we don't need to check it here and waste an Apple event
 96 |     BOOL wasPaused = self.paused;
 97 |     
 98 |     if (wasPaused) {
 99 |         DebugMsg("BGMiTunes::unpause: Unpausing iTunes");
100 |         [self.iTunes playpause];
101 |     }
102 |     
103 |     return wasPaused;
104 | }
105 | 
106 | @end
107 | 
108 | #pragma clang assume_nonnull end
109 | 
110 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/Hermes.h:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Hermes.h
 3 |  *
 4 |  * Generated with
 5 |  * sdef /Applications/Hermes.app | sdp -fh --basename Hermes
 6 |  */
 7 | 
 8 | #import <AppKit/AppKit.h>
 9 | #import <ScriptingBridge/ScriptingBridge.h>
10 | 
11 | 
12 | @class HermesApplication, HermesSong, HermesStation;
13 | 
14 | // Legal player states
15 | enum HermesPlayerStates {
16 | 	HermesPlayerStatesStopped = 'stop' /* Player is stopped */,
17 | 	HermesPlayerStatesPlaying = 'play' /* Player is playing */,
18 | 	HermesPlayerStatesPaused = 'paus' /* Player is paused */
19 | };
20 | typedef enum HermesPlayerStates HermesPlayerStates;
21 | 
22 | 
23 | 
24 | /*
25 |  * Hermes Suite
26 |  */
27 | 
28 | // The Pandora player.
29 | @interface HermesApplication : SBApplication
30 | 
31 | - (SBElementArray<HermesStation *> *) stations;
32 | 
33 | @property NSInteger playbackVolume;  // The current playback volume (0–100).
34 | @property HermesPlayerStates playbackState;  // The current playback state.
35 | @property (readonly) double playbackPosition;  // The current song’s playback position, in seconds.
36 | @property (readonly) double currentSongDuration;  // The duration (length) of the current song, in seconds.
37 | @property (copy) HermesStation *currentStation;  // The currently selected Pandora station.
38 | @property (copy, readonly) HermesSong *currentSong;  // The currently playing (or paused) Pandora song (WARNING: This is an invalid reference in current versions of Hermes; you must access the current song’s properties individually or as a group directly instead.)
39 | 
40 | - (void) playpause;  // Play the current song if it is paused; pause the current song if it is playing.
41 | - (void) pause;  // Pause the currently playing song.
42 | - (void) play;  // Resume playing the current song.
43 | - (void) nextSong;  // Skip to the next song on the current station.
44 | - (void) thumbsUp;  // Tell Pandora you like the current song.
45 | - (void) thumbsDown;  // Tell Pandora you don’t like the current song.
46 | - (void) tiredOfSong;  // Tell Pandora you’re tired of the current song.
47 | - (void) increaseVolume;  // Increase the playback volume.
48 | - (void) decreaseVolume;  // Decrease the playback volume.
49 | - (void) maximizeVolume;  // Set the playback volume to its maximum level.
50 | - (void) mute;  // Mutes playback, saving the current volume level.
51 | - (void) unmute;  // Restores the volume to the level prior to muting.
52 | 
53 | @end
54 | 
55 | // A Pandora song (track).
56 | @interface HermesSong : SBObject
57 | 
58 | @property (copy, readonly) NSString *title;  // The song’s title.
59 | @property (copy, readonly) NSString *artist;  // The song’s artist.
60 | @property (copy, readonly) NSString *album;  // The song’s album.
61 | @property (copy, readonly) NSString *artworkURL;  // An image URL for the album’s cover artwork.
62 | @property (readonly) NSInteger rating;  // The song’s numeric rating.
63 | @property (copy, readonly) NSString *albumURL;  // A Pandora URL for more information on the album.
64 | @property (copy, readonly) NSString *artistURL;  // A Pandora URL for more information on the artist.
65 | @property (copy, readonly) NSString *trackURL;  // A Pandora URL for more information on the track.
66 | 
67 | 
68 | @end
69 | 
70 | // A Pandora station.
71 | @interface HermesStation : SBObject
72 | 
73 | @property (copy, readonly) NSString *name;  // The station’s name.
74 | @property (copy, readonly) NSString *stationID;  // The station’s ID.
75 | 
76 | 
77 | @end
78 | 
79 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/Spotify.h:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Spotify.h
 3 |  *
 4 |  * Generated with
 5 |  * sdef /Applications/Spotify.app | sdp -fh --basename Spotify
 6 |  */
 7 | 
 8 | #import <AppKit/AppKit.h>
 9 | #import <ScriptingBridge/ScriptingBridge.h>
10 | 
11 | 
12 | @class SpotifyApplication, SpotifyTrack, SpotifyApplication;
13 | 
14 | enum SpotifyEPlS {
15 | 	SpotifyEPlSStopped = 'kPSS',
16 | 	SpotifyEPlSPlaying = 'kPSP',
17 | 	SpotifyEPlSPaused = 'kPSp'
18 | };
19 | typedef enum SpotifyEPlS SpotifyEPlS;
20 | 
21 | 
22 | 
23 | /*
24 |  * Spotify Suite
25 |  */
26 | 
27 | // The Spotify application.
28 | @interface SpotifyApplication : SBApplication
29 | 
30 | @property (copy, readonly) SpotifyTrack *currentTrack;  // The current playing track.
31 | @property NSInteger soundVolume;  // The sound output volume (0 = minimum, 100 = maximum)
32 | @property (readonly) SpotifyEPlS playerState;  // Is Spotify stopped, paused, or playing?
33 | @property double playerPosition;  // The player’s position within the currently playing track in seconds.
34 | @property (readonly) BOOL repeatingEnabled;  // Is repeating enabled in the current playback context?
35 | @property BOOL repeating;  // Is repeating on or off?
36 | @property (readonly) BOOL shufflingEnabled;  // Is shuffling enabled in the current playback context?
37 | @property BOOL shuffling;  // Is shuffling on or off?
38 | 
39 | - (void) nextTrack;  // Skip to the next track.
40 | - (void) previousTrack;  // Skip to the previous track.
41 | - (void) playpause;  // Toggle play/pause.
42 | - (void) pause;  // Pause playback.
43 | - (void) play;  // Resume playback.
44 | - (void) playTrack:(NSString *)x inContext:(NSString *)inContext;  // Start playback of a track in the given context.
45 | 
46 | @end
47 | 
48 | // A Spotify track.
49 | @interface SpotifyTrack : SBObject
50 | 
51 | @property (copy, readonly) NSString *artist;  // The artist of the track.
52 | @property (copy, readonly) NSString *album;  // The album of the track.
53 | @property (readonly) NSInteger discNumber;  // The disc number of the track.
54 | @property (readonly) NSInteger duration;  // The length of the track in seconds.
55 | @property (readonly) NSInteger playedCount;  // The number of times this track has been played.
56 | @property (readonly) NSInteger trackNumber;  // The index of the track in its album.
57 | @property (readonly) BOOL starred;  // Is the track starred?
58 | @property (readonly) NSInteger popularity;  // How popular is this track? 0-100
59 | - (NSString *) id;  // The ID of the item.
60 | @property (copy, readonly) NSString *name;  // The name of the track.
61 | @property (copy, readonly) NSImage *artwork;  // The track's album cover.
62 | @property (copy, readonly) NSString *albumArtist;  // That album artist of the track.
63 | @property (copy) NSString *spotifyUrl;  // The URL of the track.
64 | 
65 | 
66 | @end
67 | 
68 | 
69 | 
70 | /*
71 |  * Standard Suite
72 |  */
73 | 
74 | // The application's top level scripting object.
75 | @interface SpotifyApplication (StandardSuite)
76 | 
77 | @property (copy, readonly) NSString *name;  // The name of the application.
78 | @property (readonly) BOOL frontmost;  // Is this the frontmost (active) application?
79 | @property (copy, readonly) NSString *version;  // The version of the application.
80 | 
81 | @end
82 | 
83 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Music Players/VOX.h:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * VOX.h
 3 |  *
 4 |  * Generated with
 5 |  * sdef /Applications/VOX.app | sdp -fh --basename VOX
 6 |  */
 7 | 
 8 | #import <AppKit/AppKit.h>
 9 | #import <ScriptingBridge/ScriptingBridge.h>
10 | 
11 | 
12 | @class VoxApplication, VoxApplication;
13 | 
14 | 
15 | 
16 | /*
17 |  * Standard Suite
18 |  */
19 | 
20 | // The application's top level scripting object.
21 | @interface VoxApplication : SBApplication
22 | 
23 | @property (copy, readonly) NSString *name;  // The name of the application.
24 | @property (readonly) BOOL frontmost;  // Is this the frontmost (active) application?
25 | @property (copy, readonly) NSString *version;  // The version of the application.
26 | 
27 | - (void) quit;  // Quit an application.
28 | - (void) pause;  // Pause playback.
29 | - (void) play;  // Begin playback.
30 | - (void) playpause;  // Toggle playback between playing and paused.
31 | - (void) next;  // Skip to the next track in the playlist.
32 | - (void) previous;  // Skip to the previous track in the playlist.
33 | - (void) shuffle;  // Shuffle the tracks in the playlist.
34 | - (void) playUrl:(NSString *)x;  // Play specified URL.
35 | - (void) addUrl:(NSString *)x;  // Add specified URL to playlist
36 | - (void) rewindForward;  // Rewind current track forward.
37 | - (void) rewindForwardFast;  // Rewind current track forward fast.
38 | - (void) rewindBackward;  // Rewind current track backward.
39 | - (void) rewindBackwardFast;  // Rewind current track backward fast.
40 | - (void) increasVolume;  // Increase volume.
41 | - (void) decreaseVolume;  // Decrease volume.
42 | - (void) showHidePlaylist;  // Show/Hide playlist.
43 | 
44 | @end
45 | 
46 | 
47 | 
48 | /*
49 |  * Vox Suite
50 |  */
51 | 
52 | // The application's top-level scripting object.
53 | @interface VoxApplication (VoxSuite)
54 | 
55 | @property (copy, readonly) NSData *tiffArtworkData;  // Current track artwork data in TIFF format.
56 | @property (copy, readonly) NSImage *artworkImage;  // Current track artwork as an image.
57 | @property (readonly) NSInteger playerState;  // Player state (playing = 1, paused = 0)
58 | @property (copy, readonly) NSString *track;  // Current track title.
59 | @property (copy, readonly) NSString *trackUrl;  // Current track URL.
60 | @property (copy, readonly) NSString *artist;  // Current track artist.
61 | @property (copy, readonly) NSString *albumArtist;  // Current track album artist.
62 | @property (copy, readonly) NSString *album;  // Current track album.
63 | @property (copy, readonly) NSString *uniqueID;  // Unique identifier for the current track.
64 | @property double currentTime;  // The current playback position.
65 | @property (readonly) double totalTime;  // The total time of the currently playing track.
66 | @property double playerVolume;  // Player volume (0.0 to 1.0)
67 | @property NSInteger repeatState;  // Player repeat state (none = 0, repeat one = 1, repeat all = 2)
68 | 
69 | @end
70 | 
71 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Preferences/BGMAboutPanel.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMAboutPanel.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | //  This class manages the "About Background Music" window.
23 | //
24 | 
25 | // System Includes
26 | #import <Cocoa/Cocoa.h>
27 | 
28 | 
29 | NS_ASSUME_NONNULL_BEGIN
30 | 
31 | @interface BGMAboutPanel : NSObject
32 | 
33 | - (instancetype)initWithPanel:(NSPanel*)inAboutPanel licenseView:(NSTextView*)inLicenseView;
34 | - (void) show;
35 | 
36 | @end
37 | 
38 | 
39 | @interface BGMLinkField : NSTextField
40 | @end
41 | 
42 | NS_ASSUME_NONNULL_END
43 | 
44 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Preferences/BGMAutoPauseMusicPrefs.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMAutoPauseMusicPrefs.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Local Includes
24 | #import "BGMAudioDeviceManager.h"
25 | #import "BGMMusicPlayers.h"
26 | 
27 | // System Includes
28 | #import <Cocoa/Cocoa.h>
29 | 
30 | 
31 | #pragma clang assume_nonnull begin
32 | 
33 | @interface BGMAutoPauseMusicPrefs : NSObject
34 | 
35 | - (id) initWithPreferencesMenu:(NSMenu*)inPrefsMenu
36 |                   audioDevices:(BGMAudioDeviceManager*)inAudioDevices
37 |                   musicPlayers:(BGMMusicPlayers*)inMusicPlayers;
38 | 
39 | @end
40 | 
41 | #pragma clang assume_nonnull end 
42 | 
43 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Preferences/BGMPreferencesMenu.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMPreferencesMenu.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016, 2018, 2019 Kyle Neideck
21 | //
22 | //  Handles the preferences menu UI. The user's preference changes are often passed directly to the driver rather
23 | //  than to other BGMApp classes.
24 | //
25 | 
26 | // Local Includes
27 | #import "BGMAudioDeviceManager.h"
28 | #import "BGMMusicPlayers.h"
29 | #import "BGMStatusBarItem.h"
30 | #import "BGMUserDefaults.h"
31 | 
32 | // System Includes
33 | #import <Cocoa/Cocoa.h>
34 | 
35 | 
36 | NS_ASSUME_NONNULL_BEGIN
37 | 
38 | @interface BGMPreferencesMenu : NSObject
39 | 
40 | - (id) initWithBGMMenu:(NSMenu*)inBGMMenu
41 |           audioDevices:(BGMAudioDeviceManager*)inAudioDevices
42 |           musicPlayers:(BGMMusicPlayers*)inMusicPlayers
43 |          statusBarItem:(BGMStatusBarItem*)inStatusBarItem
44 |             aboutPanel:(NSPanel*)inAboutPanel
45 |  aboutPanelLicenseView:(NSTextView*)inAboutPanelLicenseView
46 |           userDefaults:(BGMUserDefaults*)inUserDefaults;
47 | 
48 | @end
49 | 
50 | NS_ASSUME_NONNULL_END
51 | 
52 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Scripting/BGMASApplication.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMASApplication.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2021 Marcus Wu
21 | //  Copyright © 2021 Kyle Neideck
22 | //
23 | //  An AppleScript class for volume and pan settings for running applications.
24 | //
25 | 
26 | 
27 | // Local Includes
28 | #import "BGMAppVolumesController.h"
29 | 
30 | // System Includes
31 | #import <Foundation/Foundation.h>
32 | #import <Cocoa/Cocoa.h>
33 | 
34 | 
35 | NS_ASSUME_NONNULL_BEGIN
36 | 
37 | @interface BGMASApplication : NSObject
38 | 
39 | - (instancetype) initWithApplication:(NSRunningApplication*)app
40 |                           volumeController:(BGMAppVolumesController*)volumeController
41 |                      parentSpecifier:(NSScriptObjectSpecifier* __nullable)parentSpecifier
42 |                                index:(int)i;
43 | 
44 | @property (readonly) NSString* name;
45 | @property (readonly) NSString* bundleID;
46 | @property int volume;
47 | @property int pan;
48 | @end
49 | 
50 | NS_ASSUME_NONNULL_END
51 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Scripting/BGMASApplication.m:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMASApplication.m
18 | //  BGMApp
19 | //
20 | //  Copyright © 2021 Marcus Wu
21 | //  Copyright © 2021 Kyle Neideck
22 | //
23 | 
24 | // Self Include
25 | #import "BGMASApplication.h"
26 | 
27 | // Local Includes
28 | #import "BGM_Types.h"
29 | 
30 | @implementation BGMASApplication {
31 |     NSScriptObjectSpecifier* parentSpecifier;
32 |     NSRunningApplication *application;
33 |     BGMAppVolumesController* appVolumesController;
34 |     int index;
35 | }
36 | 
37 | - (instancetype) initWithApplication:(NSRunningApplication*)app
38 |                           volumeController:(BGMAppVolumesController*)volumeController
39 |                      parentSpecifier:(NSScriptObjectSpecifier* __nullable)parent
40 |                                index:(int)i {
41 |     if ((self = [super init])) {
42 |         parentSpecifier = parent;
43 |         application = app;
44 |         appVolumesController = volumeController;
45 |         index = i;
46 |     }
47 | 
48 |     return self;
49 | }
50 | 
51 | - (NSString*) name {
52 |     return [NSString stringWithFormat:@"%@", [application localizedName]];
53 | }
54 | 
55 | - (NSString*) bundleID {
56 |     return [NSString stringWithFormat:@"%@", [application bundleIdentifier]];
57 | }
58 | 
59 | - (int) volume {
60 |     return [appVolumesController getVolumeAndPanForApp:application].volume;
61 | }
62 | 
63 | - (void) setVolume:(int)vol {
64 |     BGMAppVolumeAndPan volume = {
65 |         .volume = vol,
66 |         .pan = kAppPanNoValue
67 |     };
68 |     [appVolumesController setVolumeAndPan:volume forApp:application];
69 | }
70 | 
71 | - (int) pan {
72 |     return [appVolumesController getVolumeAndPanForApp:application].pan;
73 | }
74 | 
75 | - (void) setPan:(int)pan {
76 |     BGMAppVolumeAndPan thePan = {
77 |         .volume = -1,
78 |         .pan = pan
79 |     };
80 |     [appVolumesController setVolumeAndPan:thePan forApp:application];
81 | }
82 | 
83 | - (NSScriptObjectSpecifier* __nullable) objectSpecifier {
84 |     NSScriptClassDescription* parentClassDescription = [parentSpecifier keyClassDescription];
85 |     return [[NSNameSpecifier alloc] initWithContainerClassDescription:parentClassDescription
86 |                                                    containerSpecifier:parentSpecifier
87 |                                                                   key:@"applications"
88 |                                                                  name:self.name];
89 | }
90 | 
91 | @end
92 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Scripting/BGMASOutputDevice.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMASOutputDevice.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2017 Kyle Neideck
21 | //
22 | //  An AppleScript class for the output devices that can be selected in the preferences menu.
23 | //
24 | 
25 | // Local Includes
26 | #import "BGMAudioDeviceManager.h"
27 | 
28 | // System Includes
29 | #import <Foundation/Foundation.h>
30 | 
31 | 
32 | #pragma clang assume_nonnull begin
33 | 
34 | @interface BGMASOutputDevice : NSObject
35 | 
36 | - (instancetype) initWithAudioObjectID:(AudioObjectID)objID
37 |                           audioDevices:(BGMAudioDeviceManager*)devices
38 |                        parentSpecifier:(NSScriptObjectSpecifier* __nullable)parentSpecifier;
39 | 
40 | @property (readonly) NSString* name;
41 | @property BOOL selected;  // is this the device to be used for audio output?
42 | 
43 | @end
44 | 
45 | #pragma clang assume_nonnull end
46 | 
47 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Scripting/BGMASOutputDevice.mm:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMASOutputDevice.mm
18 | //  BGMApp
19 | //
20 | //  Copyright © 2017 Kyle Neideck
21 | //
22 | 
23 | // Self Include
24 | #import "BGMASOutputDevice.h"
25 | 
26 | // Local Includes
27 | #import "BGMAudioDevice.h"
28 | 
29 | // PublicUtility Includes
30 | #import "CADebugMacros.h"
31 | 
32 | 
33 | #pragma clang assume_nonnull begin
34 | 
35 | @implementation BGMASOutputDevice {
36 |     NSScriptObjectSpecifier* parentSpecifier;
37 |     BGMAudioDevice device;
38 |     BGMAudioDeviceManager* audioDevices;
39 | }
40 | 
41 | - (instancetype) initWithAudioObjectID:(AudioObjectID)objID
42 |                           audioDevices:(BGMAudioDeviceManager*)devices
43 |                        parentSpecifier:(NSScriptObjectSpecifier* __nullable)parent {
44 |     if ((self = [super init])) {
45 |         parentSpecifier = parent;
46 |         device = objID;
47 |         audioDevices = devices;
48 |     }
49 | 
50 |     return self;
51 | }
52 | 
53 | - (NSString*) name {
54 |     return (NSString*)CFBridgingRelease(device.CopyName());
55 | }
56 | 
57 | - (BOOL) selected {
58 |     return [audioDevices isOutputDevice:device];
59 | }
60 | 
61 | - (void) setSelected:(BOOL)selected {
62 |     if (selected && ![self selected]) {
63 |         DebugMsg("BGMASOutputDevice::setSelected: A script is setting output device to %s",
64 |                  [[self name] UTF8String]);
65 | 
66 |         NSError* err = [audioDevices setOutputDeviceWithID:device revertOnFailure:YES];
67 |         (void)err;  // TODO: Return an error to the script somehow if this isn't nil. Also, should
68 |                     //       we return an error if the script tries to set this property to false?     
69 |     }
70 | }
71 | 
72 | - (NSScriptObjectSpecifier* __nullable) objectSpecifier {
73 |     NSScriptClassDescription* parentClassDescription = [parentSpecifier keyClassDescription];
74 |     return [[NSNameSpecifier alloc] initWithContainerClassDescription:parentClassDescription
75 |                                                    containerSpecifier:parentSpecifier
76 |                                                                   key:@"output devices"
77 |                                                                  name:self.name];
78 | }
79 | 
80 | @end
81 | 
82 | #pragma clang assume_nonnull end
83 | 
84 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/Scripting/BGMAppDelegate+AppleScript.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMAppDelegate+AppleScript.h
18 | //  BGMApp
19 | //
20 | //  Copyright © 2017 Kyle Neideck
21 | //  Copyright © 2021 Marcus Wu
22 | //
23 | 
24 | #import "BGMAppDelegate.h"
25 | 
26 | // Local Includes
27 | #import "BGMAudioDeviceManager.h"
28 | #import "BGMAppVolumesController.h"
29 | 
30 | // Local Includes
31 | #import "BGMASOutputDevice.h"
32 | #import "BGMASApplication.h"
33 | 
34 | // System Includes
35 | #import <Foundation/Foundation.h>
36 | 
37 | 
38 | #pragma clang assume_nonnull begin
39 | 
40 | @interface BGMAppDelegate (AppleScript)
41 | 
42 | - (BOOL) application:(NSApplication*)sender delegateHandlesKey:(NSString*)key;
43 | 
44 | @property BGMASOutputDevice* selectedOutputDevice;
45 | @property (readonly) NSArray<BGMASOutputDevice*>* outputDevices;
46 | @property double mainVolume;
47 | @property (readonly) NSArray<BGMASApplication*>* applications;
48 | 
49 | @end
50 | 
51 | #pragma clang assume_nonnull end
52 | 
53 | 


--------------------------------------------------------------------------------
/BGMApp/BGMApp/main.m:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  main.m
18 | //  BGMApp
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // System Includes
24 | #import <Cocoa/Cocoa.h>
25 | 
26 | 
27 | int main(int argc, const char * argv[]) {
28 |     // Start BGMApp.
29 |     return NSApplicationMain(argc, argv);
30 | }
31 | 
32 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UITests/BGMApp.h:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * BGMApp.h
 3 |  *
 4 |  * Generated with
 5 |  * sdef "/Applications/Background Music.app" | sdp -fh --basename BGMApp
 6 |  */
 7 | 
 8 | #import <AppKit/AppKit.h>
 9 | #import <ScriptingBridge/ScriptingBridge.h>
10 | 
11 | 
12 | @class BGMAppOutputDevice, BGMAppApplication;
13 | 
14 | 
15 | 
16 | /*
17 |  * Background Music
18 |  */
19 | 
20 | // A hardware device that can play audio
21 | @interface BGMAppOutputDevice : SBObject
22 | 
23 | @property (copy, readonly) NSString *name;  // The name of the output device.
24 | @property BOOL selected;  // Is this the device to be used for audio output?
25 | 
26 | @end
27 | 
28 | // The application program
29 | @interface BGMAppApplication : SBApplication
30 | 
31 | - (SBElementArray<BGMAppOutputDevice *> *) outputDevices;
32 | 
33 | @property (copy) BGMAppOutputDevice *selectedOutputDevice;  // The device to be used for audio output
34 | 
35 | @end
36 | 
37 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UITests/BGMAppUITests-Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>CFBundleDevelopmentRegion</key>
 6 | 	<string>en</string>
 7 | 	<key>CFBundleExecutable</key>
 8 | 	<string>$(EXECUTABLE_NAME)</string>
 9 | 	<key>CFBundleIdentifier</key>
10 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11 | 	<key>CFBundleInfoDictionaryVersion</key>
12 | 	<string>6.0</string>
13 | 	<key>CFBundleName</key>
14 | 	<string>$(PRODUCT_NAME)</string>
15 | 	<key>CFBundlePackageType</key>
16 | 	<string>BNDL</string>
17 | 	<key>CFBundleShortVersionString</key>
18 | 	<string>1.0</string>
19 | 	<key>CFBundleVersion</key>
20 | 	<string>1</string>
21 | </dict>
22 | </plist>
23 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UITests/skip-ui-tests.py:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env python3
 2 | 
 3 | # This file is part of Background Music.
 4 | #
 5 | # Background Music is free software: you can redistribute it and/or
 6 | # modify it under the terms of the GNU General Public License as
 7 | # published by the Free Software Foundation, either version 2 of the
 8 | # License, or (at your option) any later version.
 9 | #
10 | # Background Music is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with Background Music. If not, see <http://www.gnu.org/licenses/>.
17 | 
18 | #
19 | # skip-ui-tests.py
20 | # BGMAppUITests
21 | #
22 | # Copyright (c) 2017, 2024 Kyle Neideck
23 | #
24 | # Disables the UI tests. This is mainly useful on CI systems that don't support UI tests.
25 | #
26 | 
27 | import xml.etree.ElementTree as ET
28 | 
29 | SCHEME_FILE = "BGMApp/BGMApp.xcodeproj/xcshareddata/xcschemes/Background Music.xcscheme"
30 | UI_REF_XPATH = ".//BuildableReference[@BlueprintName='BGMAppUITests']/.."
31 | 
32 | # Parse the Xcode scheme.
33 | tree = ET.parse(SCHEME_FILE)
34 | 
35 | # Set the TestableReference for the UI tests to skipped.
36 | tree.getroot().findall(UI_REF_XPATH)[0].set("skipped", "YES")
37 | 
38 | # Save the scheme.
39 | tree.write(SCHEME_FILE)
40 | 
41 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UnitTests/BGMAppUnitTests-Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>CFBundleDevelopmentRegion</key>
 6 | 	<string>en</string>
 7 | 	<key>CFBundleExecutable</key>
 8 | 	<string>$(EXECUTABLE_NAME)</string>
 9 | 	<key>CFBundleIdentifier</key>
10 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11 | 	<key>CFBundleInfoDictionaryVersion</key>
12 | 	<string>6.0</string>
13 | 	<key>CFBundleName</key>
14 | 	<string>$(PRODUCT_NAME)</string>
15 | 	<key>CFBundlePackageType</key>
16 | 	<string>BNDL</string>
17 | 	<key>CFBundleShortVersionString</key>
18 | 	<string>1.0</string>
19 | 	<key>CFBundleVersion</key>
20 | 	<string>1</string>
21 | </dict>
22 | </plist>
23 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioDevice.cpp:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  MockAudioDevice.cpp
18 | //  BGMAppUnitTests
19 | //
20 | //  Copyright © 2020 Kyle Neideck
21 | //
22 | 
23 | // Self Include
24 | #include "MockAudioDevice.h"
25 | 
26 | // BGM Includes
27 | #include "BGM_Types.h"
28 | 
29 | // STL Includes
30 | #include <functional>
31 | 
32 | 
33 | MockAudioDevice::MockAudioDevice(const std::string& inUID)
34 | :
35 |     mUID(inUID),
36 |     mNominalSampleRate(44100.0),
37 |     mIOBufferSize(512),
38 |     MockAudioObject(static_cast<AudioObjectID>(std::hash<std::string>{}(inUID)))
39 | {
40 | }
41 | 
42 | CACFString MockAudioDevice::GetPlayerBundleID() const
43 | {
44 |     if(mUID != kBGMDeviceUID)
45 |     {
46 |         throw "Only BGMDevice has kAudioDeviceCustomPropertyMusicPlayerBundleID";
47 |     }
48 | 
49 |     return mPlayerBundleID;
50 | }
51 | 
52 | void MockAudioDevice::SetPlayerBundleID(const CACFString& inPlayerBundleID)
53 | {
54 |     if(mUID != kBGMDeviceUID)
55 |     {
56 |         throw "Only BGMDevice has kAudioDeviceCustomPropertyMusicPlayerBundleID";
57 |     }
58 | 
59 |     mPlayerBundleID = inPlayerBundleID;
60 | }
61 | 
62 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioDevice.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  MockAudioObject.h
18 | //  BGMAppUnitTests
19 | //
20 | //  Copyright © 2020 Kyle Neideck
21 | //
22 | 
23 | #ifndef BGMAppUnitTests__MockAudioDevice
24 | #define BGMAppUnitTests__MockAudioDevice
25 | 
26 | // Superclass Includes
27 | #include "MockAudioObject.h"
28 | 
29 | // STL Includes
30 | #include <string>
31 | 
32 | 
33 | /*!
34 |  * A mock audio device in our mock CoreAudio HAL. In the HAL's API class hierarchy, the base class
35 |  * for audio devices, kAudioDeviceClassID, is the audio objects class, kAudioObjectClassID.
36 |  *
37 |  * The unit tests generally use instances of this class to verify the HAL is being queried correctly
38 |  * and to control the responses that the code they're testing will receive from the mock HAL.
39 |  */
40 | class MockAudioDevice
41 | :
42 |         public MockAudioObject
43 | {
44 | 
45 | public:
46 |     MockAudioDevice(const std::string& inUID);
47 | 
48 |     /*!
49 |      * @return This device's music player bundle ID property.
50 |      * @throws If this device isn't a mock of BGMDevice.
51 |      */
52 |     CACFString GetPlayerBundleID() const;
53 |     /*!
54 |      * Set this device's music player bundle ID property.
55 |      * @throws If this device isn't a mock of BGMDevice.
56 |      */
57 |     void SetPlayerBundleID(const CACFString& inPlayerBundleID);
58 | 
59 |     /*!
60 |      * The device's UID. The UID is a persistent token used to identify a particular audio device
61 |      * across boot sessions.
62 |      */
63 |     const std::string mUID;
64 |     Float64 mNominalSampleRate;
65 |     UInt32 mIOBufferSize;
66 | 
67 | private:
68 |     CACFString mPlayerBundleID { "" };
69 | 
70 | };
71 | 
72 | #endif /* BGMAppUnitTests__MockAudioDevice */
73 | 
74 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObject.cpp:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  MockAudioObject.cpp
18 | //  BGMAppUnitTests
19 | //
20 | //  Copyright © 2020 Kyle Neideck
21 | //
22 | 
23 | // Self Include
24 | #include "MockAudioObject.h"
25 | 
26 | 
27 | MockAudioObject::MockAudioObject(AudioObjectID inAudioObjectID)
28 | :
29 |         mAudioObjectID(inAudioObjectID)
30 | {
31 | }
32 | 
33 | AudioObjectID MockAudioObject::GetObjectID() const
34 | {
35 |     return mAudioObjectID;
36 | }
37 | 
38 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObject.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  MockAudioObject.h
18 | //  BGMAppUnitTests
19 | //
20 | //  Copyright © 2020 Kyle Neideck
21 | //
22 | 
23 | #ifndef BGMAppUnitTests__MockAudioObject
24 | #define BGMAppUnitTests__MockAudioObject
25 | 
26 | // PublicUtility Includes
27 | #include "CACFString.h"
28 | 
29 | // STL Includes
30 | #include <set>
31 | 
32 | // System Includes
33 | #include <CoreAudio/CoreAudio.h>
34 | 
35 | 
36 | /*!
37 |  * The base class for mock audio objects in our mock CoreAudio HAL. Maps to kAudioObjectClassID
38 |  * (AudioHardwareBase.h) in the HAL's API class hierarchy.
39 |  */
40 | class MockAudioObject
41 | {
42 | 
43 | public:
44 |     MockAudioObject(AudioObjectID inAudioObjectID);
45 |     virtual ~MockAudioObject() = default;
46 | 
47 |     AudioObjectID GetObjectID() const;
48 | 
49 |     /*!
50 |      * The properties that callers have added listeners for (and haven't since removed). See
51 |      * CAHALAudioObject::AddPropertyListener and CAHALAudioObject::RemovePropertyListener.
52 |      */
53 |     std::set<AudioObjectPropertySelector> mPropertiesWithListeners;
54 | 
55 | private:
56 |     AudioObjectID mAudioObjectID;
57 | 
58 | };
59 | 
60 | #endif /* BGMAppUnitTests__MockAudioObject */
61 | 
62 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObjects.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  MockAudioObjects.h
18 | //  BGMAppUnitTests
19 | //
20 | //  Copyright © 2020 Kyle Neideck
21 | //
22 | 
23 | #ifndef BGMAppUnitTests__MockAudioObjects
24 | #define BGMAppUnitTests__MockAudioObjects
25 | 
26 | // Local Includes
27 | #include "MockAudioObject.h"
28 | #include "MockAudioDevice.h"
29 | 
30 | // STL Includes
31 | #include <map>
32 | #include <memory>
33 | #include <string>
34 | 
35 | // System Includes
36 | #include <CoreAudio/CoreAudio.h>
37 | 
38 | 
39 | class MockAudioObjects
40 | {
41 | 
42 | public:
43 |     /*!
44 |      * Create a mock audio device in the mock CoreAudio HAL.
45 |      *
46 |      * The mock device will then be accessible using GetAudioObject and GetAudioDevice. The
47 |      * Mock_CAHAL* implementations will access the mock device when they query the mock HAL.
48 |      *
49 |      * Unit tests can check the mock device to verify the code they're testing has called the mocked
50 |      * CAHAL classes correctly. They can also modify the mock device to control the Mock_CAHAL*
51 |      * implementations, e.g. to have CAHALAudioDevice::IsAlive return false so the test can cover
52 |      * the case where a device is being removed from the system.
53 |      *
54 |      * @param inUID The UID string to give the device. The UID is a persistent token used to
55 |      *              identify a particular audio device across boot sessions.
56 |      * @return The mock device.
57 |      */
58 |     static std::shared_ptr<MockAudioDevice> CreateMockDevice(const std::string& inUID);
59 | 
60 |     /*!
61 |      * Remove all mock audio objects from the mock HAL. (Currently, mock devices are the only mock
62 |      * objects that can be created.)
63 |      */
64 |     static void DestroyMocks();
65 | 
66 |     /*! Get a mock audio object by its ID. */
67 |     static std::shared_ptr<MockAudioObject> GetAudioObject(AudioObjectID inAudioObjectID);
68 | 
69 |     /*! Get a mock audio device by its ID. */
70 |     static std::shared_ptr<MockAudioDevice> GetAudioDevice(AudioObjectID inAudioDeviceID);
71 |     /*! Get a mock audio device by its UID. */
72 |     static std::shared_ptr<MockAudioDevice> GetAudioDevice(const std::string& inUID);
73 |     /*! Get a mock audio device by its UID. */
74 |     static std::shared_ptr<MockAudioDevice> GetAudioDevice(CFStringRef inUID);
75 | 
76 | private:
77 |     typedef std::map<AudioObjectID, std::shared_ptr<MockAudioDevice>> MockDeviceMap;
78 |     typedef std::map<std::string, std::shared_ptr<MockAudioDevice>> MockDeviceMapByUID;
79 | 
80 |     static std::shared_ptr<MockAudioDevice> GetAudioDeviceOrNull(AudioObjectID inAudioDeviceID);
81 | 
82 |     /*! Maps IDs to mocked audio devices. */
83 |     static MockDeviceMap sDevices;
84 |     /*! Maps UIDs (ID strings) to mocked audio devices. */
85 |     static MockDeviceMapByUID sDevicesByUID;
86 | 
87 | };
88 | 
89 | #endif /* BGMAppUnitTests__MockAudioObjects */
90 | 
91 | 


--------------------------------------------------------------------------------
/BGMApp/BGMAppTests/UnitTests/Mocks/Mock_CAHALAudioSystemObject.cpp:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  Mock_CAHALAudioSystemObject.cpp
18 | //  BGMAppUnitTests
19 | //
20 | //  Copyright © 2017, 2020 Kyle Neideck
21 | //
22 | 
23 | // Self include
24 | #include "CAHALAudioSystemObject.h"
25 | 
26 | // BGM Includes
27 | #include "BGM_Types.h"
28 | 
29 | // Local Includes
30 | #include "MockAudioObjects.h"
31 | 
32 | 
33 | CAHALAudioSystemObject::CAHALAudioSystemObject()
34 | :
35 |     CAHALAudioObject(kAudioObjectSystemObject)
36 | {
37 | }
38 | 
39 | CAHALAudioSystemObject::~CAHALAudioSystemObject()
40 | {
41 | }
42 | 
43 | AudioObjectID	CAHALAudioSystemObject::GetAudioDeviceForUID(CFStringRef inUID) const
44 | {
45 |     auto device = MockAudioObjects::GetAudioDevice(inUID);
46 | 
47 |     if(device)
48 |     {
49 |         return device->GetObjectID();
50 |     }
51 | 
52 |     return kAudioObjectUnknown;
53 | }
54 | 
55 | #pragma mark Unimplemented Methods
56 | 
57 | #pragma clang diagnostic ignored "-Wunused-parameter"
58 | 
59 | UInt32	CAHALAudioSystemObject::GetNumberAudioDevices() const
60 | {
61 |     Throw(new CAException(kAudio_UnimplementedError));
62 | }
63 | 
64 | void	CAHALAudioSystemObject::GetAudioDevices(UInt32& ioNumberAudioDevices, AudioObjectID* outAudioDevices) const
65 | {
66 |     Throw(new CAException(kAudio_UnimplementedError));
67 | }
68 | 
69 | AudioObjectID	CAHALAudioSystemObject::GetAudioDeviceAtIndex(UInt32 inIndex) const
70 | {
71 |     Throw(new CAException(kAudio_UnimplementedError));
72 | }
73 | 
74 | void	CAHALAudioSystemObject::LogBasicDeviceInfo()
75 | {
76 |     Throw(new CAException(kAudio_UnimplementedError));
77 | }
78 | 
79 | AudioObjectID	CAHALAudioSystemObject::GetDefaultAudioDevice(bool inIsInput, bool inIsSystem) const
80 | {
81 |     Throw(new CAException(kAudio_UnimplementedError));
82 | }
83 | 
84 | void	CAHALAudioSystemObject::SetDefaultAudioDevice(bool inIsInput, bool inIsSystem, AudioObjectID inNewDefaultDevice)
85 | {
86 |     Throw(new CAException(kAudio_UnimplementedError));
87 | }
88 | 
89 | AudioObjectID	CAHALAudioSystemObject::GetAudioPlugInForBundleID(CFStringRef inUID) const
90 | {
91 |     Throw(new CAException(kAudio_UnimplementedError));
92 | }
93 | 
94 | 


--------------------------------------------------------------------------------
/BGMApp/BGMXPCHelper/BGMXPCHelperService.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMXPCHelperService.h
18 | //  BGMXPCHelper
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Local Includes
24 | #import "BGMXPCProtocols.h"
25 | 
26 | // System Includes
27 | #import <Foundation/Foundation.h>
28 | 
29 | 
30 | // This object implements the protocol which we have defined. It provides the actual behavior for the service. It is
31 | // 'exported' by the service to make it available to the process hosting the service over an NSXPCConnection.
32 | @interface BGMXPCHelperService : NSObject <BGMXPCHelperXPCProtocol>
33 | 
34 | - (id) initWithConnection:newConnection;
35 | 
36 | @end
37 | 
38 | 


--------------------------------------------------------------------------------
/BGMApp/BGMXPCHelper/BGMXPCListenerDelegate.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMXPCListenerDelegate.h
18 | //  BGMXPCHelper
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // System Includes
24 | #import <Foundation/Foundation.h>
25 | 
26 | 
27 | #pragma clang assume_nonnull begin
28 | 
29 | @interface BGMXPCListenerDelegate : NSObject <NSXPCListenerDelegate>
30 | 
31 | // The UID of the _coreaudiod user, which BGMDriver runs under. This is used in debug builds, usually to warn if a remote method is
32 | // called by BGMApp when it's only meant to be called by BGMDriver, or vice versa.
33 | + (uid_t) _coreaudiodUID;
34 | 
35 | - (BOOL) listener:(NSXPCListener*)listener shouldAcceptNewConnection:(NSXPCConnection*)newConnection;
36 |     
37 | @end
38 | 
39 | #pragma clang assume_nonnull end
40 | 
41 | 


--------------------------------------------------------------------------------
/BGMApp/BGMXPCHelper/Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>CFBundleDevelopmentRegion</key>
 6 | 	<string>en</string>
 7 | 	<key>CFBundleDisplayName</key>
 8 | 	<string>BGMXPCHelper</string>
 9 | 	<key>CFBundleExecutable</key>
10 | 	<string>$(EXECUTABLE_NAME)</string>
11 | 	<key>CFBundleIdentifier</key>
12 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13 | 	<key>CFBundleInfoDictionaryVersion</key>
14 | 	<string>6.0</string>
15 | 	<key>CFBundleName</key>
16 | 	<string>$(PRODUCT_NAME)</string>
17 | 	<key>CFBundlePackageType</key>
18 | 	<string>XPC!</string>
19 | 	<key>CFBundleShortVersionString</key>
20 | 	<string>0.4.3</string>
21 | 	<key>CFBundleSignature</key>
22 | 	<string>????</string>
23 | 	<key>CFBundleVersion</key>
24 | 	<string>1</string>
25 | 	<key>NSHumanReadableCopyright</key>
26 | 	<string>Copyright © 2016-2024 Background Music contributors</string>
27 | 	<key>XPCService</key>
28 | 	<dict>
29 | 		<key>ServiceType</key>
30 | 		<string>User</string>
31 | 	</dict>
32 | </dict>
33 | </plist>
34 | 


--------------------------------------------------------------------------------
/BGMApp/BGMXPCHelper/com.bearisdriving.BGM.XPCHelper.plist.template:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <!--
 4 |     {{# post_install.sh replaces the variables formatted like {{TEMPLATE_VARIABLE}} and comments like this one. #}}
 5 | 
 6 |     Installing/upgrading overwrites this file (/Library/LaunchDaemons/com.bearisdriving.BGM.XPCHelper.plist), so
 7 |     you might not want to edit it directly.
 8 |  -->
 9 | <plist version="1.0">
10 | <dict>
11 |     <key>Label</key>
12 |     <string>com.bearisdriving.BGM.XPCHelper</string>
13 | 
14 |     <key>ProgramArguments</key>
15 |     <array>
16 |             <!-- <string>/usr/local/libexec/BGMXPCHelper.xpc/Contents/MacOS/BGMXPCHelper</string> -->
17 |             <string>{{PATH_TO_BGMXPCHELPER}}/{{BGMXPCHELPER_EXECUTABLE_PATH}}</string>
18 |     </array>
19 | 
20 |     <key>MachServices</key>
21 |     <dict>
22 |         <key>com.bearisdriving.BGM.XPCHelper</key>
23 |         <true/>
24 |     </dict>
25 | 
26 |     <key>ProcessType</key>
27 |     <string>Adaptive</string>
28 | 
29 |     <!--
30 |     {{# post_install.sh creates this user and group. #}}
31 |     -->
32 | 
33 |     <key>UserName</key>
34 |     <string>{{BGMXPCHELPER_USER_NAME}}</string>
35 |     <key>GroupName</key>
36 |     <string>{{BGMXPCHELPER_GROUP_NAME}}</string>
37 | 
38 |     <!-- 
39 |     {{# Uncomment this to log output from BGMXPCHelper. (It logs to syslog by default, so you'd have to change  #}}
40 |     {{# that if you want logs to go to these files.)                                                            #}}
41 |     {{#                                                                                                         #}}
42 |     {{# <key>StandardInPath</key>                                                                               #}}
43 |     {{# <string>/tmp/BGMXPCHelper.stdin.log</string>                                                            #}}
44 |     {{# <key>StandardOutPath</key>                                                                              #}}
45 |     {{# <string>/tmp/BGMXPCHelper.stdout.log</string>                                                           #}}
46 |     {{# <key>StandardErrorPath</key>                                                                            #}}
47 |     {{# <string>/tmp/BGMXPCHelper.stderr.log</string>                                                           #}}
48 |     -->
49 | </dict>
50 | </plist>
51 | 
52 | 


--------------------------------------------------------------------------------
/BGMApp/BGMXPCHelperTests/BGMXPCHelperTests-Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>CFBundleDevelopmentRegion</key>
 6 | 	<string>en</string>
 7 | 	<key>CFBundleExecutable</key>
 8 | 	<string>$(EXECUTABLE_NAME)</string>
 9 | 	<key>CFBundleIdentifier</key>
10 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11 | 	<key>CFBundleInfoDictionaryVersion</key>
12 | 	<string>6.0</string>
13 | 	<key>CFBundleName</key>
14 | 	<string>$(PRODUCT_NAME)</string>
15 | 	<key>CFBundlePackageType</key>
16 | 	<string>BNDL</string>
17 | 	<key>CFBundleShortVersionString</key>
18 | 	<string>1.0</string>
19 | 	<key>CFBundleSignature</key>
20 | 	<string>????</string>
21 | 	<key>CFBundleVersion</key>
22 | 	<string>1</string>
23 | </dict>
24 | </plist>
25 | 


--------------------------------------------------------------------------------
/BGMApp/BGMXPCHelperTests/BGMXPCHelperTests.m:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMXPCHelperTests.m
18 | //  BGMXPCHelperTests
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Local Includes
24 | #import "BGM_TestUtils.h"
25 | #import "BGMXPCProtocols.h"
26 | 
27 | // System Includes
28 | #import <Foundation/Foundation.h>
29 | 
30 | 
31 | #pragma clang assume_nonnull begin
32 | 
33 | // To run these tests, BGMXPCHelper has to be installed and its launchd job enabled.
34 | 
35 | @interface BGMXPCHelperTests : XCTestCase
36 | @end
37 | 
38 | @implementation BGMXPCHelperTests {
39 |     NSXPCConnection* connection;
40 | }
41 | 
42 | - (void) setUp {
43 |     [super setUp];
44 |     
45 |     connection = [[NSXPCConnection alloc] initWithMachServiceName:kBGMXPCHelperMachServiceName
46 |                                                           options:NSXPCConnectionPrivileged];
47 |     
48 |     connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(BGMXPCHelperXPCProtocol)];
49 |     [connection resume];
50 | }
51 | 
52 | - (void) tearDown {
53 |     [connection invalidate];
54 |     
55 |     [super tearDown];
56 | }
57 | 
58 | - (void) testStartOutputDeviceWithoutBGMAppConnected {
59 |     dispatch_semaphore_t replySemaphore = dispatch_semaphore_create(0);
60 | 
61 |     // Unregister BGMXPCHelper's connection to BGMApp in case BGMApp didn't shutdown cleanly the last time it ran.
62 |     [[connection remoteObjectProxy] unregisterAsBGMApp];
63 |         
64 |     [[connection remoteObjectProxy] startBGMAppPlayThroughSyncWithReply:^(NSError* reply) {
65 |         XCTAssertEqual([reply code],
66 |                        kBGMXPC_MessageFailure,
67 |                        @"Check that BGMApp isn't running, which would cause this failure");
68 |         
69 |         dispatch_semaphore_signal(replySemaphore);
70 |     } forUISoundsDevice:NO];
71 | 
72 |     // Very long timeout to make it less likely to fail in CI builds when there's high contention.
73 |     if (0 != dispatch_semaphore_wait(replySemaphore, dispatch_time(DISPATCH_TIME_NOW, 5 * 60 * NSEC_PER_SEC))) {
74 |         XCTFail(@"Timed out waiting for BGMXPCHelper");
75 |     }
76 | }
77 | 
78 | @end
79 | 
80 | #pragma clang assume_nonnull end
81 | 
82 | 


--------------------------------------------------------------------------------
/BGMApp/OptimizationProfiles/BGMApp.profdata:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMApp/OptimizationProfiles/BGMApp.profdata


--------------------------------------------------------------------------------
/BGMApp/PublicUtility/BGMDebugLogging.c:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMDebugLogging.c
18 | //  PublicUtility
19 | //
20 | //  Copyright © 2020, 2024 Kyle Neideck
21 | //
22 | 
23 | // Self Include
24 | #include "BGMDebugLogging.h"
25 | 
26 | 
27 | #pragma clang assume_nonnull begin
28 | 
29 | // It's probably not ideal to use a global variable for this, but it's a lot easier.
30 | #if DEBUG || CoreAudio_Debug
31 |     // Enable debug logging by default in debug builds.
32 |     int gDebugLoggingIsEnabled = 1;
33 | #else
34 |     int gDebugLoggingIsEnabled = 0;
35 | #endif
36 | 
37 | // We don't bother synchronising accesses of gDebugLoggingIsEnabled because it isn't really
38 | // necessary and would complicate code that accesses it on realtime threads.
39 | int BGMDebugLoggingIsEnabled(void)
40 | {
41 |     return gDebugLoggingIsEnabled;
42 | }
43 | 
44 | void BGMSetDebugLoggingEnabled(int inEnabled)
45 | {
46 |     gDebugLoggingIsEnabled = inEnabled;
47 | }
48 | 
49 | #pragma clang assume_nonnull end
50 | 
51 | 


--------------------------------------------------------------------------------
/BGMApp/PublicUtility/BGMDebugLogging.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMDebugLogging.h
18 | //  PublicUtility
19 | //
20 | //  Copyright © 2020 Kyle Neideck
21 | //
22 | //  Functions to globally enable/disable debug logging, i.e. more detailed logging to help diagnose
23 | //  bugs. If debug logging is enabled, the DebugMsg macro from CADebugMacros.h (and possibly others)
24 | //  will log messages. If not, it won't do anything.
25 | //
26 | //  If the preprocessor macro CoreAudio_UseSysLog is true, which is currently the case for all build
27 | //  variants (see BGMApp/BGMApp.xcodeproj/project.pbxproj and
28 | //  BGMDriver/BGMDriver.xcodeproj/project.pbxproj), those messages will be logged using syslog and
29 | //  can be read using Console.app. Try searching for "background music", "bgm" or "coreaudiod".
30 | //
31 | //  Debug logging is enabled by default in debug builds, but in release builds you have to enable it
32 | //  by option-clicking the status bar icon and then checking the Debug Logging menu item. Enabling
33 | //  debug logging probably won't cause glitches, but we don't try to guarantee that and it's not
34 | //  well tested.
35 | //
36 | 
37 | #ifndef PublicUtility__BGMDebugLogging
38 | #define PublicUtility__BGMDebugLogging
39 | 
40 | #pragma clang assume_nonnull begin
41 | 
42 | /*!
43 |  * @return Non-zero if debug logging is globally enabled. (Probably -- it's not synchronised.)
44 |  *         Real-time safe.
45 |  */
46 | #if defined(__cplusplus)
47 | extern "C"
48 | #endif
49 | int BGMDebugLoggingIsEnabled(void);
50 | 
51 | /*!
52 |  * @param inEnabled Non-zero to globally enable debug logging, zero to disable it. The change might
53 |  *                  not be visible to other threads immediately.
54 |  */
55 | #if defined(__cplusplus)
56 | extern "C"
57 | #endif
58 | void BGMSetDebugLoggingEnabled(int inEnabled);
59 | 
60 | #pragma clang assume_nonnull end
61 | 
62 | #endif /* PublicUtility__BGMDebugLogging */
63 | 
64 | 


--------------------------------------------------------------------------------
/BGMApp/PublicUtility/CADebugger.h:
--------------------------------------------------------------------------------
 1 | /*
 2 |      File: CADebugger.h
 3 |  Abstract: Part of CoreAudio Utility Classes
 4 |   Version: 1.1
 5 |  
 6 |  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 7 |  Inc. ("Apple") in consideration of your agreement to the following
 8 |  terms, and your use, installation, modification or redistribution of
 9 |  this Apple software constitutes acceptance of these terms.  If you do
10 |  not agree with these terms, please do not use, install, modify or
11 |  redistribute this Apple software.
12 |  
13 |  In consideration of your agreement to abide by the following terms, and
14 |  subject to these terms, Apple grants you a personal, non-exclusive
15 |  license, under Apple's copyrights in this original Apple software (the
16 |  "Apple Software"), to use, reproduce, modify and redistribute the Apple
17 |  Software, with or without modifications, in source and/or binary forms;
18 |  provided that if you redistribute the Apple Software in its entirety and
19 |  without modifications, you must retain this notice and the following
20 |  text and disclaimers in all such redistributions of the Apple Software.
21 |  Neither the name, trademarks, service marks or logos of Apple Inc. may
22 |  be used to endorse or promote products derived from the Apple Software
23 |  without specific prior written permission from Apple.  Except as
24 |  expressly stated in this notice, no other rights or licenses, express or
25 |  implied, are granted by Apple herein, including but not limited to any
26 |  patent rights that may be infringed by your derivative works or by other
27 |  works in which the Apple Software may be incorporated.
28 |  
29 |  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30 |  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31 |  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32 |  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33 |  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34 |  
35 |  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36 |  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 |  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 |  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39 |  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40 |  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41 |  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42 |  POSSIBILITY OF SUCH DAMAGE.
43 |  
44 |  Copyright (C) 2014 Apple Inc. All Rights Reserved.
45 |  
46 | */
47 | #if !defined(__CADebugger_h__)
48 | #define __CADebugger_h__
49 | 
50 | //=============================================================================
51 | //	Includes
52 | //=============================================================================
53 | 
54 | #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
55 | 	#include <CoreAudio/CoreAudioTypes.h>
56 | #else
57 | 	#include <CoreAudioTypes.h>
58 | #endif
59 | 
60 | //=============================================================================
61 | //	CADebugger
62 | //=============================================================================
63 | 
64 | // BGM edit: Added extern "C" so CADebugger (and headers that include it) can be used in Obj-C.
65 | #ifdef __cplusplus
66 | extern "C" {
67 | #endif
68 | 
69 | #if	TARGET_API_MAC_OSX
70 | 	extern bool CAIsDebuggerAttached(void);
71 | #endif
72 | extern void    CADebuggerStop(void);
73 | 
74 | #ifdef __cplusplus
75 | }
76 | #endif
77 | 
78 | #endif
79 | 


--------------------------------------------------------------------------------
/BGMDriver/BGMDriver/BGM_Control.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGM_Control.h
18 | //  BGMDriver
19 | //
20 | //  Copyright © 2017 Kyle Neideck
21 | //
22 | //  An AudioObject that represents a user-controllable aspect of a device or stream, such as volume
23 | //  or balance.
24 | //
25 | 
26 | #ifndef BGMDriver__BGM_Control
27 | #define BGMDriver__BGM_Control
28 | 
29 | // Superclass Includes
30 | #include "BGM_Object.h"
31 | 
32 | 
33 | #pragma clang assume_nonnull begin
34 | 
35 | class BGM_Control
36 | :
37 |     public BGM_Object
38 | {
39 | 
40 | protected:
41 |                         BGM_Control(AudioObjectID inObjectID,
42 |                                     AudioClassID inClassID,
43 |                                     AudioClassID inBaseClassID,
44 |                                     AudioObjectID inOwnerObjectID,
45 |                                     AudioObjectPropertyScope inScope =
46 |                                             kAudioObjectPropertyScopeOutput,
47 |                                     AudioObjectPropertyElement inElement =
48 |                                             kAudioObjectPropertyElementMaster);
49 | 
50 | #pragma mark Property Operations
51 | 
52 | public:
53 |     virtual bool        HasProperty(AudioObjectID inObjectID,
54 |                                     pid_t inClientPID,
55 |                                     const AudioObjectPropertyAddress& inAddress) const;
56 |     virtual bool        IsPropertySettable(AudioObjectID inObjectID,
57 |                                            pid_t inClientPID,
58 |                                            const AudioObjectPropertyAddress& inAddress) const;
59 |     virtual UInt32      GetPropertyDataSize(AudioObjectID inObjectID,
60 |                                             pid_t inClientPID,
61 |                                             const AudioObjectPropertyAddress& inAddress,
62 |                                             UInt32 inQualifierDataSize,
63 |                                             const void* inQualifierData) const;
64 |     virtual void        GetPropertyData(AudioObjectID inObjectID,
65 |                                         pid_t inClientPID,
66 |                                         const AudioObjectPropertyAddress& inAddress,
67 |                                         UInt32 inQualifierDataSize,
68 |                                         const void* inQualifierData,
69 |                                         UInt32 inDataSize,
70 |                                         UInt32& outDataSize,
71 |                                         void* outData) const;
72 | 
73 | #pragma mark Implementation
74 | 
75 | protected:
76 |     void                CheckObjectID(AudioObjectID inObjectID) const;
77 | 
78 | protected:
79 |     const AudioObjectPropertyScope      mScope;
80 |     const AudioObjectPropertyElement    mElement;
81 | 
82 | };
83 | 
84 | #pragma clang assume_nonnull end
85 | 
86 | #endif /* BGMDriver__BGM_Control */
87 | 
88 | 


--------------------------------------------------------------------------------
/BGMDriver/BGMDriver/BGM_WrappedAudioEngine.cpp:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGM_WrappedAudioEngine.cpp
18 | //  BGMDriver
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Self Include
24 | #include "BGM_WrappedAudioEngine.h"
25 | 
26 | 
27 | // TODO: Register to be notified when the IO Registry values for these change so we can cache them
28 | 
29 | UInt64	BGM_WrappedAudioEngine::GetSampleRate() const
30 | {
31 |     return 0;
32 | }
33 | 
34 | kern_return_t BGM_WrappedAudioEngine::SetSampleRate(Float64 inNewSampleRate)
35 | {
36 |     #pragma unused (inNewSampleRate)
37 |     
38 |     return 0;
39 | }
40 | 
41 | UInt32 BGM_WrappedAudioEngine::GetSampleBufferFrameSize() const
42 | {
43 |     return 0;
44 | }
45 | 
46 | 


--------------------------------------------------------------------------------
/BGMDriver/BGMDriver/BGM_WrappedAudioEngine.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGM_WrappedAudioEngine.h
18 | //  BGMDriver
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | //  The plan for this is to allow devices with IOAudioEngine drivers to be used as the output device
23 | //  directly from BGMDriver, rather than going through BGMApp. That way we get roughly the same CPU
24 | //  usage and latency as normal, and don't need to worry about pausing BGMApp's IO when no clients
25 | //  are doing IO. It also lets BGMDriver mostly continue working without BGMApp running. I've written
26 | //  a very experimental version that mostly works but the code needs a lot of clean up so I haven't
27 | //  added it to this project yet.
28 | //
29 | 
30 | #ifndef __BGMDriver__BGM_WrappedAudioEngine__
31 | #define __BGMDriver__BGM_WrappedAudioEngine__
32 | 
33 | #include <CoreAudio/CoreAudioTypes.h>
34 | #include <mach/kern_return.h>
35 | 
36 | 
37 | class BGM_WrappedAudioEngine
38 | {
39 |     
40 | public:
41 |     UInt64          GetSampleRate() const;
42 |     kern_return_t   SetSampleRate(Float64 inNewSampleRate);
43 |     UInt32          GetSampleBufferFrameSize() const;
44 |     
45 | };
46 | 
47 | #endif /* __BGMDriver__BGM_WrappedAudioEngine__ */
48 | 
49 | 


--------------------------------------------------------------------------------
/BGMDriver/BGMDriver/BGM_XPCHelper.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGM_XPCHelper.h
18 | //  BGMDriver
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | #ifndef BGMDriver__BGM_XPCHelper
24 | #define BGMDriver__BGM_XPCHelper
25 | 
26 | // System Includes
27 | #include <MacTypes.h>
28 | 
29 | #if defined(__cplusplus)
30 | extern "C" {
31 | #endif
32 | 
33 | // On failure, returns one of the kBGMXPC_* error codes, or the error code received from BGMXPCHelper. Returns kBGMXPC_Success otherwise.
34 | UInt64 StartBGMAppPlayThroughSync(bool inIsForUISoundsDevice);
35 | 
36 | #if defined(__cplusplus)
37 | }
38 | #endif
39 | 
40 | #endif /* BGMDriver__BGM_XPCHelper */
41 | 
42 | 


--------------------------------------------------------------------------------
/BGMDriver/BGMDriver/DeviceClients/BGM_Client.cpp:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGM_Client.cpp
18 | //  BGMDriver
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | // Self Include
24 | #include "BGM_Client.h"
25 | 
26 | 
27 | BGM_Client::BGM_Client(const AudioServerPlugInClientInfo* inClientInfo)
28 | :
29 |     mClientID(inClientInfo->mClientID),
30 |     mProcessID(inClientInfo->mProcessID),
31 |     mIsNativeEndian(inClientInfo->mIsNativeEndian),
32 |     mBundleID(inClientInfo->mBundleID)
33 | {
34 |     // The bundle ID ref we were passed is only valid until our plugin returns control to the HAL, so we need to retain
35 |     // it. (CACFString will handle the rest of its ownership/destruction.)
36 |     if(inClientInfo->mBundleID != NULL)
37 |     {
38 |         CFRetain(inClientInfo->mBundleID);
39 |     }
40 | }
41 | 
42 | void    BGM_Client::Copy(const BGM_Client& inClient)
43 | {
44 |     mClientID = inClient.mClientID;
45 |     mProcessID = inClient.mProcessID;
46 |     mBundleID = inClient.mBundleID;
47 |     mIsNativeEndian = inClient.mIsNativeEndian;
48 |     mDoingIO = inClient.mDoingIO;
49 |     mIsMusicPlayer = inClient.mIsMusicPlayer;
50 |     mRelativeVolume = inClient.mRelativeVolume;
51 |     mPanPosition = inClient.mPanPosition;
52 | }
53 | 
54 | 


--------------------------------------------------------------------------------
/BGMDriver/BGMDriver/DeviceClients/BGM_Client.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGM_Client.h
18 | //  BGMDriver
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | 
23 | #ifndef __BGMDriver__BGM_Client__
24 | #define __BGMDriver__BGM_Client__
25 | 
26 | // PublicUtility Includes
27 | #include "CACFString.h"
28 | 
29 | // System Includes
30 | #include <CoreAudio/AudioServerPlugIn.h>
31 | 
32 | 
33 | #pragma clang assume_nonnull begin
34 | 
35 | //==================================================================================================
36 | //	BGM_Client
37 | //
38 | //  Client meaning a client (of the host) of the BGMDevice, i.e. an app registered with the HAL,
39 | //  generally so it can do IO at some point.
40 | //==================================================================================================
41 | 
42 | class BGM_Client
43 | {
44 |     
45 | public:
46 |                                   BGM_Client() = default;
47 |                                   BGM_Client(const AudioServerPlugInClientInfo* inClientInfo);
48 |                                   ~BGM_Client() = default;
49 |                                   BGM_Client(const BGM_Client& inClient) { Copy(inClient); };
50 |                                   BGM_Client& operator=(const BGM_Client& inClient) { Copy(inClient); return *this; }
51 |     
52 | private:
53 |     void                          Copy(const BGM_Client& inClient);
54 |     
55 | public:
56 |     // These fields are duplicated from AudioServerPlugInClientInfo (except the mBundleID CFStringRef is
57 |     // wrapped in a CACFString here).
58 |     UInt32                        mClientID;
59 |     pid_t                         mProcessID;
60 |     Boolean                       mIsNativeEndian = true;
61 |     CACFString                    mBundleID;
62 |     
63 |     // Becomes true when the client triggers the plugin host to call StartIO or to begin
64 |     // kAudioServerPlugInIOOperationThread, and false again on StopIO or when
65 |     // kAudioServerPlugInIOOperationThread ends
66 |     bool                          mDoingIO = false;
67 |     
68 |     // True if BGMApp has set this client as belonging to the music player app
69 |     bool                          mIsMusicPlayer = false;
70 |     
71 |     // The client's volume relative to other clients. In the range [0.0, 4.0], defaults to 1.0 (unchanged).
72 |     // mRelativeVolumeCurve is applied to this value when it's set.
73 |     Float32                       mRelativeVolume = 1.0;
74 |     
75 |     // The client's pan position, in the range [-100, 100] where -100 is left and 100 is right
76 |     SInt32                        mPanPosition = 0;
77 |     
78 | };
79 | 
80 | #pragma clang assume_nonnull end
81 | 
82 | #endif /* __BGMDriver__BGM_Client__ */
83 | 
84 | 


--------------------------------------------------------------------------------
/BGMDriver/BGMDriver/DeviceClients/BGM_ClientTasks.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGM_ClientTasks.h
18 | //  BGMDriver
19 | //
20 | //  Copyright © 2016 Kyle Neideck
21 | //
22 | //  The interface between the client classes (BGM_Client, BGM_Clients and BGM_ClientMap) and BGM_TaskQueue.
23 | //
24 | 
25 | #ifndef __BGMDriver__BGM_ClientTasks__
26 | #define __BGMDriver__BGM_ClientTasks__
27 | 
28 | // Local Includes
29 | #include "BGM_Clients.h"
30 | #include "BGM_ClientMap.h"
31 | 
32 | 
33 | // Forward Declarations
34 | class BGM_TaskQueue;
35 | 
36 | 
37 | #pragma clang assume_nonnull begin
38 | 
39 | class BGM_ClientTasks
40 | {
41 |     
42 |     friend class BGM_TaskQueue;
43 |     
44 | private:
45 |     static bool                            StartIONonRT(BGM_Clients* inClients, UInt32 inClientID) { return inClients->StartIONonRT(inClientID); }
46 |     static bool                            StopIONonRT(BGM_Clients* inClients, UInt32 inClientID) { return inClients->StopIONonRT(inClientID); }
47 |     
48 |     static void                            SwapInShadowMapsRT(BGM_ClientMap* inClientMap) { inClientMap->SwapInShadowMapsRT(); }
49 |     
50 | };
51 | 
52 | #pragma clang assume_nonnull end
53 | 
54 | #endif /* __BGMDriver__BGM_ClientTasks__ */
55 | 
56 | 


--------------------------------------------------------------------------------
/BGMDriver/BGMDriver/DeviceIcon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/BGMDriver/BGMDriver/DeviceIcon.icns


--------------------------------------------------------------------------------
/BGMDriver/BGMDriver/Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>AudioServerPlugIn_MachServices</key>
 6 | 	<array>
 7 | 		<string>com.bearisdriving.BGM.XPCHelper</string>
 8 | 	</array>
 9 | 	<key>CFBundleDevelopmentRegion</key>
10 | 	<string>en</string>
11 | 	<key>CFBundleExecutable</key>
12 | 	<string>$(EXECUTABLE_NAME)</string>
13 | 	<key>CFBundleIdentifier</key>
14 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
15 | 	<key>CFBundleInfoDictionaryVersion</key>
16 | 	<string>6.0</string>
17 | 	<key>CFBundleName</key>
18 | 	<string>$(PRODUCT_NAME)</string>
19 | 	<key>CFBundlePackageType</key>
20 | 	<string>BNDL</string>
21 | 	<key>CFBundleShortVersionString</key>
22 | 	<string>0.4.3</string>
23 | 	<key>CFBundleSignature</key>
24 | 	<string>????</string>
25 | 	<key>CFBundleVersion</key>
26 | 	<string>1.0.0</string>
27 | 	<key>CFPlugInFactories</key>
28 | 	<dict>
29 | 		<key>C957AD43-DACA-4A40-8850-3BA8CE28FAF9</key>
30 | 		<string>BGM_Create</string>
31 | 	</dict>
32 | 	<key>CFPlugInTypes</key>
33 | 	<dict>
34 | 		<key>443ABAB8-E7B3-491A-B985-BEB9187030DB</key>
35 | 		<array>
36 | 			<string>C957AD43-DACA-4A40-8850-3BA8CE28FAF9</string>
37 | 		</array>
38 | 	</dict>
39 | 	<key>NSHumanReadableCopyright</key>
40 | 	<string>Copyright © 2016-2024 Background Music contributors</string>
41 | 	<key>NSPrincipalClass</key>
42 | 	<string></string>
43 | </dict>
44 | </plist>
45 | 


--------------------------------------------------------------------------------
/BGMDriver/BGMDriverTests/Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>CFBundleDevelopmentRegion</key>
 6 | 	<string>en</string>
 7 | 	<key>CFBundleExecutable</key>
 8 | 	<string>$(EXECUTABLE_NAME)</string>
 9 | 	<key>CFBundleIdentifier</key>
10 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11 | 	<key>CFBundleInfoDictionaryVersion</key>
12 | 	<string>6.0</string>
13 | 	<key>CFBundleName</key>
14 | 	<string>$(PRODUCT_NAME)</string>
15 | 	<key>CFBundlePackageType</key>
16 | 	<string>BNDL</string>
17 | 	<key>CFBundleShortVersionString</key>
18 | 	<string>1.0</string>
19 | 	<key>CFBundleSignature</key>
20 | 	<string>????</string>
21 | 	<key>CFBundleVersion</key>
22 | 	<string>1</string>
23 | </dict>
24 | </plist>
25 | 


--------------------------------------------------------------------------------
/BGMDriver/PublicUtility/CADebugger.h:
--------------------------------------------------------------------------------
 1 | /*
 2 |      File: CADebugger.h
 3 |  Abstract: Part of CoreAudio Utility Classes
 4 |   Version: 1.1
 5 |  
 6 |  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 7 |  Inc. ("Apple") in consideration of your agreement to the following
 8 |  terms, and your use, installation, modification or redistribution of
 9 |  this Apple software constitutes acceptance of these terms.  If you do
10 |  not agree with these terms, please do not use, install, modify or
11 |  redistribute this Apple software.
12 |  
13 |  In consideration of your agreement to abide by the following terms, and
14 |  subject to these terms, Apple grants you a personal, non-exclusive
15 |  license, under Apple's copyrights in this original Apple software (the
16 |  "Apple Software"), to use, reproduce, modify and redistribute the Apple
17 |  Software, with or without modifications, in source and/or binary forms;
18 |  provided that if you redistribute the Apple Software in its entirety and
19 |  without modifications, you must retain this notice and the following
20 |  text and disclaimers in all such redistributions of the Apple Software.
21 |  Neither the name, trademarks, service marks or logos of Apple Inc. may
22 |  be used to endorse or promote products derived from the Apple Software
23 |  without specific prior written permission from Apple.  Except as
24 |  expressly stated in this notice, no other rights or licenses, express or
25 |  implied, are granted by Apple herein, including but not limited to any
26 |  patent rights that may be infringed by your derivative works or by other
27 |  works in which the Apple Software may be incorporated.
28 |  
29 |  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30 |  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31 |  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32 |  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33 |  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34 |  
35 |  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36 |  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 |  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 |  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39 |  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40 |  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41 |  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42 |  POSSIBILITY OF SUCH DAMAGE.
43 |  
44 |  Copyright (C) 2014 Apple Inc. All Rights Reserved.
45 |  
46 | */
47 | #if !defined(__CADebugger_h__)
48 | #define __CADebugger_h__
49 | 
50 | //=============================================================================
51 | //	Includes
52 | //=============================================================================
53 | 
54 | #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
55 | 	#include <CoreAudio/CoreAudioTypes.h>
56 | #else
57 | 	#include <CoreAudioTypes.h>
58 | #endif
59 | 
60 | //=============================================================================
61 | //	CADebugger
62 | //=============================================================================
63 | 
64 | #if	TARGET_API_MAC_OSX
65 | 	extern bool CAIsDebuggerAttached(void);
66 | #endif
67 | extern void	CADebuggerStop(void);
68 | 
69 | #endif
70 | 


--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
 1 | <!-- vim: set tw=120: -->
 2 | 
 3 | # Contributing
 4 | 
 5 | Firstly, thanks for reading this. Pull requests, bug reports, feature requests, questions, etc. are all very welcome --
 6 | including ones from non-developers.
 7 | 
 8 | ## Issues
 9 | 
10 | You'll probably want to update to the latest version of the code before creating an issue. The easiest way is to just
11 | run the installation command from [README.md](/README.md#install) again. (But `git pull && ./build_and_install.sh` is
12 | faster.)
13 | 
14 | For bug reports about `build_and_install.sh`, please include your `build_and_install.log`. It should be saved in the
15 | directory `build_and_install.sh` is in.
16 | 
17 | It might also be helpful to include logs in bug reports about Background Music itself. Those logs go to syslog by
18 | default, so you can use Console.app to read them. (It might help to search for "BGM" or "Background Music".)
19 | 
20 | You also might not get any log messages at all. Normally (i.e. in release builds) Background Music only logs errors and
21 | warnings. We're still working on adding optional debug-level logging to release builds.
22 | 
23 | If you feel like being really helpful, you could reproduce your bug with a debug build and include the debug logs, which
24 | are much more detailed. But don't feel obligated to. To install a debug build, use `./build_and_install.sh -d`.
25 | 
26 | If you make an issue and you're interested in implementing/fixing it yourself, mention that in the issue so we can
27 | confirm you're on the right track, assign the issue to you and so on.
28 | 
29 | ## Code
30 | 
31 | The code is mostly C++ and Objective-C. But don't worry if you don't know those languages--I don't either. Or Core
32 | Audio, for that matter. Also don't worry if you're not sure your code is right.
33 | 
34 | No dependencies so far. (Though you're welcome to add some.)
35 | 
36 | The best place to start is probably [DEVELOPING.md](/DEVELOPING.md), which has an overview of the project and
37 | instructions for building, debugging, etc. It's kind of long, though, and not very interesting, so you might prefer to
38 | go straight into the code. In that case, you'll probably want to start with
39 | [BGMAppDelegate.mm](/BGMApp/BGMApp/BGMAppDelegate.mm).
40 | 
41 | If you get stuck or have questions about the project, feel free to open an issue. You could also [email
42 | me](mailto:kyle@bearisdriving.com) or try [#backgroundmusic on
43 | Freenode](https://webchat.freenode.net/?channels=backgroundmusic).
44 | 
45 | If you have questions related to Core Audio, the [Core Audio mailing
46 | list](https://lists.apple.com/archives/coreaudio-api) is very useful. There's also the [Core Audio
47 | Overview](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html)
48 | and the [Core Audio
49 | Glossary](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioGlossary/Glossary/core_audio_glossary.html).
50 | 
51 | If you remember to, add a copyright notice with your name to any source files you change substantially. Let us know in
52 | the PR if you've intentionally not added one so we know not to add one for you.
53 | 
54 | 
55 | 


--------------------------------------------------------------------------------
/Images/FermataIcon.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/Images/FermataIcon.pdf


--------------------------------------------------------------------------------
/Images/FermataIcon.tex:
--------------------------------------------------------------------------------
 1 | % This file is part of Background Music.
 2 | %
 3 | % Background Music is free software: you can redistribute it and/or
 4 | % modify it under the terms of the GNU General Public License as
 5 | % published by the Free Software Foundation, either version 2 of the
 6 | % License, or (at your option) any later version.
 7 | %
 8 | % Background Music is distributed in the hope that it will be useful,
 9 | % but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | % GNU General Public License for more details.
12 | %
13 | % You should have received a copy of the GNU General Public License
14 | % along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | %
17 | % FermataIcon.tex
18 | % Copyright © 2016 Kyle Neideck
19 | %
20 | % The app/device/status bar icon for BGMApp
21 | %
22 | % Build with XeTeX:
23 | %   xelatex FermataIcon.tex
24 | %
25 | % Then run generate_icon_pngs.sh
26 | %
27 | % Not sure why it doesn't build properly with regular LaTeX.
28 | %
29 | 
30 | \documentclass{article}
31 | \thispagestyle{empty}
32 | 
33 | \usepackage{tikz}
34 | \usepackage[paperwidth=100mm, paperheight=100mm, margin=0mm]{geometry}
35 | 
36 | \begin{document}
37 | \begin{center}
38 | \begin{tikzpicture}[remember picture,overlay]
39 | 
40 | % A path that follows the edges of the current page
41 | \tikzstyle{reverseclip}=[insert path={(current page.north east) --
42 |   (current page.south east) --
43 |   (current page.south west) --
44 |   (current page.north west) --
45 |   (current page.north east)}
46 | ]
47 | 
48 | \begin{scope}
49 | \begin{pgfinterruptboundingbox}
50 | \path [clip] (0,-62.6mm) circle (33mm) [reverseclip];
51 | \end{pgfinterruptboundingbox}
52 | 
53 | \fill[black] (0,-50mm) circle (44mm);
54 | \end{scope}
55 | 
56 | \begin{scope}
57 | \fill[black] (0,-68.5mm) circle (26mm);
58 | \end{scope}
59 | 
60 | \end{tikzpicture}
61 | \end{center}
62 | \end{document}
63 | 
64 | 


--------------------------------------------------------------------------------
/Images/README/FermataIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/Images/README/FermataIcon.png


--------------------------------------------------------------------------------
/Images/README/Screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/Images/README/Screenshot.png


--------------------------------------------------------------------------------
/Images/README/pkg-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyleneideck/BackgroundMusic/21ec64f887440b850310ef69171827a1d2e0e688/Images/README/pkg-icon.png


--------------------------------------------------------------------------------
/Images/VolumeIcons.tex:
--------------------------------------------------------------------------------
 1 | % This file is part of Background Music.
 2 | %
 3 | % Background Music is free software: you can redistribute it and/or
 4 | % modify it under the terms of the GNU General Public License as
 5 | % published by the Free Software Foundation, either version 2 of the
 6 | % License, or (at your option) any later version.
 7 | %
 8 | % Background Music is distributed in the hope that it will be useful,
 9 | % but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | % GNU General Public License for more details.
12 | %
13 | % You should have received a copy of the GNU General Public License
14 | % along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | %
17 | % VolumeIcons.tex
18 | %
19 | % Build with XeTeX:
20 | %   xelatex -jobname=Volume0 '\def\UseOption{}\input{VolumeIcons.tex}'
21 | %   xelatex -jobname=Volume1 '\def\UseOption{w1}\input{VolumeIcons.tex}'
22 | %   xelatex -jobname=Volume2 '\def\UseOption{w1,w2}\input{VolumeIcons.tex}'
23 | %   xelatex -jobname=Volume3 '\def\UseOption{w1,w2,w3}\input{VolumeIcons.tex}'
24 | %   for n in 0 1 2 3; do mv Volume$n.pdf ../BGMApp/BGMApp/Images.xcassets/Volume$n.imageset/; done
25 | %
26 | % Might build correctly with regular LaTeX. I haven't tried it.
27 | %
28 | 
29 | \documentclass[tikz]{standalone}
30 | \usepackage{tikz}
31 | % "dummyOption" prevents "Package optional Warning: No options were selected,
32 | % so all optional text will be printed" when building Volume0.pdf.
33 | \usepackage[dummyOption]{optional}
34 | 
35 | \begin{document}
36 | \begin{tikzpicture}
37 | 
38 | % Speaker (Rounded box and triangle)
39 | \fill[rounded corners=5mm]
40 |     (0mm, 62.5mm) rectangle (25mm, 37.5mm) {};
41 | \draw[rounded corners=2.5mm,fill=black]
42 |     (3mm, 50mm)--(34mm, 76.5mm)--(34mm, 23.5mm)--cycle;
43 | 
44 | % First sound wave (Curved line)
45 | \opt{w1}{
46 |     \draw[line width=4.3mm,line cap=round]
47 |         (44mm, 36.5mm) to[out=46,in=-46] (44mm, 63.5mm);
48 | }
49 | 
50 | % Second sound wave (Curved line)
51 | \opt{w2}{
52 |     \draw[line width=4.3mm,line cap=round]
53 |         (57.5mm, 27.5mm) to[out=46,in=-46] (57.5mm, 72.5mm);
54 | }
55 | 
56 | % Third sound wave (Curved line)
57 | \opt{w3}{
58 |     \draw[line width=4.3mm,line cap=round]
59 |         (72mm, 18.5mm) to[out=46,in=-46] (72mm, 81.5mm);
60 | }
61 | 
62 | % Always draw a transparent copy of the third wave so the images will all have
63 | % the same width.
64 | \draw[line width=4.3mm,line cap=round,opacity=0]
65 |     (72mm, 18.5mm) to[out=46,in=-46] (72mm, 81.5mm);
66 | 
67 | \end{tikzpicture}
68 | \end{document}
69 | 
70 | 


--------------------------------------------------------------------------------
/Images/generate_icon_pngs.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | # vim: tw=0:
 3 | 
 4 | # This file is part of Background Music.
 5 | #
 6 | # Background Music is free software: you can redistribute it and/or
 7 | # modify it under the terms of the GNU General Public License as
 8 | # published by the Free Software Foundation, either version 2 of the
 9 | # License, or (at your option) any later version.
10 | #
11 | # Background Music is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with Background Music. If not, see <http://www.gnu.org/licenses/>.
18 | 
19 | #
20 | # generate_icon_pngs.sh
21 | # Copyright © 2016 Kyle Neideck
22 | #
23 | # Creates the app and status bar icons for BGMApp in Images.xcassets, and DeviceIcon.icns
24 | # for BGMDriver, from FermataIcon.pdf
25 | #
26 | # Requires ImageMagick (for iconizer.sh)
27 | #
28 | 
29 | # Safe mode
30 | set -euo pipefail
31 | IFS=
#39;\n\t'
32 | 
33 | echo Copying FermataIcon.pdf into FermataIcon.imageset for the status bar icon
34 | echo ----
35 | 
36 | (set -x; cp FermataIcon.pdf ../BGMApp/BGMApp/Images.xcassets/FermataIcon.imageset/)
37 | 
38 | echo
39 | echo Generating app icon for BGMApp
40 | echo ----
41 | 
42 | cp ../BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/Contents.json \
43 |     ../BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/Contents.json.brb
44 | 
45 | sh iconizer.sh FermataIcon.pdf ../BGMApp/BGMApp
46 | 
47 | # Delete unused sizes
48 | cd ../BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset/
49 | 
50 | rm appicon_114.png appicon_144.png appicon_180.png appicon_80.png appicon_100.png appicon_120.png appicon_152.png appicon_40.png appicon_57.png appicon_72.png appicon_87.png appicon_29.png appicon_50.png appicon_58.png appicon_76.png
51 | 
52 | mv Contents.json.brb Contents.json
53 | 
54 | cd - > /dev/null
55 | 
56 | echo
57 | echo Generating DeviceIcon.icns for BGMDriver
58 | echo ----
59 | 
60 | set -x
61 | 
62 | cp -r ../BGMApp/BGMApp/Images.xcassets/AppIcon.appiconset ../BGMDriver/BGMDriver/DeviceIcon.iconset
63 | 
64 | cd ../BGMDriver/BGMDriver/DeviceIcon.iconset
65 | 
66 | mv appicon_1024.png icon_512x512@2x.png
67 | mv appicon_512.png icon_512x512.png
68 | cp icon_512x512.png icon_256x256@2x.png
69 | mv appicon_256.png icon_256x256.png
70 | cp icon_256x256.png icon_128x128@2x.png
71 | mv appicon_128.png icon_128x128.png
72 | mv appicon_64.png icon_32x32@2x.png
73 | mv appicon_32.png icon_32x32.png
74 | cp icon_32x32.png icon_16x16@2x.png
75 | mv appicon_16.png icon_16x16.png
76 | 
77 | cd -
78 | 
79 | iconutil -c icns -o ../BGMDriver/BGMDriver/DeviceIcon.icns ../BGMDriver/BGMDriver/DeviceIcon.iconset
80 | 
81 | # Fail if the .icns wasn't created
82 | ls ../BGMDriver/BGMDriver/DeviceIcon.icns
83 | 
84 | rm -r ../BGMDriver/BGMDriver/DeviceIcon.iconset
85 | 
86 | 
87 | 


--------------------------------------------------------------------------------
/LICENSE-Apple-Sample-Code:
--------------------------------------------------------------------------------
 1 | Background Music includes code from Core Audio User-Space Driver
 2 | Examples, see
 3 | <https://developer.apple.com/library/mac/samplecode/AudioDriverExamples>,
 4 | which was provided with the following copyright notice and the license
 5 | below.
 6 |  
 7 | Copyright (C) 2013 Apple Inc. All Rights Reserved.
 8 | 
 9 | Background Music includes code from Core Audio Utility Classes, see
10 | <https://developer.apple.com/library/content/samplecode/CoreAudioUtilityClasses>,
11 | which was provided with the following copyright notice and the license
12 | below.
13 | 
14 | Copyright (C) 2014 Apple Inc. All Rights Reserved.
15 | 
16 | ------------------------------------------------------------------------
17 | 
18 | Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple 
19 | Inc. ("Apple") in consideration of your agreement to the following 
20 | terms, and your use, installation, modification or redistribution of 
21 | this Apple software constitutes acceptance of these terms.  If you do 
22 | not agree with these terms, please do not use, install, modify or 
23 | redistribute this Apple software. 
24 |  
25 | In consideration of your agreement to abide by the following terms, and 
26 | subject to these terms, Apple grants you a personal, non-exclusive 
27 | license, under Apple's copyrights in this original Apple software (the 
28 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 
29 | Software, with or without modifications, in source and/or binary forms; 
30 | provided that if you redistribute the Apple Software in its entirety and 
31 | without modifications, you must retain this notice and the following 
32 | text and disclaimers in all such redistributions of the Apple Software. 
33 | Neither the name, trademarks, service marks or logos of Apple Inc. may 
34 | be used to endorse or promote products derived from the Apple Software 
35 | without specific prior written permission from Apple.  Except as 
36 | expressly stated in this notice, no other rights or licenses, express or 
37 | implied, are granted by Apple herein, including but not limited to any 
38 | patent rights that may be infringed by your derivative works or by other 
39 | works in which the Apple Software may be incorporated. 
40 |  
41 | The Apple Software is provided by Apple on an "AS IS" basis.  APPLE 
42 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 
43 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 
44 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 
45 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 
46 |  
47 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 
48 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
49 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
50 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 
51 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 
52 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 
53 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 
54 | POSSIBILITY OF SUCH DAMAGE. 
55 | 
56 | 
57 | 


--------------------------------------------------------------------------------
/MANUAL-INSTALL.md:
--------------------------------------------------------------------------------
 1 | <!-- vim: set tw=120: -->
 2 | 
 3 | # Manual Build and Install
 4 | 
 5 | - Install the virtual audio device `Background Music Device.driver` to `/Library/Audio/Plug-Ins/HAL`.
 6 | 
 7 |   ```shell
 8 |   sudo xcodebuild -project BGMDriver/BGMDriver.xcodeproj \
 9 |                   -target "PublicUtility" \
10 |                   RUN_CLANG_STATIC_ANALYZER=0 \
11 |                   clean build
12 |   sudo xcodebuild -project BGMDriver/BGMDriver.xcodeproj \
13 |                   -target "Background Music Device" \
14 |                   RUN_CLANG_STATIC_ANALYZER=0 \
15 |                   DSTROOT="/" \
16 |                   clean install
17 |   ```
18 | - Install the XPC helper.
19 | 
20 |   ```shell
21 |   sudo xcodebuild -project BGMApp/BGMApp.xcodeproj \
22 |                   -target BGMXPCHelper \
23 |                   RUN_CLANG_STATIC_ANALYZER=0 \
24 |                   DSTROOT="/" \
25 |                   INSTALL_PATH="$(BGMApp/BGMXPCHelper/safe_install_dir.sh)" \
26 |                   clean install
27 |   ```
28 | - Install `Background Music.app` to `/Applications` (or wherever).
29 | 
30 |   ```shell
31 |   sudo xcodebuild -project BGMApp/BGMApp.xcodeproj \
32 |                   -target "Background Music" \
33 |                   RUN_CLANG_STATIC_ANALYZER=0 \
34 |                   DSTROOT="/" \
35 |                   clean install
36 |   ```
37 | - Restart `coreaudiod`: <br>
38 |   (Audio will stop working until the next step, so you might want to pause any running audio apps.)
39 | 
40 |   ```shell
41 |   sudo killall coreaudiod
42 |   ```
43 | 
44 |   or, if that fails
45 | 
46 |   ```shell
47 |   sudo launchctl kickstart -kp system/com.apple.audio.coreaudiod
48 |   ```
49 | - Run `Background Music.app`.
50 | 
51 | 
52 | 


--------------------------------------------------------------------------------
/MANUAL-UNINSTALL.md:
--------------------------------------------------------------------------------
 1 | <!-- vim: set tw=120: -->
 2 | 
 3 | # Manual Uninstall
 4 | 
 5 | - Delete `Background Music.app` from `/Applications`.
 6 | - Delete `Background Music Device.driver` from `/Library/Audio/Plug-Ins/HAL`.
 7 | - Pause apps that are playing audio, if you can.
 8 | - Restart `coreaudiod`:<br>
 9 |   <sup>(Open `/Applications/Utilities/Terminal.app` and paste the following at the prompt.)</sup>
10 | 
11 |   ```shell
12 |   sudo killall coreaudiod
13 |   ```
14 |   or, if that fails
15 | 
16 |   ```shell
17 |   sudo launchctl kickstart -kp system/com.apple.audio.coreaudiod
18 |   ```
19 | - Go to the Sound section in System Settings and change your default output device at least once. (If you only have
20 |   one device now, either use `Audio MIDI Setup.app` to create a temporary aggregate device, restart any audio apps that
21 |   have stopped working or just restart your system.)
22 |   
23 | ## Troubleshooting
24 | 
25 | If you still have the Background Music audio device, try using `Terminal.app` to make sure you've deleted its files:
26 | 
27 | ```shell
28 | sudo ls /Library/Audio/Plug-Ins/HAL
29 | ```
30 | 
31 | If you see `Background Music Device.driver` in the output of that command, use this command to actually delete it:
32 | 
33 | ```shell
34 | sudo rm -rf "/Library/Audio/Plug-Ins/HAL/Background Music Device.driver"
35 | ```
36 | 
37 | Then restart `coreaudiod` again. If that still doesn't work, restart your computer. If that doesn't work, feel free to
38 | open an issue. Include the output of `sudo ls /Library/Audio/Plug-Ins/HAL`.
39 | 
40 | ## Optional
41 | 
42 | - Delete `BGMXPCHelper.xpc` from `/usr/local/libexec` or possibly `/Library/Application Support/Background Music`.
43 | - Unregister BGMXPCHelper.
44 |   - If you're using OS X 10.11 or later:
45 | 
46 |     ```shell
47 |     sudo launchctl bootout system /Library/LaunchDaemons/com.bearisdriving.BGM.XPCHelper.plist
48 |     ```
49 |   - If you're using an earlier version of OS X:
50 | 
51 |     ```shell
52 |     sudo launchctl unload /Library/LaunchDaemons/com.bearisdriving.BGM.XPCHelper.plist
53 |     ```
54 | - Delete BGMXPCHelper's launchd.plist.
55 | 
56 |   ```shell
57 |   sudo rm /Library/LaunchDaemons/com.bearisdriving.BGM.XPCHelper.plist
58 |   ```
59 | - Delete BGMXPCHelper's user and group.
60 | 
61 |   ```shell
62 |   sudo dscl . -delete /Users/_BGMXPCHelper
63 |   sudo dscl . -delete /Groups/_BGMXPCHelper
64 |   ```
65 | 
66 | 
67 | 


--------------------------------------------------------------------------------
/SharedSource/BGMXPCProtocols.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGMXPCProtocols.h
18 | //  SharedSource
19 | //
20 | //  Copyright © 2016, 2017 Kyle Neideck
21 | //
22 | 
23 | // Local Includes
24 | #include "BGM_Types.h"
25 | 
26 | // System Includes
27 | #import <Foundation/Foundation.h>
28 | 
29 | 
30 | #pragma clang assume_nonnull begin
31 | 
32 | static NSString* kBGMXPCHelperMachServiceName = @kBGMXPCHelperBundleID;
33 | 
34 | // The protocol that BGMXPCHelper will vend as its XPC API.
35 | @protocol BGMXPCHelperXPCProtocol
36 | 
37 | // Tells BGMXPCHelper that the caller is BGMApp and passes a listener endpoint that BGMXPCHelper can use to create connections to BGMApp.
38 | // BGMXPCHelper may also pass the endpoint on to BGMDriver so it can do the same.
39 | - (void) registerAsBGMAppWithListenerEndpoint:(NSXPCListenerEndpoint*)endpoint reply:(void (^)(void))reply;
40 | - (void) unregisterAsBGMApp;
41 | 
42 | // BGMDriver calls this remote method when it wants BGMApp to start IO. BGMXPCHelper passes the message along and then passes the response
43 | // back. This allows BGMDriver to wait for the audio hardware to start up, which means it can let the HAL know when it's safe to start
44 | // sending us audio data from the client.
45 | //
46 | // If BGMApp can be reached, the error it returns will be passed the reply block. Otherwise, the reply block will be passed an error with
47 | // one of the kBGMXPC_* error codes. It may have an underlying error using one of the NSXPCConnection* error codes from FoundationErrors.h.
48 | - (void) startBGMAppPlayThroughSyncWithReply:(void (^)(NSError*))reply forUISoundsDevice:(BOOL)isUI;
49 | 
50 | // BGMXPCHelper will set the system's default output device to deviceID if it loses its connection
51 | // to BGMApp and BGMApp has left BGMDevice as the default device. It waits for a short time first to
52 | // give BGMApp a chance to fix the connection.
53 | //
54 | // This is so BGMDevice isn't left as the default device if BGMApp crashes or otherwise terminates
55 | // abnormally. If audio is played to BGMDevice and BGMApp isn't running, the user won't hear it.
56 | - (void) setOutputDeviceToMakeDefaultOnAbnormalTermination:(AudioObjectID)deviceID;
57 |     
58 | @end
59 | 
60 | 
61 | // The protocol that BGMApp will vend as its XPC API.
62 | @protocol BGMAppXPCProtocol
63 | 
64 | - (void) startPlayThroughSyncWithReply:(void (^)(NSError*))reply forUISoundsDevice:(BOOL)isUI;
65 | 
66 | @end
67 | 
68 | #pragma clang assume_nonnull end
69 | 
70 | 


--------------------------------------------------------------------------------
/SharedSource/BGM_TestUtils.h:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  BGM_TestUtils.h
18 | //  SharedSource
19 | //
20 | //  Copyright © 2016, 2021 Kyle Neideck
21 | //
22 | 
23 | #ifndef __SharedSource__BGM_TestUtils__
24 | #define __SharedSource__BGM_TestUtils__
25 | 
26 | // Test Framework
27 | #import <XCTest/XCTest.h>
28 | 
29 | #if defined(__cplusplus)
30 | 
31 | // STL Includes
32 | #include <functional>
33 | 
34 | 
35 | // Fails the test if f doesn't throw ExpectedException when run.
36 | // (The "self" argument is required by XCTFail, presumably so it can report the context.)
37 | template<typename ExpectedException>
38 | void BGMShouldThrow(XCTestCase* self, const std::function<void()>& f)
39 | {
40 | #pragma unused (self)
41 |     try
42 |     {
43 |         f();
44 |         XCTFail();
45 |     }
46 |     catch (ExpectedException)
47 |     { }
48 | }
49 | 
50 | #endif /* defined(__cplusplus) */
51 | 
52 | #endif /* __SharedSource__BGM_TestUtils__ */
53 | 
54 | 


--------------------------------------------------------------------------------
/SharedSource/Scripts/set-version.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | # This file is part of Background Music.
 4 | #
 5 | # Background Music is free software: you can redistribute it and/or
 6 | # modify it under the terms of the GNU General Public License as
 7 | # published by the Free Software Foundation, either version 2 of the
 8 | # License, or (at your option) any later version.
 9 | #
10 | # Background Music is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with Background Music. If not, see <http://www.gnu.org/licenses/>.
17 | 
18 | #
19 | #  set-version.sh
20 | #  SharedSource
21 | #
22 | #  Copyright © 2020 Kyle Neideck
23 | #
24 | #  Append the git HEAD short ID to the build version for SNAPSHOT and DEBUG builds. For example,
25 | #  this might change the version string from "0.4.0" to "0.4.0-SNAPSHOT-abc0123".
26 | #
27 | #  Thanks to Václav Slavík for the initial version of this:
28 | #  <http://stackoverflow.com/a/26354117/1091063>.
29 | #
30 | #  TODO: Update CFBundleVersion as well?
31 | #
32 | 
33 | # If HEAD isn't tagged, or has "SNAPSHOT" or "DEBUG" in the tag name, this is a snapshot build.
34 | # If HEAD is tagged more than once, use the most recent.
35 | TAG=$(/usr/bin/git tag --points-at HEAD --sort='-taggerdate' 2>/dev/null | head -n 1)
36 | 
37 | if [[ $? -eq 0 ]] && ( [[ "${TAG}" == "" ]] || \
38 |         [[ "${TAG}" =~ .*SNAPSHOT.* ]] || \
39 |         [[ "${TAG}" =~ .*DEBUG.* ]] ); then
40 |     head_short_id=$(/usr/bin/git rev-list HEAD --max-count=1 --abbrev-commit)
41 |     info_plist="${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}"
42 | 
43 |     if [[ "${CONFIGURATION}" != "Release" ]]; then
44 |         build_type="DEBUG"
45 |     else
46 |         build_type="SNAPSHOT"
47 |     fi
48 | 
49 |     if [[ -f "$info_plist" ]]; then
50 |         current_version=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "${info_plist}")
51 |         base_version=$(/usr/libexec/PlistBuddy -c "Print :BGMBundleVersionBase" "${info_plist}" 2>/dev/null)
52 | 
53 |         if [[ $? -ne 0 ]] || [[ "${base_version}" == "" ]]; then
54 |             base_version="${current_version}"
55 |             /usr/libexec/PlistBuddy -c "Add :BGMBundleVersionBase string ${base_version}" "${info_plist}"
56 |         fi
57 | 
58 |         new_version="${base_version}-${build_type}-${head_short_id}"
59 | 
60 |         if [[ "${new_version}" != "${current_version}" ]]; then  # Only touch the file if we need to.
61 |             /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${new_version}" "${info_plist}"
62 |         fi
63 |     fi
64 | fi
65 | 
66 | 


--------------------------------------------------------------------------------
/pkg/Distribution.xml.template:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8" standalone="no"?>
 2 | <installer-gui-script minSpecVersion="1">
 3 |     <title>Background Music {{VERSION}}</title>
 4 | 
 5 |     <volume-check>
 6 |         <allowed-os-versions>
 7 |             <!-- TODO: Get this from the Xcode project files instead of hardcoding it. -->
 8 |             <os-version min="10.13" />
 9 |         </allowed-os-versions>
10 |     </volume-check>
11 | 
12 |     <!--
13 |       Do not specify <domains>.
14 |       Installer does not show "OS X version X.Y.Z or later is required" message when <domains> exists.
15 |       <domains enable_anywhere="false" enable_currentUserHome="false" enable_localSystem="true" />
16 |       -->
17 | 
18 |     <pkg-ref id="com.bearisdriving.BGM"/>
19 | 
20 |     <options customize="never" require-scripts="false" hostArchitectures="arm64,x86_64" />
21 | 
22 |     <choices-outline>
23 |         <line choice="default">
24 |             <line choice="com.bearisdriving.BGM" />
25 |         </line>
26 |     </choices-outline>
27 | 
28 |     <choice id="default"/>
29 | 
30 |     <choice id="com.bearisdriving.BGM" visible="false">
31 |         <pkg-ref id="com.bearisdriving.BGM" />
32 |     </choice>
33 | 
34 |     <pkg-ref id="com.bearisdriving.BGM" version="{{VERSION}}">Installer.pkg</pkg-ref>
35 | 
36 |     <pkg-ref id="com.bearisdriving.BGM">
37 |         <must-close>
38 |             <app id="com.bearisdriving.BGM.App" />
39 |         </must-close>
40 |     </pkg-ref>
41 | 
42 |     <background file="FermataIcon.pdf" alignment="bottomleft" mime-type="application/pdf" />
43 | </installer-gui-script>
44 | 
45 | 
46 | 


--------------------------------------------------------------------------------
/pkg/ListInputDevices.swift:
--------------------------------------------------------------------------------
 1 | // This file is part of Background Music.
 2 | //
 3 | // Background Music is free software: you can redistribute it and/or
 4 | // modify it under the terms of the GNU General Public License as
 5 | // published by the Free Software Foundation, either version 2 of the
 6 | // License, or (at your option) any later version.
 7 | //
 8 | // Background Music is distributed in the hope that it will be useful,
 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with Background Music. If not, see <http://www.gnu.org/licenses/>.
15 | 
16 | //
17 | //  ListInputDevices.swift
18 | //
19 | //  Copyright © 2022 Kyle Neideck
20 | //
21 | //  The postinstall script uses this to check that BGMDevice was installed successfully.
22 | //
23 | 
24 | import AVFoundation
25 | 
26 | var devices: Array<AVCaptureDevice>
27 | 
28 | if #available(macOS 10.15, *) {
29 |     devices = AVCaptureDevice.DiscoverySession(
30 |         deviceTypes: [ .builtInMicrophone, .externalUnknown ],
31 |         mediaType: .audio,
32 |         position: .unspecified
33 |     ).devices
34 | } else {
35 |     devices = AVCaptureDevice.devices(for: .audio)
36 | }
37 | 
38 | print(devices.map {
39 |     (device: AVCaptureDevice) -> Array<String> in
40 |     [device.uniqueID, device.modelID, device.localizedName]
41 | })
42 | 


--------------------------------------------------------------------------------
/pkg/README.md:
--------------------------------------------------------------------------------
1 | Files used by [package.sh](../package.sh), the script that creates the .pkg installer.
2 | 


--------------------------------------------------------------------------------
/pkg/pkgbuild.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 |   <array>
 5 |     <dict>
 6 |       <key>RootRelativeBundlePath</key>      <string>Applications/Background Music.app</string>
 7 |       <key>BundleHasStrictIdentifier</key>   <false/>
 8 |       <key>BundleIsRelocatable</key>         <true/>
 9 |       <key>BundleIsVersionChecked</key>      <false/>
10 |       <key>BundleOverwriteAction</key>       <string>upgrade</string>
11 |     </dict>
12 |     <dict>
13 |       <key>RootRelativeBundlePath</key>      <string>Library/Audio/Plug-Ins/HAL/Background Music Device.driver</string>
14 |       <key>BundleHasStrictIdentifier</key>   <false/>
15 |       <key>BundleIsRelocatable</key>         <false/>
16 |       <key>BundleIsVersionChecked</key>      <false/>
17 |       <key>BundleOverwriteAction</key>       <string>upgrade</string>
18 |     </dict>
19 |   </array>
20 | </plist>
21 | 
22 | 


--------------------------------------------------------------------------------
/pkg/preinstall:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | # vim: tw=100:
 3 | 
 4 | # This file is part of Background Music.
 5 | #
 6 | # Background Music is free software: you can redistribute it and/or
 7 | # modify it under the terms of the GNU General Public License as
 8 | # published by the Free Software Foundation, either version 2 of the
 9 | # License, or (at your option) any later version.
10 | #
11 | # Background Music is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with Background Music. If not, see <http://www.gnu.org/licenses/>.
18 | 
19 | #
20 | # preinstall
21 | #
22 | # Copyright © 2017 Kyle Neideck
23 | #
24 | 
25 | PATH=/bin:/sbin:/usr/bin:/usr/sbin; export PATH
26 | 
27 | # Show a warning if we can't find a safe dir to install BGMXPCHelper in. Should be very unlikely.
28 | xpc_helper_path="$(bash safe_install_dir.sh -y)"
29 | 
30 | if [ "$(bash safe_install_dir.sh "$xpc_helper_path")" != "1" ]; then
31 |     # TODO: This message could be more user friendly.
32 |     msg="We need to install a helper app called BGMXPCHelper to ${xpc_helper_path}, but it may not "
33 |     msg+="be secure to do so.\n\n"
34 |     msg+="${xpc_helper_path} and all of its parent directories should be owned by 'root', with the "
35 |     msg+="group 'wheel', and have permissions 755 (rwxr-xr-x).\n\n"
36 |     msg+="Background Music will still work if you decide to continue."
37 | 
38 |     if [ "$COMMAND_LINE_INSTALL" == "1" ]; then
39 |         # As far as I can tell, we can't print anything the user is likely to see.
40 |         logger "WARNING: $msg"
41 |         exit 1
42 |     else
43 |         if ! osascript <<EOT
44 |             tell application id "com.apple.systemuiserver"
45 |                 display alert "Warning" \
46 |                     message "$msg" \
47 |                     buttons {"Cancel", "Install Anyway"} \
48 |                     default button "Cancel" \
49 |                     cancel button "Cancel" \
50 |                     as warning
51 |             end tell
52 | EOT
53 |         then
54 |             exit 1
55 |         fi
56 |     fi
57 | fi
58 | 
59 | exit 0
60 | 
61 | 
62 | 


--------------------------------------------------------------------------------
/uninstall.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | # vim: tw=120:
 3 | 
 4 | # This file is part of Background Music.
 5 | #
 6 | # Background Music is free software: you can redistribute it and/or
 7 | # modify it under the terms of the GNU General Public License as
 8 | # published by the Free Software Foundation, either version 2 of the
 9 | # License, or (at your option) any later version.
10 | #
11 | # Background Music is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with Background Music. If not, see <http://www.gnu.org/licenses/>.
18 | 
19 | #
20 | # uninstall.sh
21 | #
22 | # Copyright © 2016 Nick Jacques
23 | # Copyright © 2016, 2017 Kyle Neideck
24 | #
25 | # Removes BGMApp, BGMDriver and BGMXPCHelper from the system.
26 | #
27 | 
28 | # Halt on errors.
29 | set -e
30 | 
31 | PATH=/bin:/sbin:/usr/bin:/usr/sbin; export PATH
32 | 
33 | bold=$(tput bold)
34 | normal=$(tput sgr0)
35 | 
36 | # Warn if running as root.
37 | if [[ $(id -u) -eq 0 ]]; then
38 |   echo "$(tput setaf 11)WARNING$(tput sgr0): This script is not intended to be run as root. Run" \
39 |        "it normally and it'll sudo when it needs to." >&2
40 |   echo ""
41 | fi
42 | 
43 | echo "${bold}You are about to uninstall Background Music.${normal}"
44 | echo "Please pause all audio before continuing."
45 | echo ""
46 | read -p "Continue (y/N)? " user_prompt
47 | 
48 | if [ "$user_prompt" == "y" ] || [ "$user_prompt" == "Y" ]; then
49 |   # Run from the dir containing this script.
50 |   cd "$( dirname "${BASH_SOURCE[0]}" )"
51 | 
52 |   if [ -f "BGMApp/BGMApp/_uninstall-non-interactive.sh" ]; then
53 |     # Running from the source directory.
54 |     bash "BGMApp/BGMApp/_uninstall-non-interactive.sh"
55 |   elif [ -f "_uninstall-non-interactive.sh" ]; then
56 |     # Probably running from Background Music.app/Contents/Resources.
57 |     bash "_uninstall-non-interactive.sh"
58 |   else
59 |     echo "${bold}ERROR: Could not find _uninstall-non-interactive.sh${normal}" >&2
60 |     exit 1
61 |   fi
62 | 
63 |   # Invalidate sudo ticket
64 |   sudo -k
65 | 
66 |   # Open System Settings and go to Sound > Output.
67 |   osascript -e 'tell application id "com.apple.systempreferences"
68 |                   activate
69 |                   reveal anchor "output" of pane id "com.apple.preference.sound"
70 |                 end tell' >/dev/null || true
71 |   echo ""
72 | 
73 | else
74 |   echo "Uninstall cancelled."
75 | fi
76 | 
77 | 
78 | 


--------------------------------------------------------------------------------