mirror of
https://github.com/kyleneideck/BackgroundMusic
synced 2024-11-10 06:34:22 +00:00
Add optional debug logging in release builds.
Clicking the status bar icon with the option key held now reveals a setting that enables debug logging in BGMApp. It's enabled by default in debug builds. It doesn't enable debug logging in BGMDriver or BGMXPCHelper yet. This will hopefully make it easier for people to include logs when they report bugs that don't occur with most hardware or are otherwise hard to reproduce. Enabling debug logging should be unlikely to cause audio glitches, but I haven't tried to make it completely safe. Also, - add some basic unit tests for BGMPlayThrough and expand the mocks for the CoreAudio HAL API, - fix the UI tests so you can run them without code signing them, and - update copyright years.
This commit is contained in:
parent
8ca17bb5f8
commit
2c1677305d
56 changed files with 3186 additions and 443 deletions
|
@ -8,12 +8,21 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
19FE7071FF5280BC38F35E1D /* BGMVolumeChangeListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19FE7179EBFA116F3861E79D /* BGMVolumeChangeListener.cpp */; };
|
||||
19FE70F73D26D54450779A22 /* BGMPlayThroughRTLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19FE7DE5E3BA0046ED2BC3C6 /* BGMPlayThroughRTLogger.cpp */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMPlayThroughRTLogger.cpp"; }; };
|
||||
19FE715E7338035C7BCD24E7 /* BGMPlayThroughRTLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19FE7DE5E3BA0046ED2BC3C6 /* BGMPlayThroughRTLogger.cpp */; };
|
||||
19FE719951725A698A419CBA /* BGMVolumeChangeListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19FE7179EBFA116F3861E79D /* BGMVolumeChangeListener.cpp */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMVolumeChangeListener.cpp"; }; };
|
||||
19FE72566BCEB11BD1F3D487 /* BGMMusic.m in Sources */ = {isa = PBXBuildFile; fileRef = 19FE73822ADD50BA9120AB05 /* BGMMusic.m */; };
|
||||
19FE72566BCEB11BD1F3D487 /* BGMMusic.m in Sources */ = {isa = PBXBuildFile; fileRef = 19FE73822ADD50BA9120AB05 /* BGMMusic.m */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMMusic.m"; }; };
|
||||
19FE72D66CBC5C39F86333DE /* BGMPlayThroughRTLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19FE7DE5E3BA0046ED2BC3C6 /* BGMPlayThroughRTLogger.cpp */; };
|
||||
19FE734C861E0370C21E4E94 /* BGMDebugLogging.c in Sources */ = {isa = PBXBuildFile; fileRef = 19FE73389459BF65748F531F /* BGMDebugLogging.c */; };
|
||||
19FE7590D7565E7677D84C55 /* BGMDebugLogging.c in Sources */ = {isa = PBXBuildFile; fileRef = 19FE73389459BF65748F531F /* BGMDebugLogging.c */; };
|
||||
19FE76F614F260F3F65AF550 /* BGMMusic.m in Sources */ = {isa = PBXBuildFile; fileRef = 19FE73822ADD50BA9120AB05 /* BGMMusic.m */; };
|
||||
19FE77608F6C80D0B1F595A7 /* BGMStatusBarItem.mm in Sources */ = {isa = PBXBuildFile; fileRef = 19FE774DD758EC163EF4F28C /* BGMStatusBarItem.mm */; };
|
||||
19FE78EEC6D3C3B19D1FBD64 /* BGMDebugLogging.c in Sources */ = {isa = PBXBuildFile; fileRef = 19FE73389459BF65748F531F /* BGMDebugLogging.c */; };
|
||||
19FE7921FD1B6C037429ECA4 /* BGMStatusBarItem.mm in Sources */ = {isa = PBXBuildFile; fileRef = 19FE774DD758EC163EF4F28C /* BGMStatusBarItem.mm */; };
|
||||
19FE7B32E1214BA0E8166A9E /* BGMMusic.m in Sources */ = {isa = PBXBuildFile; fileRef = 19FE73822ADD50BA9120AB05 /* BGMMusic.m */; };
|
||||
19FE7B7BDF0C683288654F90 /* BGMDebugLogging.c in Sources */ = {isa = PBXBuildFile; fileRef = 19FE73389459BF65748F531F /* BGMDebugLogging.c */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMDebugLogging.c"; }; };
|
||||
19FE7BD48C0CA2CAF16C9ACE /* BGMPlayThroughTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 19FE761D0371DEF9FDF053D6 /* BGMPlayThroughTests.mm */; };
|
||||
19FE7C144C12607D947EB030 /* BGMDebugLogging.c in Sources */ = {isa = PBXBuildFile; fileRef = 19FE73389459BF65748F531F /* BGMDebugLogging.c */; };
|
||||
19FE7DFF63F69E77C53BF95E /* BGMVolumeChangeListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19FE7179EBFA116F3861E79D /* BGMVolumeChangeListener.cpp */; };
|
||||
19FE7F77376562C179449013 /* BGMStatusBarItem.mm in Sources */ = {isa = PBXBuildFile; fileRef = 19FE774DD758EC163EF4F28C /* BGMStatusBarItem.mm */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMStatusBarItem.mm"; }; };
|
||||
1C0BD0A51BF1A8E6004F4CF5 /* BGMAutoPauseMusicPrefs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C0BD0A41BF1A8E6004F4CF5 /* BGMAutoPauseMusicPrefs.mm */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMAutoPauseMusicPrefs.mm"; }; };
|
||||
|
@ -56,6 +65,15 @@
|
|||
1C533C7B1EED2F6200270802 /* safe_install_dir.sh in Resources */ = {isa = PBXBuildFile; fileRef = 276972901CB16008007A2F7C /* safe_install_dir.sh */; };
|
||||
1C533C7C1EED2F8A00270802 /* com.bearisdriving.BGM.XPCHelper.plist.template in Resources */ = {isa = PBXBuildFile; fileRef = 2769728D1CAFCEFD007A2F7C /* com.bearisdriving.BGM.XPCHelper.plist.template */; };
|
||||
1C533C801EF532CA00270802 /* _uninstall-non-interactive.sh in Resources */ = {isa = PBXBuildFile; fileRef = 1C533C7F1EF532CA00270802 /* _uninstall-non-interactive.sh */; };
|
||||
1C62FE4E23D3EB2E00B9B68E /* MockAudioObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C62FE4523D3EB2D00B9B68E /* MockAudioObject.cpp */; };
|
||||
1C62FE4F23D3EB2E00B9B68E /* Mock_CAHALAudioObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C62FE4623D3EB2D00B9B68E /* Mock_CAHALAudioObject.cpp */; };
|
||||
1C62FE5023D3EB2E00B9B68E /* MockAudioObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C62FE4723D3EB2D00B9B68E /* MockAudioObjects.cpp */; };
|
||||
1C62FE5123D3EB2E00B9B68E /* Mock_CAHALAudioSystemObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C62FE4823D3EB2D00B9B68E /* Mock_CAHALAudioSystemObject.cpp */; };
|
||||
1C62FE5223D3EB2E00B9B68E /* Mock_CAHALAudioDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C62FE4A23D3EB2E00B9B68E /* Mock_CAHALAudioDevice.cpp */; };
|
||||
1C62FE5323D3EB2E00B9B68E /* MockAudioDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C62FE4B23D3EB2E00B9B68E /* MockAudioDevice.cpp */; };
|
||||
1C62FE5523D423D700B9B68E /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C62FE5423D423D700B9B68E /* XCTest.framework */; };
|
||||
1C62FE5823D4278300B9B68E /* travis-skip.py in Resources */ = {isa = PBXBuildFile; fileRef = 1C62FE5623D4278300B9B68E /* travis-skip.py */; };
|
||||
1C687A6B23B889E000834B75 /* BGMPlayThroughRTLoggerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C687A6A23B889E000834B75 /* BGMPlayThroughRTLoggerTests.mm */; };
|
||||
1C780FF21FEF6C3B00497FAD /* BGMSystemSoundsVolume.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C780FF11FEF6C3B00497FAD /* BGMSystemSoundsVolume.mm */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMSystemSoundsVolume.mm"; }; };
|
||||
1C780FF31FEF6C3B00497FAD /* BGMSystemSoundsVolume.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C780FF11FEF6C3B00497FAD /* BGMSystemSoundsVolume.mm */; };
|
||||
1C8034D520B0347A004BC50C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C8034D420B0347A004BC50C /* Security.framework */; };
|
||||
|
@ -93,7 +111,6 @@
|
|||
1CC6593E1F91DEB400B0CCDC /* BGMTermination.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CC6593A1F91DEB400B0CCDC /* BGMTermination.mm */; };
|
||||
1CCC4F3E1E58196C008053E4 /* BGMXPCHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CCC4F3C1E58196C008053E4 /* BGMXPCHelperTests.m */; };
|
||||
1CCC4F4D1E581C40008053E4 /* BGMMusicPlayersUnitTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CCC4F4B1E581C40008053E4 /* BGMMusicPlayersUnitTests.mm */; };
|
||||
1CCC4F4E1E581C40008053E4 /* Mock_CAHALAudioObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CCC4F4C1E581C40008053E4 /* Mock_CAHALAudioObject.cpp */; };
|
||||
1CCC4F621E584100008053E4 /* BGMAppUITests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CCC4F611E584100008053E4 /* BGMAppUITests.mm */; };
|
||||
1CD1FD301BDDEAF2004F7E1B /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CD1FD2F1BDDEAF2004F7E1B /* AudioToolbox.framework */; };
|
||||
1CD410D41F9EDDAD0070A094 /* BGMAppVolumesController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CD410D31F9EDDAD0070A094 /* BGMAppVolumesController.mm */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMAppVolumesController.mm"; }; };
|
||||
|
@ -138,9 +155,10 @@
|
|||
1CD989581ECFFD250014BBBF /* CAMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C1963041BCAF468008A4DF7 /* CAMutex.cpp */; };
|
||||
1CD989591ECFFD250014BBBF /* CAPThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C8034C21BDAFD5700668E00 /* CAPThread.cpp */; };
|
||||
1CD9895A1ECFFD250014BBBF /* CARingBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C1962E21BC94E15008A4DF7 /* CARingBuffer.cpp */; };
|
||||
1CE03A57239B56740036908D /* BGMDebugLoggingMenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE03A56239B56740036908D /* BGMDebugLoggingMenuItem.m */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMDebugLoggingMenuItem.m"; }; };
|
||||
1CE03A58239B56740036908D /* BGMDebugLoggingMenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE03A56239B56740036908D /* BGMDebugLoggingMenuItem.m */; };
|
||||
1CE03A59239B56740036908D /* BGMDebugLoggingMenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE03A56239B56740036908D /* BGMDebugLoggingMenuItem.m */; };
|
||||
1CE7064C1BF1EC0600BFC06D /* BGMOutputDeviceMenuSection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CE7064B1BF1EC0600BFC06D /* BGMOutputDeviceMenuSection.mm */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMOutputDeviceMenuSection.mm"; }; };
|
||||
1CEACF4D1F34793700FEC143 /* CAHALAudioDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C1962EB1BCABFC5008A4DF7 /* CAHALAudioDevice.cpp */; };
|
||||
1CEACF4F1F34A30000FEC143 /* Mock_CAHALAudioSystemObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CEACF4E1F34A30000FEC143 /* Mock_CAHALAudioSystemObject.cpp */; };
|
||||
1CED61691C3081C2002CAFCF /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 1CED61681C3081C2002CAFCF /* LICENSE */; };
|
||||
1CED616C1C316E1A002CAFCF /* BGMAudioDeviceManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CED616B1C316E1A002CAFCF /* BGMAudioDeviceManager.mm */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGMAudioDeviceManager.mm"; }; };
|
||||
1CF2D58F1F944773008B6E35 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C1963021BCAC160008A4DF7 /* CoreAudio.framework */; };
|
||||
|
@ -229,9 +247,14 @@
|
|||
/* Begin PBXFileReference section */
|
||||
19FE70CF6C93F5007940CE91 /* BGMMusic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BGMMusic.h; path = "Music Players/BGMMusic.h"; sourceTree = "<group>"; };
|
||||
19FE7179EBFA116F3861E79D /* BGMVolumeChangeListener.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BGMVolumeChangeListener.cpp; sourceTree = "<group>"; };
|
||||
19FE72A176FD500FB4C1F5C6 /* BGMPlayThroughRTLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMPlayThroughRTLogger.h; sourceTree = "<group>"; };
|
||||
19FE73389459BF65748F531F /* BGMDebugLogging.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = BGMDebugLogging.c; path = PublicUtility/BGMDebugLogging.c; sourceTree = "<group>"; };
|
||||
19FE73822ADD50BA9120AB05 /* BGMMusic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BGMMusic.m; path = "Music Players/BGMMusic.m"; sourceTree = "<group>"; };
|
||||
19FE761D0371DEF9FDF053D6 /* BGMPlayThroughTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BGMPlayThroughTests.mm; path = UnitTests/BGMPlayThroughTests.mm; sourceTree = "<group>"; };
|
||||
19FE774DD758EC163EF4F28C /* BGMStatusBarItem.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BGMStatusBarItem.mm; sourceTree = "<group>"; };
|
||||
19FE7908A33FA7BD97B432D9 /* BGMDebugLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BGMDebugLogging.h; path = PublicUtility/BGMDebugLogging.h; sourceTree = "<group>"; };
|
||||
19FE799A86A285DD9423D164 /* BGMStatusBarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMStatusBarItem.h; sourceTree = "<group>"; };
|
||||
19FE7DE5E3BA0046ED2BC3C6 /* BGMPlayThroughRTLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BGMPlayThroughRTLogger.cpp; sourceTree = "<group>"; };
|
||||
19FE7FDAEBC3F0DB8C99823B /* BGMVolumeChangeListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMVolumeChangeListener.h; sourceTree = "<group>"; };
|
||||
1C0BD0A31BF1A8E6004F4CF5 /* BGMAutoPauseMusicPrefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BGMAutoPauseMusicPrefs.h; path = Preferences/BGMAutoPauseMusicPrefs.h; sourceTree = "<group>"; };
|
||||
1C0BD0A41BF1A8E6004F4CF5 /* BGMAutoPauseMusicPrefs.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BGMAutoPauseMusicPrefs.mm; path = Preferences/BGMAutoPauseMusicPrefs.mm; sourceTree = "<group>"; };
|
||||
|
@ -282,7 +305,7 @@
|
|||
1C3D36711ED90E8600F98E66 /* BGMDeviceControlsList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMDeviceControlsList.h; sourceTree = "<group>"; };
|
||||
1C3DB4881BE0885A00EC8160 /* BGMAppVolumes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BGMAppVolumes.m; sourceTree = "<group>"; };
|
||||
1C3DB48A1BE0888500EC8160 /* BGMAppVolumes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMAppVolumes.h; sourceTree = "<group>"; };
|
||||
1C43DABE22F582780004AF35 /* Background Music.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Background Music.entitlements"; sourceTree = "<group>"; };
|
||||
1C43DABE22F582780004AF35 /* BGMApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BGMApp.entitlements; sourceTree = "<group>"; };
|
||||
1C4699461BD5C0E400F78043 /* BGMiTunes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BGMiTunes.m; path = "Music Players/BGMiTunes.m"; sourceTree = "<group>"; };
|
||||
1C46994C1BD7694C00F78043 /* BGMDeviceControlSync.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BGMDeviceControlSync.cpp; sourceTree = "<group>"; };
|
||||
1C46994D1BD7694C00F78043 /* BGMDeviceControlSync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMDeviceControlSync.h; sourceTree = "<group>"; };
|
||||
|
@ -290,6 +313,19 @@
|
|||
1C4D1A1C217C7D6400A1ACD0 /* BGMPreferredOutputDevices.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = BGMPreferredOutputDevices.mm; sourceTree = "<group>"; };
|
||||
1C533C791EED28B700270802 /* uninstall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = uninstall.sh; path = ../../uninstall.sh; sourceTree = "<group>"; };
|
||||
1C533C7F1EF532CA00270802 /* _uninstall-non-interactive.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "_uninstall-non-interactive.sh"; sourceTree = "<group>"; };
|
||||
1C62FE4523D3EB2D00B9B68E /* MockAudioObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MockAudioObject.cpp; path = BGMAppTests/UnitTests/Mocks/MockAudioObject.cpp; sourceTree = SOURCE_ROOT; };
|
||||
1C62FE4623D3EB2D00B9B68E /* Mock_CAHALAudioObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mock_CAHALAudioObject.cpp; path = BGMAppTests/UnitTests/Mocks/Mock_CAHALAudioObject.cpp; sourceTree = SOURCE_ROOT; };
|
||||
1C62FE4723D3EB2D00B9B68E /* MockAudioObjects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MockAudioObjects.cpp; path = BGMAppTests/UnitTests/Mocks/MockAudioObjects.cpp; sourceTree = SOURCE_ROOT; };
|
||||
1C62FE4823D3EB2D00B9B68E /* Mock_CAHALAudioSystemObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mock_CAHALAudioSystemObject.cpp; path = BGMAppTests/UnitTests/Mocks/Mock_CAHALAudioSystemObject.cpp; sourceTree = SOURCE_ROOT; };
|
||||
1C62FE4923D3EB2E00B9B68E /* MockAudioDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MockAudioDevice.h; path = BGMAppTests/UnitTests/Mocks/MockAudioDevice.h; sourceTree = SOURCE_ROOT; };
|
||||
1C62FE4A23D3EB2E00B9B68E /* Mock_CAHALAudioDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mock_CAHALAudioDevice.cpp; path = BGMAppTests/UnitTests/Mocks/Mock_CAHALAudioDevice.cpp; sourceTree = SOURCE_ROOT; };
|
||||
1C62FE4B23D3EB2E00B9B68E /* MockAudioDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MockAudioDevice.cpp; path = BGMAppTests/UnitTests/Mocks/MockAudioDevice.cpp; sourceTree = SOURCE_ROOT; };
|
||||
1C62FE4C23D3EB2E00B9B68E /* MockAudioObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MockAudioObject.h; path = BGMAppTests/UnitTests/Mocks/MockAudioObject.h; sourceTree = SOURCE_ROOT; };
|
||||
1C62FE4D23D3EB2E00B9B68E /* MockAudioObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MockAudioObjects.h; path = BGMAppTests/UnitTests/Mocks/MockAudioObjects.h; sourceTree = SOURCE_ROOT; };
|
||||
1C62FE5423D423D700B9B68E /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/MacOSX.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
|
||||
1C62FE5623D4278300B9B68E /* travis-skip.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = "travis-skip.py"; path = "UITests/travis-skip.py"; sourceTree = "<group>"; };
|
||||
1C62FE5923D44FC000B9B68E /* BGMApp-Debug.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "BGMApp-Debug.entitlements"; sourceTree = "<group>"; };
|
||||
1C687A6A23B889E000834B75 /* BGMPlayThroughRTLoggerTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = BGMPlayThroughRTLoggerTests.mm; path = UnitTests/BGMPlayThroughRTLoggerTests.mm; sourceTree = "<group>"; };
|
||||
1C780FF01FEF6C3B00497FAD /* BGMSystemSoundsVolume.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BGMSystemSoundsVolume.h; sourceTree = "<group>"; };
|
||||
1C780FF11FEF6C3B00497FAD /* BGMSystemSoundsVolume.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = BGMSystemSoundsVolume.mm; sourceTree = "<group>"; };
|
||||
1C8034C21BDAFD5700668E00 /* CAPThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CAPThread.cpp; path = PublicUtility/CAPThread.cpp; sourceTree = "<group>"; };
|
||||
|
@ -329,7 +365,6 @@
|
|||
1CCC4F3C1E58196C008053E4 /* BGMXPCHelperTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BGMXPCHelperTests.m; path = BGMXPCHelperTests/BGMXPCHelperTests.m; sourceTree = SOURCE_ROOT; };
|
||||
1CCC4F491E581C0D008053E4 /* BGMAppUnitTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "BGMAppUnitTests-Info.plist"; path = "UnitTests/BGMAppUnitTests-Info.plist"; sourceTree = "<group>"; };
|
||||
1CCC4F4B1E581C40008053E4 /* BGMMusicPlayersUnitTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BGMMusicPlayersUnitTests.mm; path = UnitTests/BGMMusicPlayersUnitTests.mm; sourceTree = "<group>"; };
|
||||
1CCC4F4C1E581C40008053E4 /* Mock_CAHALAudioObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mock_CAHALAudioObject.cpp; path = UnitTests/Mock_CAHALAudioObject.cpp; sourceTree = "<group>"; };
|
||||
1CCC4F541E584081008053E4 /* BGMAppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BGMAppUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
1CCC4F5F1E5840EF008053E4 /* BGMAppUITests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "BGMAppUITests-Info.plist"; path = "UITests/BGMAppUITests-Info.plist"; sourceTree = "<group>"; };
|
||||
1CCC4F611E584100008053E4 /* BGMAppUITests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BGMAppUITests.mm; path = BGMAppTests/UITests/BGMAppUITests.mm; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -337,9 +372,10 @@
|
|||
1CD410D21F9EDDAD0070A094 /* BGMAppVolumesController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BGMAppVolumesController.h; sourceTree = "<group>"; };
|
||||
1CD410D31F9EDDAD0070A094 /* BGMAppVolumesController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = BGMAppVolumesController.mm; sourceTree = "<group>"; };
|
||||
1CDE224022CBB95B0008E3AC /* Music.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Music.h; path = "Music Players/Music.h"; sourceTree = "<group>"; };
|
||||
1CE03A55239B56740036908D /* BGMDebugLoggingMenuItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BGMDebugLoggingMenuItem.h; sourceTree = "<group>"; };
|
||||
1CE03A56239B56740036908D /* BGMDebugLoggingMenuItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BGMDebugLoggingMenuItem.m; sourceTree = "<group>"; };
|
||||
1CE7064A1BF1EC0600BFC06D /* BGMOutputDeviceMenuSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMOutputDeviceMenuSection.h; sourceTree = "<group>"; };
|
||||
1CE7064B1BF1EC0600BFC06D /* BGMOutputDeviceMenuSection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BGMOutputDeviceMenuSection.mm; sourceTree = "<group>"; };
|
||||
1CEACF4E1F34A30000FEC143 /* Mock_CAHALAudioSystemObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mock_CAHALAudioSystemObject.cpp; path = UnitTests/Mock_CAHALAudioSystemObject.cpp; sourceTree = "<group>"; };
|
||||
1CED61681C3081C2002CAFCF /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
1CED616A1C316E1A002CAFCF /* BGMAudioDeviceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGMAudioDeviceManager.h; sourceTree = "<group>"; };
|
||||
1CED616B1C316E1A002CAFCF /* BGMAudioDeviceManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BGMAudioDeviceManager.mm; sourceTree = "<group>"; };
|
||||
|
@ -414,6 +450,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1C62FE5523D423D700B9B68E /* XCTest.framework in Frameworks */,
|
||||
1C8B0C6B21645355008C5679 /* AVFoundation.framework in Frameworks */,
|
||||
1CD989401ECFFCC50014BBBF /* AudioToolbox.framework in Frameworks */,
|
||||
);
|
||||
|
@ -499,6 +536,8 @@
|
|||
1C8034C31BDAFD5700668E00 /* CAPThread.h */,
|
||||
1C1962E21BC94E15008A4DF7 /* CARingBuffer.cpp */,
|
||||
1C1962E31BC94E15008A4DF7 /* CARingBuffer.h */,
|
||||
19FE7908A33FA7BD97B432D9 /* BGMDebugLogging.h */,
|
||||
19FE73389459BF65748F531F /* BGMDebugLogging.c */,
|
||||
);
|
||||
name = PublicUtility;
|
||||
sourceTree = "<group>";
|
||||
|
@ -561,10 +600,25 @@
|
|||
name = "Music Players";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1C62FE4423D3EAC500B9B68E /* Mocks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C62FE4823D3EB2D00B9B68E /* Mock_CAHALAudioSystemObject.cpp */,
|
||||
1C62FE4623D3EB2D00B9B68E /* Mock_CAHALAudioObject.cpp */,
|
||||
1C62FE4A23D3EB2E00B9B68E /* Mock_CAHALAudioDevice.cpp */,
|
||||
1C62FE4D23D3EB2E00B9B68E /* MockAudioObjects.h */,
|
||||
1C62FE4723D3EB2D00B9B68E /* MockAudioObjects.cpp */,
|
||||
1C62FE4C23D3EB2E00B9B68E /* MockAudioObject.h */,
|
||||
1C62FE4523D3EB2D00B9B68E /* MockAudioObject.cpp */,
|
||||
1C62FE4923D3EB2E00B9B68E /* MockAudioDevice.h */,
|
||||
1C62FE4B23D3EB2E00B9B68E /* MockAudioDevice.cpp */,
|
||||
);
|
||||
path = Mocks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1CB8B32D1BBA75EF000E2DD1 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C43DABE22F582780004AF35 /* Background Music.entitlements */,
|
||||
1CB8B3381BBA75EF000E2DD1 /* BGMApp */,
|
||||
1CB8B34C1BBA75F0000E2DD1 /* BGMApp Tests */,
|
||||
27379B901C7F57DB0084A24C /* BGMXPCHelper */,
|
||||
|
@ -598,6 +652,8 @@
|
|||
1C80DED220A6718600045BBE /* BGMAppWatcher.m */,
|
||||
1C837DD61F6AA1F2004B1E60 /* BGMOutputVolumeMenuItem.h */,
|
||||
1C837DD71F6AA1F2004B1E60 /* BGMOutputVolumeMenuItem.mm */,
|
||||
1CE03A55239B56740036908D /* BGMDebugLoggingMenuItem.h */,
|
||||
1CE03A56239B56740036908D /* BGMDebugLoggingMenuItem.m */,
|
||||
1C780FF01FEF6C3B00497FAD /* BGMSystemSoundsVolume.h */,
|
||||
1C780FF11FEF6C3B00497FAD /* BGMSystemSoundsVolume.mm */,
|
||||
1C3DB48A1BE0888500EC8160 /* BGMAppVolumes.h */,
|
||||
|
@ -626,6 +682,8 @@
|
|||
1C3D36701ED90E8600F98E66 /* BGMDeviceControlsList.cpp */,
|
||||
1C1962E61BC94E91008A4DF7 /* BGMPlayThrough.h */,
|
||||
1C1962E51BC94E91008A4DF7 /* BGMPlayThrough.cpp */,
|
||||
19FE72A176FD500FB4C1F5C6 /* BGMPlayThroughRTLogger.h */,
|
||||
19FE7DE5E3BA0046ED2BC3C6 /* BGMPlayThroughRTLogger.cpp */,
|
||||
19FE799A86A285DD9423D164 /* BGMStatusBarItem.h */,
|
||||
19FE774DD758EC163EF4F28C /* BGMStatusBarItem.mm */,
|
||||
1CC6593B1F91DEB400B0CCDC /* BGMTermination.h */,
|
||||
|
@ -646,6 +704,8 @@
|
|||
1CB8B3391BBA75EF000E2DD1 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C43DABE22F582780004AF35 /* BGMApp.entitlements */,
|
||||
1C62FE5923D44FC000B9B68E /* BGMApp-Debug.entitlements */,
|
||||
275343BF1DFD01BC00DF3858 /* SystemPreferences.h */,
|
||||
1CED61681C3081C2002CAFCF /* LICENSE */,
|
||||
1CC1DF951BE8607700FB8FE4 /* Images.xcassets */,
|
||||
|
@ -691,6 +751,7 @@
|
|||
children = (
|
||||
1CCC4F5F1E5840EF008053E4 /* BGMAppUITests-Info.plist */,
|
||||
1CCC4F491E581C0D008053E4 /* BGMAppUnitTests-Info.plist */,
|
||||
1C62FE5623D4278300B9B68E /* travis-skip.py */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
|
@ -699,8 +760,9 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
1CCC4F4B1E581C40008053E4 /* BGMMusicPlayersUnitTests.mm */,
|
||||
1CCC4F4C1E581C40008053E4 /* Mock_CAHALAudioObject.cpp */,
|
||||
1CEACF4E1F34A30000FEC143 /* Mock_CAHALAudioSystemObject.cpp */,
|
||||
19FE761D0371DEF9FDF053D6 /* BGMPlayThroughTests.mm */,
|
||||
1C687A6A23B889E000834B75 /* BGMPlayThroughRTLoggerTests.mm */,
|
||||
1C62FE4423D3EAC500B9B68E /* Mocks */,
|
||||
);
|
||||
name = "Unit Tests";
|
||||
sourceTree = "<group>";
|
||||
|
@ -756,6 +818,7 @@
|
|||
2743CA1B1D86DA9B0089613B /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1C62FE5423D423D700B9B68E /* XCTest.framework */,
|
||||
1C8034D420B0347A004BC50C /* Security.framework */,
|
||||
1C8B0C69216205BF008C5679 /* AVFoundation.framework */,
|
||||
270A84501E0044EE00F13C99 /* ScriptingBridge.framework */,
|
||||
|
@ -902,7 +965,7 @@
|
|||
};
|
||||
2743C9F51D86CFF90089613B = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
ProvisioningStyle = Automatic;
|
||||
ProvisioningStyle = Manual;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -948,6 +1011,7 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1C62FE5823D4278300B9B68E /* travis-skip.py in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1013,6 +1077,7 @@
|
|||
files = (
|
||||
1C86DA6A1F91EE3B000C8CCF /* CAPThread.cpp in Sources */,
|
||||
1C780FF21FEF6C3B00497FAD /* BGMSystemSoundsVolume.mm in Sources */,
|
||||
1CE03A57239B56740036908D /* BGMDebugLoggingMenuItem.m in Sources */,
|
||||
1C4699471BD5C0E400F78043 /* BGMiTunes.m in Sources */,
|
||||
1CD410D41F9EDDAD0070A094 /* BGMAppVolumesController.mm in Sources */,
|
||||
1C1962E41BC94E15008A4DF7 /* CARingBuffer.cpp in Sources */,
|
||||
|
@ -1067,6 +1132,8 @@
|
|||
19FE7F77376562C179449013 /* BGMStatusBarItem.mm in Sources */,
|
||||
19FE719951725A698A419CBA /* BGMVolumeChangeListener.cpp in Sources */,
|
||||
19FE72566BCEB11BD1F3D487 /* BGMMusic.m in Sources */,
|
||||
19FE70F73D26D54450779A22 /* BGMPlayThroughRTLogger.cpp in Sources */,
|
||||
19FE7B7BDF0C683288654F90 /* BGMDebugLogging.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1076,6 +1143,7 @@
|
|||
files = (
|
||||
1C8104B022AD082E00B35517 /* BGMGooglePlayMusicDesktopPlayer.m in Sources */,
|
||||
1C8D830520423E1C00A838F2 /* BGMSwinsian.m in Sources */,
|
||||
1CE03A58239B56740036908D /* BGMDebugLoggingMenuItem.m in Sources */,
|
||||
1CACCF3A1F334447007F86CA /* BGMBackgroundMusicDevice.cpp in Sources */,
|
||||
1C780FF31FEF6C3B00497FAD /* BGMSystemSoundsVolume.mm in Sources */,
|
||||
1CC6593D1F91DEB400B0CCDC /* BGMTermination.mm in Sources */,
|
||||
|
@ -1130,6 +1198,8 @@
|
|||
19FE7921FD1B6C037429ECA4 /* BGMStatusBarItem.mm in Sources */,
|
||||
19FE7DFF63F69E77C53BF95E /* BGMVolumeChangeListener.cpp in Sources */,
|
||||
19FE7B32E1214BA0E8166A9E /* BGMMusic.m in Sources */,
|
||||
19FE72D66CBC5C39F86333DE /* BGMPlayThroughRTLogger.cpp in Sources */,
|
||||
19FE734C861E0370C21E4E94 /* BGMDebugLogging.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1158,6 +1228,7 @@
|
|||
27D643C01C9FB99200737F6E /* BGMXPCHelperService.mm in Sources */,
|
||||
27D643C11C9FB99200737F6E /* main.m in Sources */,
|
||||
277170161CA24D7C00AB34B4 /* BGMXPCListenerDelegate.m in Sources */,
|
||||
19FE7590D7565E7677D84C55 /* BGMDebugLogging.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1165,10 +1236,10 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1C62FE5123D3EB2E00B9B68E /* Mock_CAHALAudioSystemObject.cpp in Sources */,
|
||||
1C8104AF22AD07E200B35517 /* BGMAppWatcher.m in Sources */,
|
||||
1C8D830620423E2400A838F2 /* BGMSwinsian.m in Sources */,
|
||||
1C227C0B1FA4C48200A95B6D /* BGMAppVolumes.m in Sources */,
|
||||
1CEACF4D1F34793700FEC143 /* CAHALAudioDevice.cpp in Sources */,
|
||||
1CACCF3B1F334450007F86CA /* BGMBackgroundMusicDevice.cpp in Sources */,
|
||||
1C8D830C2042DE9600A838F2 /* BGMGooglePlayMusicDesktopPlayer.m in Sources */,
|
||||
1C3D36741ED90E8600F98E66 /* BGMDeviceControlsList.cpp in Sources */,
|
||||
|
@ -1176,14 +1247,16 @@
|
|||
27FB8C311DE4758A0084DB9D /* BGM_Utils.cpp in Sources */,
|
||||
27FB8C071DD75D0A0084DB9D /* BGMHermes.m in Sources */,
|
||||
2743CA211D86DE780089613B /* BGMDeviceControlSync.cpp in Sources */,
|
||||
1CE03A59239B56740036908D /* BGMDebugLoggingMenuItem.m in Sources */,
|
||||
2743CA0C1D86D7FA0089613B /* CACFArray.cpp in Sources */,
|
||||
1C837DDA1F6AA1F2004B1E60 /* BGMOutputVolumeMenuItem.mm in Sources */,
|
||||
2743CA0D1D86D7FA0089613B /* CACFDictionary.cpp in Sources */,
|
||||
2743CA0E1D86D7FA0089613B /* CACFNumber.cpp in Sources */,
|
||||
2743CA0F1D86D7FA0089613B /* CACFString.cpp in Sources */,
|
||||
1CCC4F4E1E581C40008053E4 /* Mock_CAHALAudioObject.cpp in Sources */,
|
||||
2743CA101D86D7FA0089613B /* CADebugger.cpp in Sources */,
|
||||
1C687A6B23B889E000834B75 /* BGMPlayThroughRTLoggerTests.mm in Sources */,
|
||||
2743CA111D86D7FA0089613B /* CADebugMacros.cpp in Sources */,
|
||||
1C62FE4F23D3EB2E00B9B68E /* Mock_CAHALAudioObject.cpp in Sources */,
|
||||
2743CA121D86D7FA0089613B /* CADebugPrintf.cpp in Sources */,
|
||||
1CCC4F4D1E581C40008053E4 /* BGMMusicPlayersUnitTests.mm in Sources */,
|
||||
2743CA141D86D7FA0089613B /* CAHALAudioStream.cpp in Sources */,
|
||||
|
@ -1193,7 +1266,6 @@
|
|||
2743CA191D86D7FA0089613B /* CARingBuffer.cpp in Sources */,
|
||||
2743CA0A1D86D52D0089613B /* BGMAudioDeviceManager.mm in Sources */,
|
||||
2743CA031D86D41C0089613B /* BGMScriptingBridge.m in Sources */,
|
||||
1CEACF4F1F34A30000FEC143 /* Mock_CAHALAudioSystemObject.cpp in Sources */,
|
||||
2743CA041D86D41C0089613B /* BGMMusicPlayer.m in Sources */,
|
||||
1CD410D61F9EDDAD0070A094 /* BGMAppVolumesController.mm in Sources */,
|
||||
2743CA051D86D41C0089613B /* BGMDecibel.m in Sources */,
|
||||
|
@ -1201,14 +1273,21 @@
|
|||
2743CA071D86D41C0089613B /* BGMVLC.m in Sources */,
|
||||
1CF5423D1EAAEE4300445AD8 /* BGMAudioDevice.cpp in Sources */,
|
||||
2743CA081D86D41C0089613B /* BGMVOX.m in Sources */,
|
||||
1C62FE5223D3EB2E00B9B68E /* Mock_CAHALAudioDevice.cpp in Sources */,
|
||||
1C62FE5323D3EB2E00B9B68E /* MockAudioDevice.cpp in Sources */,
|
||||
2743CA091D86D41C0089613B /* BGMUserDefaults.m in Sources */,
|
||||
1C62FE5023D3EB2E00B9B68E /* MockAudioObjects.cpp in Sources */,
|
||||
1CC6593E1F91DEB400B0CCDC /* BGMTermination.mm in Sources */,
|
||||
2743CA011D86D3CB0089613B /* BGMMusicPlayers.mm in Sources */,
|
||||
1C62FE4E23D3EB2E00B9B68E /* MockAudioObject.cpp in Sources */,
|
||||
2743CA021D86D3CB0089613B /* BGMiTunes.m in Sources */,
|
||||
19FE77608F6C80D0B1F595A7 /* BGMStatusBarItem.mm in Sources */,
|
||||
19FE7071FF5280BC38F35E1D /* BGMVolumeChangeListener.cpp in Sources */,
|
||||
1C9258492090287F00B8D3A6 /* BGMGooglePlayMusicDesktopPlayerConnection.m in Sources */,
|
||||
19FE76F614F260F3F65AF550 /* BGMMusic.m in Sources */,
|
||||
19FE715E7338035C7BCD24E7 /* BGMPlayThroughRTLogger.cpp in Sources */,
|
||||
19FE78EEC6D3C3B19D1FBD64 /* BGMDebugLogging.c in Sources */,
|
||||
19FE7BD48C0CA2CAF16C9ACE /* BGMPlayThroughTests.mm in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1217,6 +1296,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1CCC4F3E1E58196C008053E4 /* BGMXPCHelperTests.m in Sources */,
|
||||
19FE7C144C12607D947EB030 /* BGMDebugLogging.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1336,13 +1416,12 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_USE_OPTIMIZATION_PROFILE = NO;
|
||||
CODE_SIGN_ENTITLEMENTS = "Background Music.entitlements";
|
||||
CODE_SIGN_ENTITLEMENTS = "BGMApp/BGMApp-Debug.entitlements";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEPLOYMENT_POSTPROCESSING = NO;
|
||||
DWARF_DSYM_FILE_NAME = "$(EXECUTABLE_NAME).dSYM";
|
||||
DWARF_DSYM_FOLDER_PATH = "$(CONFIGURATION_BUILD_DIR)/$(EXECUTABLE_FOLDER_PATH)";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
INFOPLIST_FILE = BGMApp/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
|
@ -1522,13 +1601,12 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_USE_OPTIMIZATION_PROFILE = NO;
|
||||
CODE_SIGN_ENTITLEMENTS = "Background Music.entitlements";
|
||||
CODE_SIGN_ENTITLEMENTS = "BGMApp/BGMApp-Debug.entitlements";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEPLOYMENT_POSTPROCESSING = NO;
|
||||
DWARF_DSYM_FILE_NAME = "$(EXECUTABLE_NAME).dSYM";
|
||||
DWARF_DSYM_FOLDER_PATH = "$(CONFIGURATION_BUILD_DIR)/$(EXECUTABLE_FOLDER_PATH)";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
INFOPLIST_FILE = BGMApp/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
|
@ -1544,13 +1622,21 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_USE_OPTIMIZATION_PROFILE = NO;
|
||||
CODE_SIGN_ENTITLEMENTS = "Background Music.entitlements";
|
||||
CODE_SIGN_ENTITLEMENTS = BGMApp/BGMApp.entitlements;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEPLOYMENT_POSTPROCESSING = YES;
|
||||
DWARF_DSYM_FILE_NAME = "$(EXECUTABLE_NAME).dSYM";
|
||||
DWARF_DSYM_FOLDER_PATH = "$(CONFIGURATION_BUILD_DIR)/$(EXECUTABLE_FOLDER_PATH)";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=0",
|
||||
"CoreAudio_Debug=0",
|
||||
"CoreAudio_StopOnAssert=0",
|
||||
"BGM_StopDebuggerOnLoggedExceptions=$(BGM_STOP_DEBUGGER_ON_LOGGED_EXCEPTIONS)",
|
||||
"BGM_StopDebuggerOnLoggedUnexpectedExceptions=$(BGM_STOP_DEBUGGER_ON_LOGGED_UNEXPECTED_EXCEPTIONS)",
|
||||
"CoreAudio_StopOnThrow=0",
|
||||
"CoreAudio_UseSysLog=1",
|
||||
);
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
INFOPLIST_FILE = BGMApp/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
|
@ -1568,14 +1654,17 @@
|
|||
1CCC4F5C1E584081008053E4 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "BGMApp/BGMApp-Debug.entitlements";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = "BGMAppTests/UITests/BGMAppUITests-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.bearisdriving.BGM.AppUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
TEST_TARGET_NAME = "Background Music";
|
||||
WARNING_CFLAGS = "";
|
||||
};
|
||||
|
@ -1584,13 +1673,16 @@
|
|||
1CCC4F5D1E584081008053E4 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "BGMApp/BGMApp-Debug.entitlements";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = "BGMAppTests/UITests/BGMAppUITests-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.bearisdriving.BGM.AppUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
TEST_TARGET_NAME = "Background Music";
|
||||
WARNING_CFLAGS = "";
|
||||
};
|
||||
|
@ -1599,14 +1691,17 @@
|
|||
1CCC4F5E1E584081008053E4 /* DebugOpt */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "BGMApp/BGMApp-Debug.entitlements";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = "BGMAppTests/UITests/BGMAppUITests-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.bearisdriving.BGM.AppUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
TEST_TARGET_NAME = "Background Music";
|
||||
WARNING_CFLAGS = "";
|
||||
};
|
||||
|
@ -1672,11 +1767,25 @@
|
|||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"CoreAudio_Debug=1",
|
||||
"CoreAudio_UseSysLog=1",
|
||||
"CoreAudio_StopOnAssert=1",
|
||||
"CoreAudio_ThreadStampMessages=0",
|
||||
"BGM_StopDebuggerOnLoggedExceptions=$(BGM_STOP_DEBUGGER_ON_LOGGED_EXCEPTIONS)",
|
||||
"BGM_StopDebuggerOnLoggedUnexpectedExceptions=$(BGM_STOP_DEBUGGER_ON_LOGGED_UNEXPECTED_EXCEPTIONS)",
|
||||
"CoreAudio_StopOnThrow=0",
|
||||
"BGM_UnitTest=1",
|
||||
);
|
||||
INFOPLIST_FILE = "BGMAppTests/UnitTests/BGMAppUnitTests-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.bearisdriving.BGM.AppUnitTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
WARNING_CFLAGS = "";
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -1689,11 +1798,23 @@
|
|||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=0",
|
||||
"CoreAudio_Debug=0",
|
||||
"CoreAudio_StopOnAssert=0",
|
||||
"BGM_StopDebuggerOnLoggedExceptions=$(BGM_STOP_DEBUGGER_ON_LOGGED_EXCEPTIONS)",
|
||||
"BGM_StopDebuggerOnLoggedUnexpectedExceptions=$(BGM_STOP_DEBUGGER_ON_LOGGED_UNEXPECTED_EXCEPTIONS)",
|
||||
"CoreAudio_StopOnThrow=0",
|
||||
"BGM_UnitTest=1",
|
||||
);
|
||||
INFOPLIST_FILE = "BGMAppTests/UnitTests/BGMAppUnitTests-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.bearisdriving.BGM.AppUnitTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
WARNING_CFLAGS = "";
|
||||
};
|
||||
name = Release;
|
||||
|
@ -1706,11 +1827,25 @@
|
|||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"CoreAudio_Debug=1",
|
||||
"CoreAudio_UseSysLog=1",
|
||||
"CoreAudio_StopOnAssert=1",
|
||||
"CoreAudio_ThreadStampMessages=0",
|
||||
"BGM_StopDebuggerOnLoggedExceptions=$(BGM_STOP_DEBUGGER_ON_LOGGED_EXCEPTIONS)",
|
||||
"BGM_StopDebuggerOnLoggedUnexpectedExceptions=$(BGM_STOP_DEBUGGER_ON_LOGGED_UNEXPECTED_EXCEPTIONS)",
|
||||
"CoreAudio_StopOnThrow=0",
|
||||
"BGM_UnitTest=1",
|
||||
);
|
||||
INFOPLIST_FILE = "BGMAppTests/UnitTests/BGMAppUnitTests-Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.bearisdriving.BGM.AppUnitTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
WARNING_CFLAGS = "";
|
||||
};
|
||||
name = DebugOpt;
|
||||
|
|
|
@ -26,9 +26,42 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
enableAddressSanitizer = "YES"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
enableUBSanitizer = "YES"
|
||||
codeCoverageEnabled = "YES"
|
||||
onlyGenerateCoverageForSpecifiedTargets = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "27379B8E1C7F57DA0084A24C"
|
||||
BuildableName = "BGMXPCHelper.xpc"
|
||||
BlueprintName = "BGMXPCHelper"
|
||||
ReferencedContainer = "container:BGMApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
<AdditionalOption
|
||||
key = "NSZombieEnabled"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
<AdditionalOption
|
||||
key = "MallocScribble"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "27379B8E1C7F57DA0084A24C"
|
||||
BuildableName = "BGMXPCHelper.xpc"
|
||||
BlueprintName = "BGMXPCHelper"
|
||||
ReferencedContainer = "container:BGMApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</CodeCoverageTargets>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
|
@ -41,24 +74,14 @@
|
|||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "27379B8E1C7F57DA0084A24C"
|
||||
BuildableName = "BGMXPCHelper.xpc"
|
||||
BlueprintName = "BGMXPCHelper"
|
||||
ReferencedContainer = "container:BGMApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
enableAddressSanitizer = "YES"
|
||||
language = ""
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
enableUBSanitizer = "YES"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -82,6 +105,16 @@
|
|||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
<AdditionalOption
|
||||
key = "NSZombieEnabled"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
<AdditionalOption
|
||||
key = "MallocScribble"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
|
|
|
@ -26,11 +26,47 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
enableAddressSanitizer = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
enableUBSanitizer = "YES"
|
||||
codeCoverageEnabled = "YES"
|
||||
onlyGenerateCoverageForSpecifiedTargets = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1CB8B3351BBA75EF000E2DD1"
|
||||
BuildableName = "Background Music.app"
|
||||
BlueprintName = "Background Music"
|
||||
ReferencedContainer = "container:BGMApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
<AdditionalOption
|
||||
key = "NSZombieEnabled"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
<AdditionalOption
|
||||
key = "MallocScribble"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1CB8B3351BBA75EF000E2DD1"
|
||||
BuildableName = "Background Music.app"
|
||||
BlueprintName = "Background Music"
|
||||
ReferencedContainer = "container:BGMApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</CodeCoverageTargets>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
skipped = "NO"
|
||||
parallelizable = "YES"
|
||||
testExecutionOrdering = "random">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2743C9F51D86CFF90089613B"
|
||||
|
@ -50,23 +86,14 @@
|
|||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1CB8B3351BBA75EF000E2DD1"
|
||||
BuildableName = "Background Music.app"
|
||||
BlueprintName = "Background Music"
|
||||
ReferencedContainer = "container:BGMApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
enableAddressSanitizer = "YES"
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
enableUBSanitizer = "YES"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -101,6 +128,16 @@
|
|||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
<AdditionalOption
|
||||
key = "NSZombieEnabled"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
<AdditionalOption
|
||||
key = "MallocScribble"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
|
|
15
BGMApp/BGMApp/BGMApp-Debug.entitlements
Normal file
15
BGMApp/BGMApp/BGMApp-Debug.entitlements
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.automation.apple-events</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<!--
|
||||
Without this key, AddressSanitizer and the UI tests would only work when BGMApp is code signed.
|
||||
-->
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -17,7 +17,7 @@
|
|||
// BGMAppDelegate.h
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
// Copyright © 2016, 2017, 2020 Kyle Neideck
|
||||
//
|
||||
// Sets up and tears down the app.
|
||||
//
|
||||
|
@ -50,6 +50,7 @@ static NSInteger const kSeparatorBelowVolumesMenuItemTag = 4;
|
|||
@property (unsafe_unretained) IBOutlet NSTextView* aboutPanelLicenseView;
|
||||
|
||||
@property (weak) IBOutlet NSMenuItem* autoPauseMenuItemUnwrapped;
|
||||
@property (weak) IBOutlet NSMenuItem* debugLoggingMenuItemUnwrapped;
|
||||
|
||||
@property (readonly) BGMAudioDeviceManager* audioDevices;
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// BGMAppDelegate.mm
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2016-2019 Kyle Neideck
|
||||
// Copyright © 2016-2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
|
@ -28,6 +28,7 @@
|
|||
#import "BGMAppVolumesController.h"
|
||||
#import "BGMAutoPauseMusic.h"
|
||||
#import "BGMAutoPauseMenuItem.h"
|
||||
#import "BGMDebugLoggingMenuItem.h"
|
||||
#import "BGMMusicPlayers.h"
|
||||
#import "BGMOutputDeviceMenuSection.h"
|
||||
#import "BGMOutputVolumeMenuItem.h"
|
||||
|
@ -66,6 +67,7 @@ static NSString* const kOptShowDockIcon = @"--show-dock-icon";
|
|||
BGMAppVolumesController* appVolumes;
|
||||
BGMOutputDeviceMenuSection* outputDeviceMenuSection;
|
||||
BGMPreferencesMenu* prefsMenu;
|
||||
BGMDebugLoggingMenuItem* debugLoggingMenuItem;
|
||||
BGMXPCListener* xpcListener;
|
||||
BGMPreferredOutputDevices* preferredOutputDevices;
|
||||
}
|
||||
|
@ -251,6 +253,11 @@ static NSString* const kOptShowDockIcon = @"--show-dock-icon";
|
|||
aboutPanel:self.aboutPanel
|
||||
aboutPanelLicenseView:self.aboutPanelLicenseView];
|
||||
|
||||
// Enable/disable debug logging. Hidden unless you option-click the status bar icon.
|
||||
debugLoggingMenuItem =
|
||||
[[BGMDebugLoggingMenuItem alloc] initWithMenuItem:self.debugLoggingMenuItemUnwrapped];
|
||||
[statusBarItem setDebugLoggingMenuItem:debugLoggingMenuItem];
|
||||
|
||||
// Handle events about the main menu. (See the NSMenuDelegate methods below.)
|
||||
self.bgmMenu.delegate = self;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// BGMAppVolumes.m
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2016-2018 Kyle Neideck
|
||||
// Copyright © 2016-2020 Kyle Neideck
|
||||
// Copyright © 2017 Andrew Tonner
|
||||
//
|
||||
|
||||
|
@ -196,14 +196,15 @@ static NSString* const kMoreAppsMenuTitle = @"More Apps";
|
|||
|
||||
BGMAssert(button, "!button");
|
||||
BGMAssert(menuItem, "!menuItem");
|
||||
|
||||
|
||||
CGFloat width = menuItem.view.frame.size.width;
|
||||
CGFloat height = menuItem.view.frame.size.height;
|
||||
|
||||
#if DEBUG
|
||||
const char* appName = [((NSRunningApplication*)menuItem.representedObject).localizedName UTF8String];
|
||||
CGFloat height = menuItem.view.frame.size.height;
|
||||
#endif
|
||||
|
||||
const char* appName =
|
||||
[((NSRunningApplication*)menuItem.representedObject).localizedName UTF8String];
|
||||
|
||||
// Using this function (instead of just ==) shouldn't be necessary, but just in case.
|
||||
BOOL(^nearEnough)(CGFloat x, CGFloat y) = ^BOOL(CGFloat x, CGFloat y) {
|
||||
return fabs(x - y) < 0.01; // We don't need much precision.
|
||||
|
|
|
@ -48,7 +48,7 @@ BGMAudioDevice::BGMAudioDevice(const CAHALAudioDevice& inDevice)
|
|||
:
|
||||
BGMAudioDevice(inDevice.GetObjectID())
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
BGMAudioDevice::~BGMAudioDevice()
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// BGMAudioDevice.h
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
// Copyright © 2017, 2020 Kyle Neideck
|
||||
//
|
||||
// A HAL audio device. Note that this class's only state is the AudioObjectID of the device.
|
||||
//
|
||||
|
@ -59,7 +59,8 @@ public:
|
|||
operator AudioObjectID() const { return GetObjectID(); }
|
||||
|
||||
/*!
|
||||
@return True if this device is BGMDevice. (Specifically, the main instance of BGMDevice.)
|
||||
@return True if this device is BGMDevice. (Specifically, the main instance of BGMDevice, not
|
||||
the instance used for UI sounds.)
|
||||
@throws CAException If the HAL returns an error when queried.
|
||||
*/
|
||||
bool IsBGMDevice() const { return IsBGMDevice(false); };
|
||||
|
|
48
BGMApp/BGMApp/BGMDebugLoggingMenuItem.h
Normal file
48
BGMApp/BGMApp/BGMDebugLoggingMenuItem.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// BGMDebugLoggingMenuItem.h
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
// A menu item in the main menu that enables/disables debug logging. Only visible if you hold the
|
||||
// option down when you click the status bar icon to reveal the main menu.
|
||||
//
|
||||
// TODO: It would be better to have this menu item in the Preferences menu (maybe in an Advanced
|
||||
// section) and always visible, but first we'd need to add something that tells the user how
|
||||
// to view the log messages. Or better yet, something that automatically opens them.
|
||||
//
|
||||
|
||||
// System Includes
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
@interface BGMDebugLoggingMenuItem : NSObject
|
||||
|
||||
- (instancetype) initWithMenuItem:(NSMenuItem*)menuItem;
|
||||
|
||||
// True if the main menu is showing hidden items/options because the user held the option key when
|
||||
// they clicked the icon. This class makes the debug logging menu item visible if this property has
|
||||
// been set true or if debug logging is enabled.
|
||||
@property (nonatomic) BOOL menuShowingExtraOptions;
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
73
BGMApp/BGMApp/BGMDebugLoggingMenuItem.m
Normal file
73
BGMApp/BGMApp/BGMDebugLoggingMenuItem.m
Normal file
|
@ -0,0 +1,73 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// BGMDebugLoggingMenuItem.m
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#import "BGMDebugLoggingMenuItem.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#import "BGMDebugLogging.h"
|
||||
#import "CADebugMacros.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
@implementation BGMDebugLoggingMenuItem {
|
||||
NSMenuItem* _menuItem;
|
||||
BOOL _menuShowingExtraOptions;
|
||||
}
|
||||
|
||||
- (instancetype) initWithMenuItem:(NSMenuItem*)menuItem {
|
||||
if ((self = [super init])) {
|
||||
_menuItem = menuItem;
|
||||
_menuItem.state =
|
||||
BGMDebugLoggingIsEnabled() ? NSControlStateValueOn : NSControlStateValueOff;
|
||||
|
||||
[self setMenuShowingExtraOptions:NO];
|
||||
|
||||
// Enable/disable debug logging when the menu item is clicked.
|
||||
menuItem.target = self;
|
||||
menuItem.action = @selector(toggleDebugLogging);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) setMenuShowingExtraOptions:(BOOL)showingExtra {
|
||||
_menuShowingExtraOptions = showingExtra;
|
||||
_menuItem.hidden = !BGMDebugLoggingIsEnabled() && !showingExtra;
|
||||
|
||||
DebugMsg("BGMDebugLoggingMenuItem::menuShowingExtraOptions: %s the menu item",
|
||||
_menuItem.hidden ? "Hiding" : "Showing");
|
||||
}
|
||||
|
||||
- (void) toggleDebugLogging {
|
||||
BGMSetDebugLoggingEnabled(!BGMDebugLoggingIsEnabled());
|
||||
_menuItem.state = BGMDebugLoggingIsEnabled() ? NSControlStateValueOn : NSControlStateValueOff;
|
||||
|
||||
DebugMsg("BGMDebugLoggingMenuItem::toggleDebugLogging: Debug logging %s",
|
||||
BGMDebugLoggingIsEnabled() ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
// BGMPlayThrough.cpp
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
// Copyright © 2016, 2017, 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
|
@ -569,20 +569,21 @@ OSStatus BGMPlayThrough::WaitForOutputDeviceToStart() noexcept
|
|||
while((theError != KERN_SUCCESS) && // Signalled from the IOProc.
|
||||
(state == IOState::Starting) && // IO state changed.
|
||||
(waitedNsec < kStartIOTimeoutNsec)); // Timed out.
|
||||
|
||||
#if DEBUG
|
||||
UInt64 startedBy = mach_absolute_time();
|
||||
|
||||
struct mach_timebase_info baseInfo = { 0, 0 };
|
||||
mach_timebase_info(&baseInfo);
|
||||
UInt64 base = baseInfo.numer / baseInfo.denom;
|
||||
|
||||
DebugMsg("BGMPlayThrough::WaitForOutputDeviceToStart: Started %f ms after notification, %f ms "
|
||||
"after entering WaitForOutputDeviceToStart.",
|
||||
static_cast<Float64>(startedBy - mToldOutputDeviceToStartAt) * base / NSEC_PER_MSEC,
|
||||
static_cast<Float64>(startedBy - startedAt) * base / NSEC_PER_MSEC);
|
||||
#endif
|
||||
|
||||
|
||||
if(BGMDebugLoggingIsEnabled())
|
||||
{
|
||||
UInt64 startedBy = mach_absolute_time();
|
||||
|
||||
struct mach_timebase_info baseInfo = { 0, 0 };
|
||||
mach_timebase_info(&baseInfo);
|
||||
UInt64 base = baseInfo.numer / baseInfo.denom;
|
||||
|
||||
DebugMsg("BGMPlayThrough::WaitForOutputDeviceToStart: Started %f ms after notification, %f "
|
||||
"ms after entering WaitForOutputDeviceToStart.",
|
||||
static_cast<Float64>(startedBy - mToldOutputDeviceToStartAt) * base / NSEC_PER_MSEC,
|
||||
static_cast<Float64>(startedBy - startedAt) * base / NSEC_PER_MSEC);
|
||||
}
|
||||
|
||||
// Figure out which error code to return.
|
||||
switch (theError)
|
||||
{
|
||||
|
@ -604,7 +605,7 @@ OSStatus BGMPlayThrough::WaitForOutputDeviceToStart() noexcept
|
|||
|
||||
// Release any threads waiting for the output device to start. This function doesn't take mStateMutex
|
||||
// because it gets called on the IO thread, which is realtime priority.
|
||||
void BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart() const
|
||||
void BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart()
|
||||
{
|
||||
if(mActive)
|
||||
{
|
||||
|
@ -612,13 +613,10 @@ void BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart() const
|
|||
|
||||
if(semaphore != SEMAPHORE_NULL)
|
||||
{
|
||||
DebugMsg("BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart: Releasing waiting threads");
|
||||
mRTLogger.LogReleasingWaitingThreads();
|
||||
|
||||
kern_return_t theError = semaphore_signal_all(semaphore);
|
||||
|
||||
// TODO: Tell another thread to log this error, since we might be on a realtime thread.
|
||||
BGM_Utils::LogIfMachError("BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart",
|
||||
"semaphore_signal_all",
|
||||
theError);
|
||||
mRTLogger.LogIfMachError_ReleaseWaitingThreadsSignal(theError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -870,9 +868,8 @@ void BGMPlayThrough::HandleBGMDeviceIsRunning(BGMPlayThrough* refCon)
|
|||
|
||||
if(isRunningSomewhereOtherThanBGMApp)
|
||||
{
|
||||
#if DEBUG
|
||||
refCon->mToldOutputDeviceToStartAt = mach_absolute_time();
|
||||
#endif
|
||||
|
||||
// TODO: Handle expected exceptions (mostly CAExceptions from PublicUtility classes) in Start.
|
||||
// For any that can't be handled sensibly in Start, catch them here and retry a few
|
||||
// times (with a very short delay) before handling them by showing an unobtrusive error
|
||||
|
@ -932,6 +929,7 @@ OSStatus BGMPlayThrough::InputDeviceIOProc(AudioObjectID inDevice,
|
|||
|
||||
IOState state;
|
||||
UpdateIOProcState("InputDeviceIOProc",
|
||||
refCon->mRTLogger,
|
||||
refCon->mInputDeviceIOProcState,
|
||||
refCon->mInputDeviceIOProcID,
|
||||
refCon->mInputDevice,
|
||||
|
@ -956,9 +954,8 @@ OSStatus BGMPlayThrough::InputDeviceIOProc(AudioObjectID inDevice,
|
|||
refCon->mBuffer.Store(inInputData,
|
||||
framesToStore,
|
||||
static_cast<CARingBuffer::SampleTime>(inInputTime->mSampleTime));
|
||||
|
||||
HandleRingBufferError(err, "InputDeviceIOProc", "mBuffer.Store");
|
||||
|
||||
refCon->mRTLogger.LogIfRingBufferError_Store(err);
|
||||
|
||||
CAMemoryBarrier();
|
||||
refCon->mLastInputSampleTime = inInputTime->mSampleTime;
|
||||
|
||||
|
@ -981,6 +978,7 @@ OSStatus BGMPlayThrough::OutputDeviceIOProc(AudioObjectID inDevice,
|
|||
|
||||
IOState state;
|
||||
const bool didChangeState = UpdateIOProcState("OutputDeviceIOProc",
|
||||
refCon->mRTLogger,
|
||||
refCon->mOutputDeviceIOProcState,
|
||||
refCon->mOutputDeviceIOProcID,
|
||||
refCon->mOutputDevice,
|
||||
|
@ -1020,13 +1018,8 @@ OSStatus BGMPlayThrough::OutputDeviceIOProc(AudioObjectID inDevice,
|
|||
refCon->mInToOutSampleOffset = inOutputTime->mSampleTime - refCon->mLastInputSampleTime;
|
||||
|
||||
// Log if we dropped frames
|
||||
if(refCon->mFirstInputSampleTime != refCon->mLastInputSampleTime)
|
||||
{
|
||||
DebugMsg("BGMPlayThrough::OutputDeviceIOProc: Dropped %f frames before output started. %s%f %s%f",
|
||||
(refCon->mLastInputSampleTime - refCon->mFirstInputSampleTime),
|
||||
"mFirstInputSampleTime=", refCon->mFirstInputSampleTime,
|
||||
"mLastInputSampleTime=", refCon->mLastInputSampleTime);
|
||||
}
|
||||
refCon->mRTLogger.LogIfDroppedFrames(refCon->mFirstInputSampleTime,
|
||||
refCon->mLastInputSampleTime);
|
||||
}
|
||||
|
||||
CARingBuffer::SampleTime readHeadSampleTime =
|
||||
|
@ -1054,11 +1047,10 @@ OSStatus BGMPlayThrough::OutputDeviceIOProc(AudioObjectID inDevice,
|
|||
}
|
||||
if(lastInputSampleTime < readHeadSampleTime || outOfBounds)
|
||||
{
|
||||
DebugMsg("BGMPlayThrough::OutputDeviceIOProc: No input samples ready at output sample time. %s%lld %s%lld %s%f",
|
||||
"lastInputSampleTime=", lastInputSampleTime,
|
||||
"readHeadSampleTime=", readHeadSampleTime,
|
||||
"mInToOutSampleOffset=", refCon->mInToOutSampleOffset);
|
||||
|
||||
refCon->mRTLogger.LogNoSamplesReady(lastInputSampleTime,
|
||||
readHeadSampleTime,
|
||||
refCon->mInToOutSampleOffset);
|
||||
|
||||
// Recalculate the in-to-out offset and read head
|
||||
refCon->mInToOutSampleOffset = inOutputTime->mSampleTime - lastInputSampleTime;
|
||||
readHeadSampleTime = static_cast<CARingBuffer::SampleTime>(inOutputTime->mSampleTime - refCon->mInToOutSampleOffset);
|
||||
|
@ -1066,16 +1058,20 @@ OSStatus BGMPlayThrough::OutputDeviceIOProc(AudioObjectID inDevice,
|
|||
|
||||
// Copy the frames from the ring buffer
|
||||
err = refCon->mBuffer.Fetch(outOutputData, framesToOutput, readHeadSampleTime);
|
||||
|
||||
HandleRingBufferError(err, "OutputDeviceIOProc", "mBuffer.Fetch");
|
||||
|
||||
// TODO: Not sure what else we should do to handle these errors, if anything. There's code in
|
||||
// Apple's CAPlayThrough.cpp sample code that handles them. (Look for
|
||||
// "kCARingBufferError_OK" around line 707.) Should be easy enough to use, but it's more
|
||||
// complicated that just directly copying it.
|
||||
refCon->mRTLogger.LogIfRingBufferError_Fetch(err);
|
||||
|
||||
refCon->mLastOutputSampleTime = inOutputTime->mSampleTime;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
// static
|
||||
bool BGMPlayThrough::UpdateIOProcState(const char* __nullable callerName,
|
||||
bool BGMPlayThrough::UpdateIOProcState(const char* inCallerName,
|
||||
BGMPlayThroughRTLogger& inRTLogger,
|
||||
std::atomic<IOState>& inState,
|
||||
AudioDeviceIOProcID __nullable inIOProcID,
|
||||
BGMAudioDevice& inDevice,
|
||||
|
@ -1088,6 +1084,9 @@ bool BGMPlayThrough::UpdateIOProcState(const char* __nullable callerName,
|
|||
//
|
||||
// compare_exchange_strong will return true iff it changed inState from Starting to Running.
|
||||
// Otherwise it will set prevState to the current value of inState.
|
||||
//
|
||||
// TODO: We probably don't actually need memory_order_seq_cst (the default). Would it be worth
|
||||
// changing? Might be worth checking for the other atomics/barriers in this class, too.
|
||||
IOState prevState = IOState::Starting;
|
||||
bool didChangeState = inState.compare_exchange_strong(prevState, IOState::Running);
|
||||
|
||||
|
@ -1105,21 +1104,28 @@ bool BGMPlayThrough::UpdateIOProcState(const char* __nullable callerName,
|
|||
{
|
||||
// The IOProc isn't Starting or Running, so it must be Stopping. That is, it's been
|
||||
// told to stop itself.
|
||||
|
||||
BGMAssert(outNewState == IOState::Stopping,
|
||||
"BGMPlayThrough::UpdateIOProcState: Unexpected state: %d",
|
||||
outNewState);
|
||||
|
||||
bool stoppedSuccessfully = false;
|
||||
BGMLogAndSwallowExceptionsMsg("BGMPlayThrough::UpdateIOProcState", callerName, [&]() {
|
||||
// TODO: If this throws, tell another thread to log the exception rather than
|
||||
// logging it from a real-time thread.
|
||||
|
||||
try
|
||||
{
|
||||
inDevice.StopIOProc(inIOProcID);
|
||||
|
||||
// StopIOProc didn't throw, so the IOProc won't be called again until the next
|
||||
// time playthrough is started.
|
||||
stoppedSuccessfully = true;
|
||||
});
|
||||
}
|
||||
catch(CAException e)
|
||||
{
|
||||
inRTLogger.LogExceptionStoppingIOProc(inCallerName, e.GetError());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
inRTLogger.LogExceptionStoppingIOProc(inCallerName);
|
||||
}
|
||||
|
||||
if(stoppedSuccessfully)
|
||||
{
|
||||
|
@ -1132,7 +1138,7 @@ bool BGMPlayThrough::UpdateIOProcState(const char* __nullable callerName,
|
|||
//
|
||||
// Stop won't return until the IOProc has changed inState to Stopped, unless it
|
||||
// times out, so Stop should still be waiting. And since Start and Stop are
|
||||
// mutually exclusive, so this should be safe.
|
||||
// mutually exclusive, this should be safe.
|
||||
//
|
||||
// But if Stop has timed out and inState has changed, we leave it in its new
|
||||
// state (unless there's some ABA problem thing happening), which I suspect is
|
||||
|
@ -1145,8 +1151,8 @@ bool BGMPlayThrough::UpdateIOProcState(const char* __nullable callerName,
|
|||
}
|
||||
else
|
||||
{
|
||||
DebugMsg("BGMPlayThrough::UpdateIOProcState: inState changed since last read "
|
||||
"outNewState = %d", outNewState);
|
||||
inRTLogger.LogUnexpectedIOStateAfterStopping(inCallerName,
|
||||
static_cast<int>(outNewState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1155,30 +1161,3 @@ bool BGMPlayThrough::UpdateIOProcState(const char* __nullable callerName,
|
|||
return didChangeState;
|
||||
}
|
||||
|
||||
// static
|
||||
void BGMPlayThrough::HandleRingBufferError(CARingBufferError inErr,
|
||||
const char* inMethodName,
|
||||
const char* inCallReturningErr)
|
||||
{
|
||||
#if DEBUG
|
||||
if(inErr != kCARingBufferError_OK)
|
||||
{
|
||||
const char* errStr = (inErr == kCARingBufferError_TooMuch ? "kCARingBufferError_TooMuch" :
|
||||
(inErr == kCARingBufferError_CPUOverload ? "kCARingBufferError_CPUOverload" : "unknown error"));
|
||||
|
||||
DebugMsg("BGMPlayThrough::%s: %s returned %s (%d)", inMethodName, inCallReturningErr, errStr, inErr);
|
||||
|
||||
// kCARingBufferError_CPUOverload wouldn't mean we have a bug, but I think kCARingBufferError_TooMuch would
|
||||
if(inErr != kCARingBufferError_CPUOverload)
|
||||
{
|
||||
Throw(CAException(inErr));
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Not sure what we should do to handle these errors in release builds, if anything.
|
||||
// TODO: There's code in Apple's CAPlayThrough.cpp sample code that handles them. (Look for "kCARingBufferError_OK"
|
||||
// around line 707.) Should be easy enough to use, but it's more complicated that just directly copying it.
|
||||
#pragma unused (inErr, inMethodName, inCallReturningErr)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// BGMPlayThrough.h
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
// Copyright © 2016, 2017, 2020 Kyle Neideck
|
||||
//
|
||||
// Reads audio from an input device and immediately writes it to an output device. We currently use this class with the input
|
||||
// device always set to BGMDevice and the output device set to the one selected in the preferences menu.
|
||||
|
@ -41,10 +41,11 @@
|
|||
|
||||
// Local Includes
|
||||
#include "BGMAudioDevice.h"
|
||||
#include "BGMPlayThroughRTLogger.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CARingBuffer.h"
|
||||
#include "CAMutex.h"
|
||||
#include "CARingBuffer.h"
|
||||
|
||||
// STL Includes
|
||||
#include <atomic>
|
||||
|
@ -115,7 +116,8 @@ public:
|
|||
OSStatus WaitForOutputDeviceToStart() noexcept;
|
||||
|
||||
private:
|
||||
void ReleaseThreadsWaitingForOutputToStart() const;
|
||||
/*! Real-time safe. */
|
||||
void ReleaseThreadsWaitingForOutputToStart();
|
||||
|
||||
public:
|
||||
OSStatus Stop();
|
||||
|
@ -156,16 +158,13 @@ private:
|
|||
|
||||
// The IOProcs call this to update their IOState member. Also stops the IOProc if its state has been set to Stopping.
|
||||
// Returns true if it changes the state.
|
||||
static bool UpdateIOProcState(const char* __nullable callerName,
|
||||
static bool UpdateIOProcState(const char* inCallerName,
|
||||
BGMPlayThroughRTLogger& inRTLogger,
|
||||
std::atomic<IOState>& inState,
|
||||
AudioDeviceIOProcID __nullable inIOProcID,
|
||||
BGMAudioDevice& inDevice,
|
||||
IOState& outNewState);
|
||||
|
||||
static void HandleRingBufferError(CARingBufferError err,
|
||||
const char* methodName,
|
||||
const char* callReturningErr);
|
||||
|
||||
private:
|
||||
CARingBuffer mBuffer;
|
||||
|
||||
|
@ -200,7 +199,9 @@ private:
|
|||
|
||||
// Subtract this from the output time to get the input time.
|
||||
Float64 mInToOutSampleOffset { 0.0 };
|
||||
|
||||
|
||||
BGMPlayThroughRTLogger mRTLogger;
|
||||
|
||||
};
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
|
496
BGMApp/BGMApp/BGMPlayThroughRTLogger.cpp
Normal file
496
BGMApp/BGMApp/BGMPlayThroughRTLogger.cpp
Normal file
|
@ -0,0 +1,496 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// BGMPlayThroughRTLogger.cpp
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "BGMPlayThroughRTLogger.h"
|
||||
|
||||
// Local Includes
|
||||
#include "BGM_Utils.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
|
||||
// STL Includes
|
||||
#include <atomic>
|
||||
|
||||
// System Includes
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/task.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
// Track the number of messages logged when built for the unit tests.
|
||||
#if BGM_UnitTest
|
||||
#define LogSync_Debug(inFormat, ...) do { \
|
||||
mNumDebugMessagesLogged++; \
|
||||
DebugMsg(inFormat, ## __VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define LogSync_Debug(inFormat, ...) DebugMsg(inFormat, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
BGMPlayThroughRTLogger::BGMPlayThroughRTLogger()
|
||||
{
|
||||
// Create the semaphore we use to wake up the logging thread when it has messages to log.
|
||||
mWakeUpLoggingThreadSemaphore = CreateSemaphore();
|
||||
|
||||
// Create the logging thread last because it starts immediately and expects the other member
|
||||
// variables to be initialised.
|
||||
mLoggingThread = std::thread(&BGMPlayThroughRTLogger::LoggingThreadEntry, this);
|
||||
}
|
||||
|
||||
// static
|
||||
semaphore_t BGMPlayThroughRTLogger::CreateSemaphore()
|
||||
{
|
||||
// TODO: Make a BGMMachSemaphore class to reduce some of this repetitive semaphore code.
|
||||
|
||||
// Create the semaphore.
|
||||
semaphore_t semaphore;
|
||||
kern_return_t error =
|
||||
semaphore_create(mach_task_self(), &semaphore, SYNC_POLICY_FIFO, 0);
|
||||
|
||||
// Check the error code.
|
||||
BGM_Utils::ThrowIfMachError("BGMPlayThroughRTLogger::CreateSemaphore",
|
||||
"semaphore_create",
|
||||
error);
|
||||
ThrowIf(semaphore == SEMAPHORE_NULL,
|
||||
CAException(kAudioHardwareUnspecifiedError),
|
||||
"BGMPlayThroughRTLogger::CreateSemaphore: Failed to create semaphore");
|
||||
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
BGMPlayThroughRTLogger::~BGMPlayThroughRTLogger()
|
||||
{
|
||||
// Stop the logging thread.
|
||||
mLoggingThreadShouldExit = true;
|
||||
kern_return_t error = semaphore_signal(mWakeUpLoggingThreadSemaphore);
|
||||
|
||||
BGM_Utils::LogIfMachError("BGMPlayThroughRTLogger::~BGMPlayThroughRTLogger",
|
||||
"semaphore_signal",
|
||||
error);
|
||||
|
||||
if(error == KERN_SUCCESS)
|
||||
{
|
||||
// Wait for it to stop.
|
||||
mLoggingThread.join();
|
||||
|
||||
// Destroy the semaphore.
|
||||
error = semaphore_destroy(mach_task_self(), mWakeUpLoggingThreadSemaphore);
|
||||
BGM_Utils::LogIfMachError("BGMPlayThroughRTLogger::~BGMPlayThroughRTLogger",
|
||||
"semaphore_destroy",
|
||||
error);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we couldn't tell it to wake up, it's not safe to wait for it to stop or to destroy the
|
||||
// semaphore. We have to detach it so its destructor doesn't cause a crash.
|
||||
mLoggingThread.detach();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Log Messages
|
||||
|
||||
void BGMPlayThroughRTLogger::LogReleasingWaitingThreads()
|
||||
{
|
||||
if(!BGMDebugLoggingIsEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mLogReleasingWaitingThreadsMsg.is_lock_free())
|
||||
{
|
||||
// Modifying mLogReleasingWaitingThreadsMsg might cause the thread to lock a mutex that
|
||||
// isn't safe to lock on a realtime thread, so just give up.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the flag that tells the logging thread to log the message.
|
||||
mLogReleasingWaitingThreadsMsg = true;
|
||||
|
||||
// Wake the logging thread so it can log the message.
|
||||
WakeLoggingThread();
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogIfMachError_ReleaseWaitingThreadsSignal(mach_error_t inError)
|
||||
{
|
||||
if(inError == KERN_SUCCESS)
|
||||
{
|
||||
// No error.
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mReleaseWaitingThreadsSignalError.is_lock_free())
|
||||
{
|
||||
// Modifying mReleaseWaitingThreadsSignalError might cause the thread to lock a mutex that
|
||||
// isn't safe to lock on a realtime thread, so just give up.
|
||||
return;
|
||||
}
|
||||
|
||||
mReleaseWaitingThreadsSignalError = inError;
|
||||
WakeLoggingThread();
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogIfDroppedFrames(Float64 inFirstInputSampleTime,
|
||||
Float64 inLastInputSampleTime)
|
||||
{
|
||||
if(inFirstInputSampleTime == inLastInputSampleTime || !BGMDebugLoggingIsEnabled())
|
||||
{
|
||||
// Either we didn't drop any initial frames or we don't need to log a message about it.
|
||||
return;
|
||||
}
|
||||
|
||||
LogAsync(mDroppedFrames, [&]()
|
||||
{
|
||||
// Store the data to include in the log message.
|
||||
mDroppedFrames.firstInputSampleTime = inFirstInputSampleTime;
|
||||
mDroppedFrames.lastInputSampleTime = inLastInputSampleTime;
|
||||
});
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogNoSamplesReady(CARingBuffer::SampleTime inLastInputSampleTime,
|
||||
CARingBuffer::SampleTime inReadHeadSampleTime,
|
||||
Float64 inInToOutSampleOffset)
|
||||
{
|
||||
if(!BGMDebugLoggingIsEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LogAsync(mNoSamplesReady, [&]()
|
||||
{
|
||||
// Store the data to include in the log message.
|
||||
mNoSamplesReady.lastInputSampleTime = inLastInputSampleTime;
|
||||
mNoSamplesReady.readHeadSampleTime = inReadHeadSampleTime;
|
||||
mNoSamplesReady.inToOutSampleOffset = inInToOutSampleOffset;
|
||||
});
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogExceptionStoppingIOProc(const char* inCallerName,
|
||||
OSStatus inError,
|
||||
bool inErrorKnown)
|
||||
{
|
||||
LogAsync(mExceptionStoppingIOProc, [&]()
|
||||
{
|
||||
// Store the data to include in the log message.
|
||||
mExceptionStoppingIOProc.callerName = inCallerName;
|
||||
mExceptionStoppingIOProc.error = inError;
|
||||
mExceptionStoppingIOProc.errorKnown = inErrorKnown;
|
||||
});
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogUnexpectedIOStateAfterStopping(const char* inCallerName,
|
||||
int inIOState)
|
||||
{
|
||||
LogAsync(mUnexpectedIOStateAfterStopping, [&]()
|
||||
{
|
||||
// Store the data to include in the log message.
|
||||
mUnexpectedIOStateAfterStopping.callerName = inCallerName;
|
||||
mUnexpectedIOStateAfterStopping.ioState = inIOState;
|
||||
});
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogIfRingBufferError(CARingBufferError inError,
|
||||
std::atomic<CARingBufferError>& outError)
|
||||
{
|
||||
if(inError == kCARingBufferError_OK)
|
||||
{
|
||||
// No error.
|
||||
return;
|
||||
}
|
||||
|
||||
if(!outError.is_lock_free())
|
||||
{
|
||||
// Modifying outError might cause the thread to lock a mutex that isn't safe to lock on
|
||||
// a realtime thread, so just give up.
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the error.
|
||||
outError = inError;
|
||||
|
||||
// Wake the logging thread so it can log the error.
|
||||
WakeLoggingThread();
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void BGMPlayThroughRTLogger::LogAsync(T& inMessageData, F&& inStoreMessageData)
|
||||
{
|
||||
if(!inMessageData.shouldLogMessage.is_lock_free())
|
||||
{
|
||||
// Modifying shouldLogMessage might cause the thread to lock a mutex that isn't safe to
|
||||
// lock on a realtime thread, so just give up.
|
||||
return;
|
||||
}
|
||||
|
||||
if(inMessageData.shouldLogMessage)
|
||||
{
|
||||
// The logging thread could be reading inMessageData.
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the data to include in the log message.
|
||||
//
|
||||
// std::forward lets the compiler treat inStoreMessageData as an rvalue if the caller gave it as
|
||||
// an rvalue. No idea if that actually does anything.
|
||||
std::forward<F>(inStoreMessageData)();
|
||||
|
||||
// shouldLogMessage is a std::atomic, so this store also makes sure that the non-atomic stores
|
||||
// in inStoreMessageData will be visible to the logger thread (since the default memory order is
|
||||
// memory_order_seq_cst).
|
||||
inMessageData.shouldLogMessage = true;
|
||||
|
||||
WakeLoggingThread();
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogSync_Warning(const char* inFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, inFormat);
|
||||
|
||||
#if BGM_UnitTest
|
||||
mNumWarningMessagesLogged++;
|
||||
#endif
|
||||
|
||||
LogWarning(inFormat, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogSync_Error(const char* inFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, inFormat);
|
||||
|
||||
#if BGM_UnitTest
|
||||
mNumErrorMessagesLogged++;
|
||||
|
||||
if(!mContinueOnErrorLogged)
|
||||
{
|
||||
LogError(inFormat, args);
|
||||
}
|
||||
#else
|
||||
LogError(inFormat, args);
|
||||
#endif
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#pragma mark Logging Thread
|
||||
|
||||
void BGMPlayThroughRTLogger::WakeLoggingThread()
|
||||
{
|
||||
kern_return_t error = semaphore_signal(mWakeUpLoggingThreadSemaphore);
|
||||
|
||||
BGMAssert(error == KERN_SUCCESS, "semaphore_signal (%d)", error);
|
||||
|
||||
// We can't do anything useful with the error in release builds. At least, not easily.
|
||||
(void)error;
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogMessages()
|
||||
{
|
||||
// Log the messages/errors from the realtime threads (if any).
|
||||
LogSync_ReleasingWaitingThreads();
|
||||
LogSync_ReleaseWaitingThreadsSignalError();
|
||||
LogSync_DroppedFrames();
|
||||
LogSync_NoSamplesReady();
|
||||
LogSync_ExceptionStoppingIOProc();
|
||||
LogSync_UnexpectedIOStateAfterStopping();
|
||||
LogSync_RingBufferError(mRingBufferStoreError, "InputDeviceIOProc");
|
||||
LogSync_RingBufferError(mRingBufferFetchError, "OutputDeviceIOProc");
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogSync_ReleasingWaitingThreads()
|
||||
{
|
||||
if(mLogReleasingWaitingThreadsMsg)
|
||||
{
|
||||
LogSync_Debug("BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart: "
|
||||
"Releasing waiting threads");
|
||||
// Reset it.
|
||||
mLogReleasingWaitingThreadsMsg = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogSync_ReleaseWaitingThreadsSignalError()
|
||||
{
|
||||
if(mReleaseWaitingThreadsSignalError != KERN_SUCCESS)
|
||||
{
|
||||
BGM_Utils::LogIfMachError("BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart",
|
||||
"semaphore_signal_all",
|
||||
mReleaseWaitingThreadsSignalError);
|
||||
// Reset it.
|
||||
mReleaseWaitingThreadsSignalError = KERN_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogSync_DroppedFrames()
|
||||
{
|
||||
if(mDroppedFrames.shouldLogMessage)
|
||||
{
|
||||
LogSync_Debug("BGMPlayThrough::OutputDeviceIOProc: "
|
||||
"Dropped %f frames before output started. %s%f %s%f",
|
||||
(mDroppedFrames.lastInputSampleTime - mDroppedFrames.firstInputSampleTime),
|
||||
"mFirstInputSampleTime=",
|
||||
mDroppedFrames.firstInputSampleTime,
|
||||
"mLastInputSampleTime=",
|
||||
mDroppedFrames.lastInputSampleTime);
|
||||
mDroppedFrames.shouldLogMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogSync_NoSamplesReady()
|
||||
{
|
||||
if(mNoSamplesReady.shouldLogMessage)
|
||||
{
|
||||
LogSync_Debug("BGMPlayThrough::OutputDeviceIOProc: "
|
||||
"No input samples ready at output sample time. %s%lld %s%lld %s%f",
|
||||
"lastInputSampleTime=", mNoSamplesReady.lastInputSampleTime,
|
||||
"readHeadSampleTime=", mNoSamplesReady.readHeadSampleTime,
|
||||
"mInToOutSampleOffset=", mNoSamplesReady.inToOutSampleOffset);
|
||||
mNoSamplesReady.shouldLogMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogSync_ExceptionStoppingIOProc()
|
||||
{
|
||||
if(mExceptionStoppingIOProc.shouldLogMessage)
|
||||
{
|
||||
const char error4CC[5] = CA4CCToCString(mExceptionStoppingIOProc.error);
|
||||
LogSync_Error("BGMPlayThrough::UpdateIOProcState: "
|
||||
"Exception while stopping IOProc %s: %s (%d)",
|
||||
mExceptionStoppingIOProc.callerName,
|
||||
mExceptionStoppingIOProc.errorKnown ? error4CC : "unknown",
|
||||
mExceptionStoppingIOProc.error);
|
||||
mExceptionStoppingIOProc.shouldLogMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogSync_UnexpectedIOStateAfterStopping()
|
||||
{
|
||||
if(mUnexpectedIOStateAfterStopping.shouldLogMessage)
|
||||
{
|
||||
LogSync_Warning("BGMPlayThrough::UpdateIOProcState: "
|
||||
"%s IO state changed since last read. state = %d",
|
||||
mUnexpectedIOStateAfterStopping.callerName,
|
||||
mUnexpectedIOStateAfterStopping.ioState);
|
||||
mUnexpectedIOStateAfterStopping.shouldLogMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BGMPlayThroughRTLogger::LogSync_RingBufferError(
|
||||
std::atomic<CARingBufferError>& ioRingBufferError,
|
||||
const char* inMethodName)
|
||||
{
|
||||
CARingBufferError error = ioRingBufferError;
|
||||
|
||||
switch(error)
|
||||
{
|
||||
case kCARingBufferError_OK:
|
||||
// No error.
|
||||
return;
|
||||
case kCARingBufferError_CPUOverload:
|
||||
// kCARingBufferError_CPUOverload might not be our fault, so just log a warning.
|
||||
LogSync_Warning("BGMPlayThrough::%s: Ring buffer error: "
|
||||
"kCARingBufferError_CPUOverload (%d)",
|
||||
inMethodName,
|
||||
error);
|
||||
break;
|
||||
default:
|
||||
// Other types of CARingBuffer errors should never occur. This will crash debug builds.
|
||||
LogSync_Error("BGMPlayThrough::%s: Ring buffer error: %s (%d)",
|
||||
inMethodName,
|
||||
(error == kCARingBufferError_TooMuch ?
|
||||
"kCARingBufferError_TooMuch" :
|
||||
"unknown error"),
|
||||
error);
|
||||
break;
|
||||
};
|
||||
|
||||
// Reset it.
|
||||
ioRingBufferError = kCARingBufferError_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void* __nullable BGMPlayThroughRTLogger::LoggingThreadEntry(BGMPlayThroughRTLogger* inRefCon)
|
||||
{
|
||||
DebugMsg("BGMPlayThroughRTLogger::IOProcLoggingThreadEntry: "
|
||||
"Starting the IOProc logging thread");
|
||||
|
||||
while(!inRefCon->mLoggingThreadShouldExit)
|
||||
{
|
||||
// Log the messages, if there are any to log.
|
||||
inRefCon->LogMessages();
|
||||
|
||||
// Wait until woken up.
|
||||
kern_return_t error = semaphore_wait(inRefCon->mWakeUpLoggingThreadSemaphore);
|
||||
BGM_Utils::LogIfMachError("BGMPlayThroughRTLogger::IOProcLoggingThreadEntry",
|
||||
"semaphore_wait",
|
||||
error);
|
||||
}
|
||||
|
||||
DebugMsg("BGMPlayThroughRTLogger::IOProcLoggingThreadEntry: IOProc logging thread exiting");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if BGM_UnitTest
|
||||
|
||||
#pragma mark Test Helpers
|
||||
|
||||
bool BGMPlayThroughRTLogger::WaitUntilLoggerThreadIdle()
|
||||
{
|
||||
int msWaited = 0;
|
||||
|
||||
while(mLogReleasingWaitingThreadsMsg ||
|
||||
mReleaseWaitingThreadsSignalError != KERN_SUCCESS ||
|
||||
mDroppedFrames.shouldLogMessage ||
|
||||
mNoSamplesReady.shouldLogMessage ||
|
||||
mUnexpectedIOStateAfterStopping.shouldLogMessage ||
|
||||
mExceptionStoppingIOProc.shouldLogMessage ||
|
||||
mRingBufferStoreError != kCARingBufferError_OK ||
|
||||
mRingBufferFetchError != kCARingBufferError_OK)
|
||||
{
|
||||
// Poll until the logger thread has nothing left to log. (Ideally we'd use a semaphore
|
||||
// instead of polling, but it isn't worth the effort at this point.)
|
||||
usleep(10 * 1000);
|
||||
msWaited += 10;
|
||||
|
||||
// Time out after 5 seconds.
|
||||
if(msWaited > 5000)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* BGM_UnitTest */
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
219
BGMApp/BGMApp/BGMPlayThroughRTLogger.h
Normal file
219
BGMApp/BGMApp/BGMPlayThroughRTLogger.h
Normal file
|
@ -0,0 +1,219 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// BGMPlayThroughRTLogger.h
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
// A real-time safe logger for BGMPlayThrough. The messages are logged asynchronously by a
|
||||
// non-realtime thread.
|
||||
//
|
||||
// For the sake of simplicity, this class is very closely coupled with BGMPlayThrough and its
|
||||
// methods make assumptions about where they will be called. Also, if the same logging method is
|
||||
// called multiple times before the logging thread next checks for messages, it will only log the
|
||||
// message for one of those calls and ignore the others.
|
||||
//
|
||||
// This class's methods are real-time safe in that they return in a bounded amount of time and we
|
||||
// think they're probably fast enough that the callers won't miss their deadlines, but we don't try
|
||||
// to guarantee it. Some of them should only be called in unusual cases where it's worth increasing
|
||||
// the risk of a thread missing its deadline.
|
||||
//
|
||||
|
||||
#ifndef BGMApp__BGMPlayThroughRTLogger
|
||||
#define BGMApp__BGMPlayThroughRTLogger
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CARingBuffer.h"
|
||||
|
||||
// STL Includes
|
||||
#include <thread>
|
||||
|
||||
// System Includes
|
||||
#include <mach/error.h>
|
||||
#include <mach/semaphore.h>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
class BGMPlayThroughRTLogger
|
||||
{
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
public:
|
||||
BGMPlayThroughRTLogger();
|
||||
~BGMPlayThroughRTLogger();
|
||||
BGMPlayThroughRTLogger(const BGMPlayThroughRTLogger&) = delete;
|
||||
BGMPlayThroughRTLogger& operator=(
|
||||
const BGMPlayThroughRTLogger&) = delete;
|
||||
private:
|
||||
static semaphore_t CreateSemaphore();
|
||||
|
||||
#pragma mark Log Messages
|
||||
|
||||
public:
|
||||
/*! For BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart. */
|
||||
void LogReleasingWaitingThreads();
|
||||
/*! For BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart. */
|
||||
void LogIfMachError_ReleaseWaitingThreadsSignal(mach_error_t inError);
|
||||
|
||||
/*! For BGMPlayThrough::OutputDeviceIOProc. Not thread-safe. */
|
||||
void LogIfDroppedFrames(Float64 inFirstInputSampleTime,
|
||||
Float64 inLastInputSampleTime);
|
||||
/*! For BGMPlayThrough::OutputDeviceIOProc. Not thread-safe. */
|
||||
void LogNoSamplesReady(CARingBuffer::SampleTime inLastInputSampleTime,
|
||||
CARingBuffer::SampleTime inReadHeadSampleTime,
|
||||
Float64 inInToOutSampleOffset);
|
||||
|
||||
/*! For BGMPlayThrough::UpdateIOProcState. Not thread-safe. */
|
||||
void LogExceptionStoppingIOProc(const char* inCallerName)
|
||||
{
|
||||
LogExceptionStoppingIOProc(inCallerName, noErr, false);
|
||||
}
|
||||
/*! For BGMPlayThrough::UpdateIOProcState. Not thread-safe. */
|
||||
void LogExceptionStoppingIOProc(const char* inCallerName, OSStatus inError)
|
||||
{
|
||||
LogExceptionStoppingIOProc(inCallerName, inError, true);
|
||||
}
|
||||
|
||||
private:
|
||||
void LogExceptionStoppingIOProc(const char* inCallerName,
|
||||
OSStatus inError,
|
||||
bool inErrorKnown);
|
||||
|
||||
public:
|
||||
/*! For BGMPlayThrough::UpdateIOProcState. Not thread-safe. */
|
||||
void LogUnexpectedIOStateAfterStopping(const char* inCallerName,
|
||||
int inIOState);
|
||||
|
||||
/*! For BGMPlayThrough::OutputDeviceIOProc. */
|
||||
void LogIfRingBufferError_Fetch(CARingBufferError inError)
|
||||
{
|
||||
LogIfRingBufferError(inError, mRingBufferFetchError);
|
||||
}
|
||||
/*! For BGMPlayThrough::InputDeviceIOProc. */
|
||||
void LogIfRingBufferError_Store(CARingBufferError inError)
|
||||
{
|
||||
LogIfRingBufferError(inError, mRingBufferStoreError);
|
||||
}
|
||||
|
||||
private:
|
||||
void LogIfRingBufferError(CARingBufferError inError,
|
||||
std::atomic<CARingBufferError>& outError);
|
||||
|
||||
template <typename T, typename F>
|
||||
void LogAsync(T& inMessageData, F&& inStoreMessageData);
|
||||
|
||||
// Wrapper methods used to mock out the logging for unit tests.
|
||||
void LogSync_Warning(const char* inFormat, ...) __printflike(2, 3);
|
||||
void LogSync_Error(const char* inFormat, ...) __printflike(2, 3);
|
||||
|
||||
#pragma mark Logging Thread
|
||||
|
||||
private:
|
||||
void WakeLoggingThread();
|
||||
|
||||
void LogMessages();
|
||||
void LogSync_ReleasingWaitingThreads();
|
||||
void LogSync_ReleaseWaitingThreadsSignalError();
|
||||
void LogSync_DroppedFrames();
|
||||
void LogSync_NoSamplesReady();
|
||||
void LogSync_ExceptionStoppingIOProc();
|
||||
void LogSync_UnexpectedIOStateAfterStopping();
|
||||
void LogSync_RingBufferError(
|
||||
std::atomic<CARingBufferError>& ioRingBufferError,
|
||||
const char* inMethodName);
|
||||
|
||||
// The entry point of the logging thread (mLoggingThread).
|
||||
static void* __nullable LoggingThreadEntry(BGMPlayThroughRTLogger* inRefCon);
|
||||
|
||||
#if BGM_UnitTest
|
||||
|
||||
#pragma mark Test Helpers
|
||||
|
||||
public:
|
||||
/*!
|
||||
* @return True if the logger thread finished logging the requested messages. False if it still
|
||||
* had messages to log after 5 seconds.
|
||||
*/
|
||||
bool WaitUntilLoggerThreadIdle();
|
||||
|
||||
#endif /* BGM_UnitTest */
|
||||
|
||||
private:
|
||||
// For BGMPlayThrough::ReleaseThreadsWaitingForOutputToStart
|
||||
std::atomic<bool> mLogReleasingWaitingThreadsMsg { false };
|
||||
std::atomic<kern_return_t> mReleaseWaitingThreadsSignalError { KERN_SUCCESS };
|
||||
|
||||
// For BGMPlayThrough::InputDeviceIOProc and BGMPlayThrough::OutputDeviceIOProc
|
||||
struct {
|
||||
Float64 firstInputSampleTime;
|
||||
Float64 lastInputSampleTime;
|
||||
std::atomic<bool> shouldLogMessage { false };
|
||||
} mDroppedFrames;
|
||||
|
||||
struct {
|
||||
CARingBuffer::SampleTime lastInputSampleTime;
|
||||
CARingBuffer::SampleTime readHeadSampleTime;
|
||||
Float64 inToOutSampleOffset;
|
||||
std::atomic<bool> shouldLogMessage { false };
|
||||
} mNoSamplesReady;
|
||||
|
||||
// For BGMPlayThrough::UpdateIOProcState
|
||||
struct {
|
||||
const char* callerName;
|
||||
int ioState;
|
||||
std::atomic<bool> shouldLogMessage { false };
|
||||
} mUnexpectedIOStateAfterStopping;
|
||||
|
||||
struct {
|
||||
const char* callerName;
|
||||
OSStatus error;
|
||||
bool errorKnown; // If false, we didn't get an error code from the exception.
|
||||
std::atomic<bool> shouldLogMessage { false };
|
||||
} mExceptionStoppingIOProc;
|
||||
|
||||
// For BGMPlayThrough::OutputDeviceIOProc
|
||||
std::atomic<CARingBufferError> mRingBufferStoreError { kCARingBufferError_OK };
|
||||
// For BGMPlayThrough::InputDeviceIOProc.
|
||||
std::atomic<CARingBufferError> mRingBufferFetchError { kCARingBufferError_OK };
|
||||
|
||||
// Signalled to wake up the mLoggingThread when it has messages to log.
|
||||
semaphore_t mWakeUpLoggingThreadSemaphore;
|
||||
std::atomic<bool> mLoggingThreadShouldExit { false };
|
||||
// The thread that actually logs the messages.
|
||||
std::thread mLoggingThread;
|
||||
|
||||
#if BGM_UnitTest
|
||||
|
||||
public:
|
||||
// Tests normally crash (abort) if LogError is called. This flag lets us test the code that
|
||||
// would otherwise call LogError.
|
||||
bool mContinueOnErrorLogged { false };
|
||||
|
||||
int mNumDebugMessagesLogged { 0 };
|
||||
int mNumWarningMessagesLogged { 0 };
|
||||
int mNumErrorMessagesLogged { 0 };
|
||||
|
||||
#endif /* BGM_UnitTest */
|
||||
|
||||
};
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* BGMApp__BGMPlayThroughRTLogger */
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
// BGMStatusBarItem.h
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2019 Kyle Neideck
|
||||
// Copyright © 2019, 2020 Kyle Neideck
|
||||
//
|
||||
// The button in the system status bar (the bar with volume, battery, clock, etc.) to show the main
|
||||
// menu for the app. These are called "menu bar extras" in the Human Interface Guidelines.
|
||||
|
@ -25,6 +25,7 @@
|
|||
|
||||
// Local Includes
|
||||
#import "BGMAudioDeviceManager.h"
|
||||
#import "BGMDebugLoggingMenuItem.h"
|
||||
|
||||
// System Includes
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
@ -57,6 +58,10 @@ static BGMStatusBarIcon const kBGMStatusBarIconDefaultValue = BGMFermataStatusBa
|
|||
// same as the icon for the macOS volume status bar item.
|
||||
@property BGMStatusBarIcon icon;
|
||||
|
||||
// If the user holds down the option key when they click the status bar icon, this menu item will be
|
||||
// shown in the main menu.
|
||||
- (void) setDebugLoggingMenuItem:(BGMDebugLoggingMenuItem*)menuItem;
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// BGMStatusBarItem.m
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2019 Kyle Neideck
|
||||
// Copyright © 2019, 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
|
@ -48,11 +48,16 @@ static CGFloat const kVolumeIconAdditionalVerticalPadding = 0.075;
|
|||
NSImage* volumeIcon3SoundWaves;
|
||||
|
||||
NSStatusItem* statusBarItem;
|
||||
BGMDebugLoggingMenuItem* debugLoggingMenuItem;
|
||||
|
||||
BGMVolumeChangeListener* volumeChangeListener;
|
||||
id __nullable clickEventHandler;
|
||||
|
||||
BGMStatusBarIcon _icon;
|
||||
}
|
||||
|
||||
#pragma mark Initialisation
|
||||
|
||||
- (instancetype) initWithMenu:(NSMenu*)bgmMenu
|
||||
audioDevices:(BGMAudioDeviceManager*)devices
|
||||
userDefaults:(BGMUserDefaults*)defaults {
|
||||
|
@ -72,6 +77,10 @@ static CGFloat const kVolumeIconAdditionalVerticalPadding = 0.075;
|
|||
// Set the menu item to open the main menu.
|
||||
statusBarItem.menu = bgmMenu;
|
||||
|
||||
// Monitor click events so we can show extra options in the menu if the user was holding the
|
||||
// option key.
|
||||
clickEventHandler = [self addClickMonitor];
|
||||
|
||||
// Set the accessibility label to "Background Music". (We intentionally don't set a title or
|
||||
// a tooltip.)
|
||||
if ([BGMStatusBarItem buttonAvailable]) {
|
||||
|
@ -92,8 +101,25 @@ static CGFloat const kVolumeIconAdditionalVerticalPadding = 0.075;
|
|||
return self;
|
||||
}
|
||||
|
||||
- (id __nullable) addClickMonitor {
|
||||
NSEvent* __nullable (^handlerBlock)(NSEvent*) =
|
||||
^NSEvent* __nullable (NSEvent* event) {
|
||||
[self statusBarItemWasClicked:event];
|
||||
return event;
|
||||
};
|
||||
|
||||
// TODO: I doubt this works well with VoiceOver.
|
||||
return [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown
|
||||
handler:handlerBlock];
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
delete volumeChangeListener;
|
||||
|
||||
if (clickEventHandler) {
|
||||
[NSEvent removeMonitor:(id)clickEventHandler];
|
||||
clickEventHandler = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) initIcons {
|
||||
|
@ -142,6 +168,8 @@ static CGFloat const kVolumeIconAdditionalVerticalPadding = 0.075;
|
|||
[volumeIcon3SoundWaves setTemplate:YES];
|
||||
}
|
||||
|
||||
#pragma mark Accessors
|
||||
|
||||
+ (BOOL) buttonAvailable {
|
||||
// NSStatusItem doesn't have the "button" property on OS X 10.9.
|
||||
return (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_10);
|
||||
|
@ -188,6 +216,8 @@ static CGFloat const kVolumeIconAdditionalVerticalPadding = 0.075;
|
|||
});
|
||||
}
|
||||
|
||||
#pragma mark Volume Icon
|
||||
|
||||
- (void) bgmDeviceVolumeDidChange {
|
||||
if (self.icon == BGMVolumeStatusBarIcon) {
|
||||
[self updateVolumeStatusBarIcon];
|
||||
|
@ -251,6 +281,21 @@ static CGFloat const kVolumeIconAdditionalVerticalPadding = 0.075;
|
|||
statusBarItem.image.name.UTF8String);
|
||||
}
|
||||
|
||||
#pragma mark Debug Logging Menu Item
|
||||
|
||||
- (void) statusBarItemWasClicked:(NSEvent* __nonnull)event {
|
||||
if ((event.modifierFlags & NSEventModifierFlagOption) != 0) {
|
||||
DebugMsg("BGMStatusBarItem::statusBarItemWasClicked: Option key held");
|
||||
[debugLoggingMenuItem setMenuShowingExtraOptions:YES];
|
||||
} else {
|
||||
[debugLoggingMenuItem setMenuShowingExtraOptions:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setDebugLoggingMenuItem:(BGMDebugLoggingMenuItem*)menuItem {
|
||||
debugLoggingMenuItem = menuItem;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14835.7" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<development version="8000" identifier="xcode"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14835.7"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
@ -21,6 +20,7 @@
|
|||
<outlet property="appVolumeView" destination="MWB-XH-kFI" id="eFA-RN-VMC"/>
|
||||
<outlet property="autoPauseMenuItemUnwrapped" destination="nHv-T8-1nb" id="Lie-Cx-jw6"/>
|
||||
<outlet property="bgmMenu" destination="8AN-nh-rEe" id="UWn-BX-eLy"/>
|
||||
<outlet property="debugLoggingMenuItemUnwrapped" destination="sc9-vO-KyP" id="Zyd-0v-0RN"/>
|
||||
<outlet property="outputVolumeLabel" destination="wfC-C6-SLv" id="Nuf-mo-osG"/>
|
||||
<outlet property="outputVolumeSlider" destination="9Ru-Sc-dqC" id="wv0-Md-BwF"/>
|
||||
<outlet property="outputVolumeView" destination="JOz-H1-mj9" id="xeJ-fk-NMI"/>
|
||||
|
@ -68,6 +68,9 @@
|
|||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Debug Logging" hidden="YES" toolTip="Log detailed messages to help diagnose bugs. Search for "bgm" or "background music" in Console.app." id="sc9-vO-KyP">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Quit Background Music" id="Nj2-gJ-DhW">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
|
@ -128,7 +131,7 @@
|
|||
<rect key="frame" x="162" y="-1" width="12" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="L" id="hgE-7A-bez">
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<font key="font" metaFont="menu" size="9"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
@ -137,7 +140,7 @@
|
|||
<rect key="frame" x="228" y="-1" width="12" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="R" id="lzr-NO-0Na">
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<font key="font" metaFont="menu" size="9"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
@ -244,7 +247,7 @@
|
|||
<rect key="frame" x="413" y="20" width="203" height="11"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="The AirPlay Logo is a trademark of Apple Inc." id="lx7-k3-q16">
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<font key="font" metaFont="menu" size="9"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
@ -252,7 +255,7 @@
|
|||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" tag="2" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vy4-dv-jQB">
|
||||
<rect key="frame" x="18" y="75" width="346" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Copyright © 2016-2019 Background Music contributors" placeholderString="" id="ctF-95-uVu">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Copyright © 2016-2020 Background Music contributors" placeholderString="" id="ctF-95-uVu">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -330,53 +333,53 @@
|
|||
<image name="buttonCell:IXo-C7-3uE:image" width="1" height="1">
|
||||
<mutableData key="keyedArchiveRepresentation">
|
||||
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05T
|
||||
S2V5ZWRBcmNoaXZlctEICVRyb290gAGuCwwXGB0iIycoLzI1Oz5VJG51bGzVDQ4PEBESExQVFlZOU1Np
|
||||
emVWJGNsYXNzXE5TSW1hZ2VGbGFnc1ZOU1JlcHNXTlNDb2xvcoACgA0SIMMAAIADgAtWezEsIDF90hkO
|
||||
GhxaTlMub2JqZWN0c6EbgASACtIZDh4hoh8ggAWABoAJEADSJA4lJl8QFE5TVElGRlJlcHJlc2VudGF0
|
||||
aW9ugAeACE8RCMRNTQAqAAAACgAAABABAAADAAAAAQABAAABAQADAAAAAQABAAABAgADAAAAAgAIAAgB
|
||||
AwADAAAAAQABAAABBgADAAAAAQABAAABCgADAAAAAQABAAABEQAEAAAAAQAAAAgBEgADAAAAAQABAAAB
|
||||
FQADAAAAAQACAAABFgADAAAAAQABAAABFwAEAAAAAQAAAAIBHAADAAAAAQABAAABKAADAAAAAQACAAAB
|
||||
UgADAAAAAQABAAABUwADAAAAAgABAAGHcwAHAAAH9AAAANAAAAAAAAAH9GFwcGwCIAAAbW50ckdSQVlY
|
||||
WVogB9AAAgAOAAwAAAAAYWNzcEFQUEwAAAAAbm9uZQAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1h
|
||||
cHBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZGVzYwAAAMAA
|
||||
AABvZHNjbQAAATAAAAZmY3BydAAAB5gAAAA4d3RwdAAAB9AAAAAUa1RSQwAAB+QAAAAOZGVzYwAAAAAA
|
||||
AAAVR2VuZXJpYyBHcmF5IFByb2ZpbGUAAAAAAAAAAAAAABVHZW5lcmljIEdyYXkgUHJvZmlsZQAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1sdWMAAAAAAAAAHwAAAAxz
|
||||
a1NLAAAAKgAAAYRlblVTAAAAKAAAAa5jYUVTAAAALAAAAdZ2aVZOAAAALAAAAgJwdEJSAAAAKgAAAi51
|
||||
a1VBAAAALAAAAlhmckZVAAAAKgAAAoRodUhVAAAALgAAAq56aFRXAAAAEAAAAtxuYk5PAAAALAAAAuxr
|
||||
b0tSAAAAGAAAAxhjc0NaAAAAJAAAAzBoZUlMAAAAIAAAA1Ryb1JPAAAAJAAAA3RkZURFAAAAOgAAA5hp
|
||||
dElUAAAALgAAA9JzdlNFAAAALgAABAB6aENOAAAAEAAABC5qYUpQAAAAFgAABD5lbEdSAAAAJAAABFRw
|
||||
dFBPAAAAOAAABHhubE5MAAAAKgAABLBlc0VTAAAAKAAABNp0aFRIAAAAJAAABQJ0clRSAAAAIgAABSZm
|
||||
aUZJAAAALAAABUhockhSAAAAOgAABXRwbFBMAAAANgAABa5ydVJVAAAAJgAABeRhckVHAAAAKAAABgpk
|
||||
YURLAAAANAAABjIAVgFhAGUAbwBiAGUAYwBuAP0AIABzAGkAdgD9ACAAcAByAG8AZgBpAGwARwBlAG4A
|
||||
ZQByAGkAYwAgAEcAcgBhAHkAIABQAHIAbwBmAGkAbABlAFAAZQByAGYAaQBsACAAZABlACAAZwByAGkA
|
||||
cwAgAGcAZQBuAOgAcgBpAGMAQx6lAHUAIABoAOwAbgBoACAATQDgAHUAIAB4AOEAbQAgAEMAaAB1AG4A
|
||||
ZwBQAGUAcgBmAGkAbAAgAEMAaQBuAHoAYQAgAEcAZQBuAOkAcgBpAGMAbwQXBDAEMwQwBDsETAQ9BDgE
|
||||
OQAgBD8EQAQ+BEQEMAQ5BDsAIABHAHIAYQB5AFAAcgBvAGYAaQBsACAAZwDpAG4A6QByAGkAcQB1AGUA
|
||||
IABnAHIAaQBzAMEAbAB0AGEAbADhAG4AbwBzACAAcwB6APwAcgBrAGUAIABwAHIAbwBmAGkAbJAadShw
|
||||
cJaOgnJfaWPPj/AARwBlAG4AZQByAGkAcwBrACAAZwByAOUAdABvAG4AZQBwAHIAbwBmAGkAbMd8vBgA
|
||||
IABHAHIAYQB5ACDVBLhc0wzHfABPAGIAZQBjAG4A/QAgAWEAZQBkAP0AIABwAHIAbwBmAGkAbAXkBegF
|
||||
1QXkBdkF3AAgAEcAcgBhAHkAIAXbBdwF3AXZAFAAcgBvAGYAaQBsACAAZwByAGkAIABnAGUAbgBlAHIA
|
||||
aQBjAEEAbABsAGcAZQBtAGUAaQBuAGUAcwAgAEcAcgBhAHUAcwB0AHUAZgBlAG4ALQBQAHIAbwBmAGkA
|
||||
bABQAHIAbwBmAGkAbABvACAAZwByAGkAZwBpAG8AIABnAGUAbgBlAHIAaQBjAG8ARwBlAG4AZQByAGkA
|
||||
cwBrACAAZwByAOUAcwBrAGEAbABlAHAAcgBvAGYAaQBsZm6QGnBwXqZjz4/wZYdO9k4AgiwwsDDsMKQw
|
||||
1zDtMNUwoTCkMOsDkwO1A70DuQO6A8wAIAPAA8EDvwPGA68DuwAgA7MDugPBA7kAUABlAHIAZgBpAGwA
|
||||
IABnAGUAbgDpAHIAaQBjAG8AIABkAGUAIABjAGkAbgB6AGUAbgB0AG8AcwBBAGwAZwBlAG0AZQBlAG4A
|
||||
IABnAHIAaQBqAHMAcAByAG8AZgBpAGUAbABQAGUAcgBmAGkAbAAgAGcAcgBpAHMAIABnAGUAbgDpAHIA
|
||||
aQBjAG8OQg4bDiMORA4fDiUOTA4qDjUOQA4XDjIOFw4xDkgOJw5EDhsARwBlAG4AZQBsACAARwByAGkA
|
||||
IABQAHIAbwBmAGkAbABpAFkAbABlAGkAbgBlAG4AIABoAGEAcgBtAGEAYQBwAHIAbwBmAGkAaQBsAGkA
|
||||
RwBlAG4AZQByAGkBDQBrAGkAIABwAHIAbwBmAGkAbAAgAHMAaQB2AGkAaAAgAHQAbwBuAG8AdgBhAFUA
|
||||
bgBpAHcAZQByAHMAYQBsAG4AeQAgAHAAcgBvAGYAaQBsACAAcwB6AGEAcgBvAVsAYwBpBB4EMQRJBDgE
|
||||
OQAgBEEENQRABEsEOQAgBD8EQAQ+BEQEOAQ7BEwGRQZEBkEAIAYqBjkGMQZKBkEAIABHAHIAYQB5ACAG
|
||||
JwZEBjkGJwZFAEcAZQBuAGUAcgBlAGwAIABnAHIA5QB0AG8AbgBlAGIAZQBzAGsAcgBpAHYAZQBsAHMA
|
||||
ZQAAdGV4dAAAAABDb3B5cmlnaHQgMjAwNyBBcHBsZSBJbmMuLCBhbGwgcmlnaHRzIHJlc2VydmVkLgBY
|
||||
WVogAAAAAAAA81EAAQAAAAEWzGN1cnYAAAAAAAAAAQHNAADSKSorLFokY2xhc3NuYW1lWCRjbGFzc2Vz
|
||||
XxAQTlNCaXRtYXBJbWFnZVJlcKMrLS5aTlNJbWFnZVJlcFhOU09iamVjdNIpKjAxV05TQXJyYXmiMC7S
|
||||
KSozNF5OU011dGFibGVBcnJheaMzMC7TNjcOODk6V05TV2hpdGVcTlNDb2xvclNwYWNlRDAgMAAQA4AM
|
||||
0ikqPD1XTlNDb2xvcqI8LtIpKj9AV05TSW1hZ2WiPy4ACAARABoAJAApADIANwBJAEwAUQBTAGIAaABz
|
||||
AHoAgQCOAJUAnQCfAKEApgCoAKoAsQC2AMEAwwDFAMcAzADPANEA0wDVANcA3ADzAPUA9wm/CcQJzwnY
|
||||
CesJ7wn6CgMKCAoQChMKGAonCisKMgo6CkcKTApOClAKVQpdCmAKZQptAAAAAAAAAgEAAAAAAAAAQQAA
|
||||
AAAAAAAAAAAAAAAACnA
|
||||
S2V5ZWRBcmNoaXZlctEICVRyb290gAGuCwwZGh8UJCgpMDM2PD9VJG51bGzWDQ4PEBESExQVFhcYVk5T
|
||||
U2l6ZV5OU1Jlc2l6aW5nTW9kZVYkY2xhc3NcTlNJbWFnZUZsYWdzVk5TUmVwc1dOU0NvbG9ygAIQAIAN
|
||||
EiDDAACAA4ALVnsxLCAxfdIbDxweWk5TLm9iamVjdHOhHYAEgArSGw8gI6IhIoAFgAaACdIlDyYnXxAU
|
||||
TlNUSUZGUmVwcmVzZW50YXRpb26AB4AITxEIxE1NACoAAAAKAAAAEAEAAAMAAAABAAEAAAEBAAMAAAAB
|
||||
AAEAAAECAAMAAAACAAgACAEDAAMAAAABAAEAAAEGAAMAAAABAAEAAAEKAAMAAAABAAEAAAERAAQAAAAB
|
||||
AAAACAESAAMAAAABAAEAAAEVAAMAAAABAAIAAAEWAAMAAAABAAEAAAEXAAQAAAABAAAAAgEcAAMAAAAB
|
||||
AAEAAAEoAAMAAAABAAIAAAFSAAMAAAABAAEAAAFTAAMAAAACAAEAAYdzAAcAAAf0AAAA0AAAAAAAAAf0
|
||||
YXBwbAIgAABtbnRyR1JBWVhZWiAH0AACAA4ADAAAAABhY3NwQVBQTAAAAABub25lAAAAAAAAAAAAAAAA
|
||||
AAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAVkZXNjAAAAwAAAAG9kc2NtAAABMAAABmZjcHJ0AAAHmAAAADh3dHB0AAAH0AAAABRrVFJD
|
||||
AAAH5AAAAA5kZXNjAAAAAAAAABVHZW5lcmljIEdyYXkgUHJvZmlsZQAAAAAAAAAAAAAAFUdlbmVyaWMg
|
||||
R3JheSBQcm9maWxlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
bWx1YwAAAAAAAAAfAAAADHNrU0sAAAAqAAABhGVuVVMAAAAoAAABrmNhRVMAAAAsAAAB1nZpVk4AAAAs
|
||||
AAACAnB0QlIAAAAqAAACLnVrVUEAAAAsAAACWGZyRlUAAAAqAAAChGh1SFUAAAAuAAACrnpoVFcAAAAQ
|
||||
AAAC3G5iTk8AAAAsAAAC7GtvS1IAAAAYAAADGGNzQ1oAAAAkAAADMGhlSUwAAAAgAAADVHJvUk8AAAAk
|
||||
AAADdGRlREUAAAA6AAADmGl0SVQAAAAuAAAD0nN2U0UAAAAuAAAEAHpoQ04AAAAQAAAELmphSlAAAAAW
|
||||
AAAEPmVsR1IAAAAkAAAEVHB0UE8AAAA4AAAEeG5sTkwAAAAqAAAEsGVzRVMAAAAoAAAE2nRoVEgAAAAk
|
||||
AAAFAnRyVFIAAAAiAAAFJmZpRkkAAAAsAAAFSGhySFIAAAA6AAAFdHBsUEwAAAA2AAAFrnJ1UlUAAAAm
|
||||
AAAF5GFyRUcAAAAoAAAGCmRhREsAAAA0AAAGMgBWAWEAZQBvAGIAZQBjAG4A/QAgAHMAaQB2AP0AIABw
|
||||
AHIAbwBmAGkAbABHAGUAbgBlAHIAaQBjACAARwByAGEAeQAgAFAAcgBvAGYAaQBsAGUAUABlAHIAZgBp
|
||||
AGwAIABkAGUAIABnAHIAaQBzACAAZwBlAG4A6AByAGkAYwBDHqUAdQAgAGgA7ABuAGgAIABNAOAAdQAg
|
||||
AHgA4QBtACAAQwBoAHUAbgBnAFAAZQByAGYAaQBsACAAQwBpAG4AegBhACAARwBlAG4A6QByAGkAYwBv
|
||||
BBcEMAQzBDAEOwRMBD0EOAQ5ACAEPwRABD4ERAQwBDkEOwAgAEcAcgBhAHkAUAByAG8AZgBpAGwAIABn
|
||||
AOkAbgDpAHIAaQBxAHUAZQAgAGcAcgBpAHMAwQBsAHQAYQBsAOEAbgBvAHMAIABzAHoA/AByAGsAZQAg
|
||||
AHAAcgBvAGYAaQBskBp1KHBwlo6Ccl9pY8+P8ABHAGUAbgBlAHIAaQBzAGsAIABnAHIA5QB0AG8AbgBl
|
||||
AHAAcgBvAGYAaQBsx3y8GAAgAEcAcgBhAHkAINUEuFzTDMd8AE8AYgBlAGMAbgD9ACABYQBlAGQA/QAg
|
||||
AHAAcgBvAGYAaQBsBeQF6AXVBeQF2QXcACAARwByAGEAeQAgBdsF3AXcBdkAUAByAG8AZgBpAGwAIABn
|
||||
AHIAaQAgAGcAZQBuAGUAcgBpAGMAQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAARwByAGEAdQBzAHQAdQBm
|
||||
AGUAbgAtAFAAcgBvAGYAaQBsAFAAcgBvAGYAaQBsAG8AIABnAHIAaQBnAGkAbwAgAGcAZQBuAGUAcgBp
|
||||
AGMAbwBHAGUAbgBlAHIAaQBzAGsAIABnAHIA5QBzAGsAYQBsAGUAcAByAG8AZgBpAGxmbpAacHBepmPP
|
||||
j/Blh072TgCCLDCwMOwwpDDXMO0w1TChMKQw6wOTA7UDvQO5A7oDzAAgA8ADwQO/A8YDrwO7ACADswO6
|
||||
A8EDuQBQAGUAcgBmAGkAbAAgAGcAZQBuAOkAcgBpAGMAbwAgAGQAZQAgAGMAaQBuAHoAZQBuAHQAbwBz
|
||||
AEEAbABnAGUAbQBlAGUAbgAgAGcAcgBpAGoAcwBwAHIAbwBmAGkAZQBsAFAAZQByAGYAaQBsACAAZwBy
|
||||
AGkAcwAgAGcAZQBuAOkAcgBpAGMAbw5CDhsOIw5EDh8OJQ5MDioONQ5ADhcOMg4XDjEOSA4nDkQOGwBH
|
||||
AGUAbgBlAGwAIABHAHIAaQAgAFAAcgBvAGYAaQBsAGkAWQBsAGUAaQBuAGUAbgAgAGgAYQByAG0AYQBh
|
||||
AHAAcgBvAGYAaQBpAGwAaQBHAGUAbgBlAHIAaQENAGsAaQAgAHAAcgBvAGYAaQBsACAAcwBpAHYAaQBo
|
||||
ACAAdABvAG4AbwB2AGEAVQBuAGkAdwBlAHIAcwBhAGwAbgB5ACAAcAByAG8AZgBpAGwAIABzAHoAYQBy
|
||||
AG8BWwBjAGkEHgQxBEkEOAQ5ACAEQQQ1BEAESwQ5ACAEPwRABD4ERAQ4BDsETAZFBkQGQQAgBioGOQYx
|
||||
BkoGQQAgAEcAcgBhAHkAIAYnBkQGOQYnBkUARwBlAG4AZQByAGUAbAAgAGcAcgDlAHQAbwBuAGUAYgBl
|
||||
AHMAawByAGkAdgBlAGwAcwBlAAB0ZXh0AAAAAENvcHlyaWdodCAyMDA3IEFwcGxlIEluYy4sIGFsbCBy
|
||||
aWdodHMgcmVzZXJ2ZWQuAFhZWiAAAAAAAADzUQABAAAAARbMY3VydgAAAAAAAAABAc0AANIqKywtWiRj
|
||||
bGFzc25hbWVYJGNsYXNzZXNfEBBOU0JpdG1hcEltYWdlUmVwoywuL1pOU0ltYWdlUmVwWE5TT2JqZWN0
|
||||
0iorMTJXTlNBcnJheaIxL9IqKzQ1Xk5TTXV0YWJsZUFycmF5ozQxL9M3OA85OjtXTlNXaGl0ZVxOU0Nv
|
||||
bG9yU3BhY2VEMCAwABADgAzSKis9PldOU0NvbG9yoj0v0iorQEFXTlNJbWFnZaJALwAIABEAGgAkACkA
|
||||
MgA3AEkATABRAFMAYgBoAHUAfACLAJIAnwCmAK4AsACyALQAuQC7AL0AxADJANQA1gDYANoA3wDiAOQA
|
||||
5gDoAO0BBAEGAQgJ0AnVCeAJ6Qn8CgAKCwoUChkKIQokCikKOAo8CkMKSwpYCl0KXwphCmYKbgpxCnYK
|
||||
fgAAAAAAAAIBAAAAAAAAAEIAAAAAAAAAAAAAAAAAAAqBA
|
||||
</mutableData>
|
||||
</image>
|
||||
</resources>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<key>NSAppleScriptEnabled</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016-2019 Background Music contributors</string>
|
||||
<string>Copyright © 2016-2020 Background Music contributors</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// BGMApp
|
||||
//
|
||||
// Copyright © 2016-2018 Kyle Neideck
|
||||
// Portions copyright (C) 2012 Peter Ljunglöf. All rights reserved.
|
||||
// Copyright (C) 2012 Peter Ljunglöf. All rights reserved.
|
||||
//
|
||||
|
||||
// Self Include
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// BGMAppUITests.mm
|
||||
// BGMAppUITests
|
||||
//
|
||||
// Copyright © 2017, 2018 Kyle Neideck
|
||||
// Copyright © 2017, 2018, 2020 Kyle Neideck
|
||||
//
|
||||
// You might want to use Xcode's UI test recording feature if you add new tests.
|
||||
//
|
||||
|
@ -30,6 +30,9 @@
|
|||
// Scripting Bridge Includes
|
||||
#import "BGMApp.h"
|
||||
|
||||
// System Includes
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
|
||||
// TODO: Skip these tests if macOS SDK 10.11 or higher isn't available.
|
||||
// TODO: Mock BGMDevice and music players.
|
||||
|
@ -99,13 +102,15 @@
|
|||
[menuItems[@"Quit Background Music"] click];
|
||||
|
||||
// BGMApp should quit.
|
||||
XCTAssert(!app.exists);
|
||||
for (NSRunningApplication* runningApp : [[NSWorkspace sharedWorkspace] runningApplications]) {
|
||||
XCTAssertFalse([[runningApp bundleIdentifier] isEqualToString:@kBGMAppBundleID]);
|
||||
}
|
||||
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void) testCycleOutputDevices {
|
||||
const int NUM_CYCLES = 2;
|
||||
const int NUM_CYCLES = 1;
|
||||
|
||||
// sbApp lets us use AppleScript to query BGMApp and check the test has made the changes to its
|
||||
// settings we expect.
|
||||
|
|
|
@ -17,24 +17,28 @@
|
|||
// BGMMusicPlayersUnitTests.mm
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2016-2018 Kyle Neideck
|
||||
// Copyright © 2016-2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Unit include
|
||||
#import "BGMMusicPlayers.h"
|
||||
|
||||
// Local includes
|
||||
#import "BGM_TestUtils.h"
|
||||
|
||||
// BGM includes
|
||||
#import "BGM_Types.h"
|
||||
#import "BGMAudioDeviceManager.h"
|
||||
#import "BGMiTunes.h"
|
||||
#import "BGMVLC.h"
|
||||
#import "BGMDecibel.h"
|
||||
#import "BGMSpotify.h"
|
||||
#import "BGMVLC.h"
|
||||
|
||||
// Local includes
|
||||
#import "BGM_TestUtils.h"
|
||||
#import "MockAudioObject.h"
|
||||
#import "MockAudioObjects.h"
|
||||
|
||||
// System includes
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
|
||||
// Note that the PublicUtility classes that we use to communicate with the HAL, CAHALAudioObject and
|
||||
|
@ -72,32 +76,6 @@
|
|||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
class BGMMockBackgroundMusicDevice
|
||||
:
|
||||
public BGMBackgroundMusicDevice
|
||||
{
|
||||
|
||||
public:
|
||||
CFStringRef GetMusicPlayerBundleID() const;
|
||||
void SetMusicPlayerBundleID(CFStringRef inBundleID);
|
||||
|
||||
private:
|
||||
CFStringRef mMusicPlayerBundleID = CFSTR("");
|
||||
|
||||
};
|
||||
|
||||
CFStringRef BGMMockBackgroundMusicDevice::GetMusicPlayerBundleID() const
|
||||
{
|
||||
return mMusicPlayerBundleID;
|
||||
}
|
||||
|
||||
void BGMMockBackgroundMusicDevice::SetMusicPlayerBundleID(CFStringRef inBundleID)
|
||||
{
|
||||
mMusicPlayerBundleID = inBundleID;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
@interface BGMMockAudioDeviceManager : BGMAudioDeviceManager
|
||||
@end
|
||||
|
||||
|
@ -127,6 +105,10 @@ void BGMMockBackgroundMusicDevice::SetMusicPlayerBundleID(CFStringRef inBundleID
|
|||
- (void) setUp {
|
||||
[super setUp];
|
||||
|
||||
// Mock BGMDevice.
|
||||
MockAudioObjects::CreateMockDevice(kBGMDeviceUID);
|
||||
MockAudioObjects::CreateMockDevice(kBGMDeviceUID_UISounds);
|
||||
|
||||
devices = [BGMMockAudioDeviceManager new];
|
||||
defaults = [BGMMockUserDefaults new];
|
||||
|
||||
|
@ -137,9 +119,10 @@ void BGMMockBackgroundMusicDevice::SetMusicPlayerBundleID(CFStringRef inBundleID
|
|||
|
||||
- (void) tearDown {
|
||||
[super tearDown];
|
||||
MockAudioObjects::DestroyMocks();
|
||||
}
|
||||
|
||||
- (void) testNoSelectedMusicPlayerStored {
|
||||
- (void) testNoSelectedMusicPlayerStored_iTunesDefault {
|
||||
// Test the case where the user has never changed the music player preference.
|
||||
|
||||
// Test with iTunes as the default.
|
||||
|
@ -156,16 +139,20 @@ void BGMMockBackgroundMusicDevice::SetMusicPlayerBundleID(CFStringRef inBundleID
|
|||
|
||||
XCTAssertEqualObjects(players.selectedMusicPlayer.musicPlayerID, [BGMiTunes sharedMusicPlayerID]);
|
||||
XCTAssertEqualObjects(players.selectedMusicPlayer.name, @"iTunes");
|
||||
|
||||
[self resetDevice];
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void) testNoSelectedMusicPlayerStored_vlcDefault {
|
||||
// Test the case where the user has never changed the music player preference.
|
||||
|
||||
// Test with VLC as the default.
|
||||
players = [[BGMMusicPlayers alloc] initWithAudioDevices:devices
|
||||
defaultMusicPlayerID:vlcID
|
||||
musicPlayerClasses:@[ BGMiTunes.class,
|
||||
BGMVLC.class,
|
||||
BGMDecibel.class ]
|
||||
userDefaults:defaults];
|
||||
BGMMusicPlayers* players =
|
||||
[[BGMMusicPlayers alloc] initWithAudioDevices:devices
|
||||
defaultMusicPlayerID:vlcID
|
||||
musicPlayerClasses:@[ BGMiTunes.class,
|
||||
BGMVLC.class,
|
||||
BGMDecibel.class ]
|
||||
userDefaults:defaults];
|
||||
|
||||
XCTAssertEqual(players.musicPlayers.count, 3);
|
||||
|
||||
|
@ -193,15 +180,15 @@ void BGMMockBackgroundMusicDevice::SetMusicPlayerBundleID(CFStringRef inBundleID
|
|||
|
||||
XCTAssertEqualObjects(players.selectedMusicPlayer.musicPlayerID, spotifyID);
|
||||
XCTAssertEqualObjects(players.selectedMusicPlayer.name, @"Spotify");
|
||||
|
||||
[self resetDevice];
|
||||
|
||||
}
|
||||
|
||||
- (void) testUnrecognizedSelectedMusicPlayerInUserDefaults {
|
||||
// If there's an unrecognized ID in user defaults, the default music player should be selected.
|
||||
defaults.selectedPlayerID = [[NSUUID alloc] initWithUUIDString:@"11111111-1111-1111-0000-000000000000"];
|
||||
|
||||
// This initializer sets iTunes as the default music player and adds all the other music players.
|
||||
players = [[BGMMusicPlayers alloc] initWithAudioDevices:devices
|
||||
userDefaults:defaults];
|
||||
BGMMusicPlayers* players = [[BGMMusicPlayers alloc] initWithAudioDevices:devices
|
||||
userDefaults:defaults];
|
||||
|
||||
XCTAssert(players.musicPlayers.count >= 6);
|
||||
|
||||
|
@ -226,10 +213,5 @@ void BGMMockBackgroundMusicDevice::SetMusicPlayerBundleID(CFStringRef inBundleID
|
|||
|
||||
// TODO: Test setting the selectedMusicPlayer property
|
||||
|
||||
- (void) resetDevice {
|
||||
// Reset the mock BGMDevice.
|
||||
[devices bgmDevice].SetMusicPlayerBundleID(CFSTR(""));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
|
174
BGMApp/BGMAppTests/UnitTests/BGMPlayThroughRTLoggerTests.mm
Normal file
174
BGMApp/BGMAppTests/UnitTests/BGMPlayThroughRTLoggerTests.mm
Normal file
|
@ -0,0 +1,174 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// BGMPlayThroughRTLoggerTests.mm
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Unit Include
|
||||
#import "BGMPlayThroughRTLogger.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#import "CARingBuffer.h"
|
||||
|
||||
// System Includes
|
||||
#import <CoreAudio/CoreAudio.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
|
||||
@interface BGMPlayThroughRTLoggerTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation BGMPlayThroughRTLoggerTests
|
||||
{
|
||||
BGMPlayThroughRTLogger* logger;
|
||||
}
|
||||
|
||||
- (void) setUp {
|
||||
[super setUp];
|
||||
logger = new BGMPlayThroughRTLogger;
|
||||
}
|
||||
|
||||
- (void) tearDown {
|
||||
[super tearDown];
|
||||
delete logger;
|
||||
}
|
||||
|
||||
- (void) testLogReleasingWaitingThreads {
|
||||
logger->LogReleasingWaitingThreads();
|
||||
[self assertLoggedOneDebugMessage];
|
||||
}
|
||||
|
||||
- (void) testLogIfMachError_ReleaseWaitingThreadsSignal {
|
||||
logger->LogIfMachError_ReleaseWaitingThreadsSignal(KERN_SUCCESS);
|
||||
[self assertLoggedNoMessages];
|
||||
}
|
||||
|
||||
- (void) testLogIfDroppedFrames_didNotDropFrames {
|
||||
logger->LogIfDroppedFrames(11256.0, 11256.0);
|
||||
[self assertLoggedNoMessages];
|
||||
}
|
||||
|
||||
- (void) testLogIfDroppedFrames_didDropFrames {
|
||||
logger->LogIfDroppedFrames(11256.0, 11768.0);
|
||||
[self assertLoggedOneDebugMessage];
|
||||
}
|
||||
|
||||
- (void) testLogNoSamplesReady {
|
||||
logger->LogNoSamplesReady(512, 1024, 512.0);
|
||||
[self assertLoggedOneDebugMessage];
|
||||
}
|
||||
|
||||
- (void) testLogExceptionStoppingIOProc_withoutErrorCode {
|
||||
// Set a test-only flag that keeps it from calling abort() after logging the error when the
|
||||
// tests are compiled with the debug configuration.
|
||||
logger->mContinueOnErrorLogged = true;
|
||||
|
||||
logger->LogExceptionStoppingIOProc("InputDeviceIOProc");
|
||||
[self assertLoggedOneErrorMessage];
|
||||
}
|
||||
|
||||
- (void) testLogExceptionStoppingIOProc_withErrorCode {
|
||||
// Set a test-only flag that keeps it from calling abort() after logging the error when the
|
||||
// tests are compiled with the debug configuration.
|
||||
logger->mContinueOnErrorLogged = true;
|
||||
|
||||
logger->LogExceptionStoppingIOProc("OutputDeviceIOProc", kAudioHardwareUnknownPropertyError);
|
||||
[self assertLoggedOneErrorMessage];
|
||||
}
|
||||
|
||||
- (void) testLogUnexpectedIOStateAfterStopping {
|
||||
logger->LogUnexpectedIOStateAfterStopping("OutputDeviceIOProc", 1);
|
||||
[self assertLoggedOneWarningMessage];
|
||||
}
|
||||
|
||||
- (void) testLogIfRingBufferError_Fetch_noError {
|
||||
logger->LogIfRingBufferError_Fetch(kCARingBufferError_OK);
|
||||
[self assertLoggedNoMessages];
|
||||
}
|
||||
|
||||
- (void) testLogIfRingBufferError_Fetch_errorCPUOverload {
|
||||
logger->LogIfRingBufferError_Fetch(kCARingBufferError_CPUOverload);
|
||||
[self assertLoggedOneWarningMessage];
|
||||
}
|
||||
|
||||
- (void) testLogIfRingBufferError_Fetch_errorTooMuch {
|
||||
// Set a test-only flag that keeps it from calling abort() after logging the error when the
|
||||
// tests are compiled with the debug configuration.
|
||||
logger->mContinueOnErrorLogged = true;
|
||||
|
||||
logger->LogIfRingBufferError_Fetch(kCARingBufferError_TooMuch);
|
||||
[self assertLoggedOneErrorMessage];
|
||||
}
|
||||
|
||||
- (void) testLogIfRingBufferError_Store_noError {
|
||||
logger->LogIfRingBufferError_Store(kCARingBufferError_OK);
|
||||
[self assertLoggedNoMessages];
|
||||
}
|
||||
|
||||
- (void) testLogIfRingBufferError_Store_errorCPUOverload {
|
||||
logger->LogIfRingBufferError_Store(kCARingBufferError_CPUOverload);
|
||||
[self assertLoggedOneWarningMessage];
|
||||
}
|
||||
|
||||
- (void) testLogIfRingBufferError_Store_errorTooMuch {
|
||||
// Set a test-only flag that keeps it from calling abort() after logging the error when the
|
||||
// tests are compiled with the debug configuration.
|
||||
logger->mContinueOnErrorLogged = true;
|
||||
|
||||
logger->LogIfRingBufferError_Store(kCARingBufferError_TooMuch);
|
||||
[self assertLoggedOneErrorMessage];
|
||||
}
|
||||
|
||||
- (void) waitForLoggingThread {
|
||||
// Wait for it to finish logging the messages.
|
||||
bool noMessagesLeft = logger->WaitUntilLoggerThreadIdle();
|
||||
XCTAssert(noMessagesLeft);
|
||||
}
|
||||
|
||||
- (void) assertLoggedNoMessages {
|
||||
[self waitForLoggingThread];
|
||||
XCTAssertEqual(0, logger->mNumDebugMessagesLogged);
|
||||
XCTAssertEqual(0, logger->mNumWarningMessagesLogged);
|
||||
XCTAssertEqual(0, logger->mNumErrorMessagesLogged);
|
||||
}
|
||||
|
||||
- (void) assertLoggedOneDebugMessage {
|
||||
[self waitForLoggingThread];
|
||||
XCTAssertEqual(1, logger->mNumDebugMessagesLogged);
|
||||
XCTAssertEqual(0, logger->mNumWarningMessagesLogged);
|
||||
XCTAssertEqual(0, logger->mNumErrorMessagesLogged);
|
||||
}
|
||||
|
||||
- (void) assertLoggedOneWarningMessage {
|
||||
[self waitForLoggingThread];
|
||||
XCTAssertEqual(0, logger->mNumDebugMessagesLogged);
|
||||
XCTAssertEqual(1, logger->mNumWarningMessagesLogged);
|
||||
XCTAssertEqual(0, logger->mNumErrorMessagesLogged);
|
||||
}
|
||||
|
||||
- (void) assertLoggedOneErrorMessage {
|
||||
[self waitForLoggingThread];
|
||||
XCTAssertEqual(0, logger->mNumDebugMessagesLogged);
|
||||
XCTAssertEqual(0, logger->mNumWarningMessagesLogged);
|
||||
XCTAssertEqual(1, logger->mNumErrorMessagesLogged);
|
||||
}
|
||||
|
||||
@end
|
||||
|
106
BGMApp/BGMAppTests/UnitTests/BGMPlayThroughTests.mm
Normal file
106
BGMApp/BGMAppTests/UnitTests/BGMPlayThroughTests.mm
Normal file
|
@ -0,0 +1,106 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// BGMPlayThroughTests.mm
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Unit Include
|
||||
#import "BGMPlayThrough.h"
|
||||
|
||||
// Local Includes
|
||||
#import "MockAudioDevice.h"
|
||||
#import "MockAudioObjects.h"
|
||||
|
||||
// BGM Includes
|
||||
#import "BGM_Types.h"
|
||||
#import "BGMAudioDevice.h"
|
||||
|
||||
// STL Includes
|
||||
#import <memory>
|
||||
|
||||
// System Includes
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
|
||||
@interface BGMPlayThroughTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation BGMPlayThroughTests {
|
||||
BGMAudioDevice inputDevice;
|
||||
BGMAudioDevice outputDevice;
|
||||
|
||||
// The unit tests use mock implementations of CAHALAudioObject and CAHALAudioDevice, which are
|
||||
// the superclasses of BGMAudioDevice. When BGMPlayThrough calls methods on inputDevice or
|
||||
// outputDevice, some of them will update these objects.
|
||||
std::shared_ptr<MockAudioDevice> mockInputDevice;
|
||||
std::shared_ptr<MockAudioDevice> mockOutputDevice;
|
||||
}
|
||||
|
||||
- (void) setUp {
|
||||
[super setUp];
|
||||
|
||||
// Set up the mocks.
|
||||
mockInputDevice = MockAudioObjects::CreateMockDevice(kBGMDeviceUID);
|
||||
mockOutputDevice = MockAudioObjects::CreateMockDevice("Mock Output Device");
|
||||
|
||||
inputDevice = BGMAudioDevice(mockInputDevice->GetObjectID());
|
||||
outputDevice = BGMAudioDevice(mockOutputDevice->GetObjectID());
|
||||
}
|
||||
|
||||
- (void) tearDown {
|
||||
[super tearDown];
|
||||
MockAudioObjects::DestroyMocks();
|
||||
}
|
||||
|
||||
- (void) testActivate {
|
||||
// Set the mock output device's sample rate and IO buffer size.
|
||||
outputDevice.SetNominalSampleRate(12345.0);
|
||||
outputDevice.SetIOBufferSize(123);
|
||||
|
||||
// Create an instance and activate it.
|
||||
BGMPlayThrough playThrough(inputDevice, outputDevice);
|
||||
playThrough.Activate();
|
||||
|
||||
// It should set the input device's sample rate and IO buffer size to match the output device.
|
||||
XCTAssertEqual(12345.0, inputDevice.GetNominalSampleRate());
|
||||
XCTAssertEqual(123, inputDevice.GetIOBufferSize());
|
||||
|
||||
// It should add the property listeners it needs.
|
||||
std::set<AudioObjectPropertySelector> expectedProperties {
|
||||
kAudioDevicePropertyDeviceIsRunning,
|
||||
kAudioDeviceProcessorOverload,
|
||||
kAudioDeviceCustomPropertyDeviceIsRunningSomewhereOtherThanBGMApp
|
||||
};
|
||||
|
||||
XCTAssertEqual(expectedProperties, mockInputDevice->mPropertiesWithListeners);
|
||||
}
|
||||
|
||||
- (void) testDeactivate {
|
||||
BGMPlayThrough playThrough(inputDevice, outputDevice);
|
||||
|
||||
playThrough.Activate();
|
||||
playThrough.Deactivate();
|
||||
|
||||
// It should remove the property listeners added by Activate.
|
||||
XCTAssert(mockInputDevice->mPropertiesWithListeners.empty());
|
||||
}
|
||||
|
||||
@end
|
||||
|
61
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioDevice.cpp
Normal file
61
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioDevice.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// MockAudioDevice.cpp
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "MockAudioDevice.h"
|
||||
|
||||
// BGM Includes
|
||||
#include "BGM_Types.h"
|
||||
|
||||
// STL Includes
|
||||
#include <functional>
|
||||
|
||||
|
||||
MockAudioDevice::MockAudioDevice(const std::string& inUID)
|
||||
:
|
||||
mUID(inUID),
|
||||
mNominalSampleRate(44100.0),
|
||||
mIOBufferSize(512),
|
||||
MockAudioObject(static_cast<AudioObjectID>(std::hash<std::string>{}(inUID)))
|
||||
{
|
||||
}
|
||||
|
||||
CACFString MockAudioDevice::GetPlayerBundleID() const
|
||||
{
|
||||
if(mUID != kBGMDeviceUID)
|
||||
{
|
||||
throw "Only BGMDevice has kAudioDeviceCustomPropertyMusicPlayerBundleID";
|
||||
}
|
||||
|
||||
return mPlayerBundleID;
|
||||
}
|
||||
|
||||
void MockAudioDevice::SetPlayerBundleID(const CACFString& inPlayerBundleID)
|
||||
{
|
||||
if(mUID != kBGMDeviceUID)
|
||||
{
|
||||
throw "Only BGMDevice has kAudioDeviceCustomPropertyMusicPlayerBundleID";
|
||||
}
|
||||
|
||||
mPlayerBundleID = inPlayerBundleID;
|
||||
}
|
||||
|
73
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioDevice.h
Normal file
73
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioDevice.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// MockAudioObject.h
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
#ifndef BGMAppUnitTests__MockAudioDevice
|
||||
#define BGMAppUnitTests__MockAudioDevice
|
||||
|
||||
// Superclass Includes
|
||||
#include "MockAudioObject.h"
|
||||
|
||||
// STL Includes
|
||||
#include <string>
|
||||
|
||||
|
||||
/*!
|
||||
* A mock audio device in our mock CoreAudio HAL. In the HAL's API class hierarchy, the base class
|
||||
* for audio devices, kAudioDeviceClassID, is the audio objects class, kAudioObjectClassID.
|
||||
*
|
||||
* The unit tests generally use instances of this class to verify the HAL is being queried correctly
|
||||
* and to control the responses that the code they're testing will receive from the mock HAL.
|
||||
*/
|
||||
class MockAudioDevice
|
||||
:
|
||||
public MockAudioObject
|
||||
{
|
||||
|
||||
public:
|
||||
MockAudioDevice(const std::string& inUID);
|
||||
|
||||
/*!
|
||||
* @return This device's music player bundle ID property.
|
||||
* @throws If this device isn't a mock of BGMDevice.
|
||||
*/
|
||||
CACFString GetPlayerBundleID() const;
|
||||
/*!
|
||||
* Set this device's music player bundle ID property.
|
||||
* @throws If this device isn't a mock of BGMDevice.
|
||||
*/
|
||||
void SetPlayerBundleID(const CACFString& inPlayerBundleID);
|
||||
|
||||
/*!
|
||||
* The device's UID. The UID is a persistent token used to identify a particular audio device
|
||||
* across boot sessions.
|
||||
*/
|
||||
const std::string mUID;
|
||||
Float64 mNominalSampleRate;
|
||||
UInt32 mIOBufferSize;
|
||||
|
||||
private:
|
||||
CACFString mPlayerBundleID { "" };
|
||||
|
||||
};
|
||||
|
||||
#endif /* BGMAppUnitTests__MockAudioDevice */
|
||||
|
37
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObject.cpp
Normal file
37
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObject.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// MockAudioObject.cpp
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "MockAudioObject.h"
|
||||
|
||||
|
||||
MockAudioObject::MockAudioObject(AudioObjectID inAudioObjectID)
|
||||
:
|
||||
mAudioObjectID(inAudioObjectID)
|
||||
{
|
||||
}
|
||||
|
||||
AudioObjectID MockAudioObject::GetObjectID() const
|
||||
{
|
||||
return mAudioObjectID;
|
||||
}
|
||||
|
61
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObject.h
Normal file
61
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObject.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// MockAudioObject.h
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
#ifndef BGMAppUnitTests__MockAudioObject
|
||||
#define BGMAppUnitTests__MockAudioObject
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CACFString.h"
|
||||
|
||||
// STL Includes
|
||||
#include <set>
|
||||
|
||||
// System Includes
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
|
||||
|
||||
/*!
|
||||
* The base class for mock audio objects in our mock CoreAudio HAL. Maps to kAudioObjectClassID
|
||||
* (AudioHardwareBase.h) in the HAL's API class hierarchy.
|
||||
*/
|
||||
class MockAudioObject
|
||||
{
|
||||
|
||||
public:
|
||||
MockAudioObject(AudioObjectID inAudioObjectID);
|
||||
virtual ~MockAudioObject() = default;
|
||||
|
||||
AudioObjectID GetObjectID() const;
|
||||
|
||||
/*!
|
||||
* The properties that callers have added listeners for (and haven't since removed). See
|
||||
* CAHALAudioObject::AddPropertyListener and CAHALAudioObject::RemovePropertyListener.
|
||||
*/
|
||||
std::set<AudioObjectPropertySelector> mPropertiesWithListeners;
|
||||
|
||||
private:
|
||||
AudioObjectID mAudioObjectID;
|
||||
|
||||
};
|
||||
|
||||
#endif /* BGMAppUnitTests__MockAudioObject */
|
||||
|
123
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObjects.cpp
Normal file
123
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObjects.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// MockAudioObjects.cpp
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "MockAudioObjects.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CACFString.h"
|
||||
|
||||
|
||||
// static
|
||||
MockAudioObjects::MockDeviceMap MockAudioObjects::sDevices;
|
||||
|
||||
// static
|
||||
MockAudioObjects::MockDeviceMapByUID MockAudioObjects::sDevicesByUID;
|
||||
|
||||
// static
|
||||
std::shared_ptr<MockAudioDevice> MockAudioObjects::CreateMockDevice(const std::string& inUID)
|
||||
{
|
||||
std::shared_ptr<MockAudioDevice> mockDevice = std::make_shared<MockAudioDevice>(inUID);
|
||||
|
||||
sDevices.insert(MockDeviceMap::value_type(mockDevice->GetObjectID(), mockDevice));
|
||||
sDevicesByUID.insert(MockDeviceMapByUID::value_type(inUID, mockDevice));
|
||||
|
||||
return mockDevice;
|
||||
}
|
||||
|
||||
// static
|
||||
void MockAudioObjects::DestroyMocks()
|
||||
{
|
||||
sDevices.clear();
|
||||
}
|
||||
|
||||
// static
|
||||
std::shared_ptr<MockAudioObject> MockAudioObjects::GetAudioObject(AudioObjectID inAudioObjectID)
|
||||
{
|
||||
auto device = GetAudioDeviceOrNull(inAudioObjectID);
|
||||
|
||||
if(device)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
|
||||
// Devices are the only audio objects we currently mock.
|
||||
|
||||
// Tests have to create mocks for all of the audio objects they expect the code they test to
|
||||
// access. They should fail if it accesses any others.
|
||||
throw "Mock audio object not found.";
|
||||
}
|
||||
|
||||
// static
|
||||
std::shared_ptr<MockAudioDevice> MockAudioObjects::GetAudioDevice(AudioObjectID inAudioObjectID)
|
||||
{
|
||||
auto device = GetAudioDeviceOrNull(inAudioObjectID);
|
||||
|
||||
if(device)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
|
||||
// Tests have to create mocks for all of the audio devices they expect the code they test to
|
||||
// access. They should fail if it accesses any others.
|
||||
throw "Mock audio device not found.";
|
||||
}
|
||||
|
||||
// static
|
||||
std::shared_ptr<MockAudioDevice> MockAudioObjects::GetAudioDevice(CFStringRef inUID)
|
||||
{
|
||||
// Convert inUID to a std::string.
|
||||
UInt32 uidCStringLen = CACFString::GetStringByteLength(inUID) + 1;
|
||||
char uidCString[uidCStringLen];
|
||||
CACFString::GetCString(inUID, uidCString, uidCStringLen);
|
||||
std::string uid = std::string(uidCString);
|
||||
|
||||
return GetAudioDevice(uid);
|
||||
}
|
||||
|
||||
// static
|
||||
std::shared_ptr<MockAudioDevice> MockAudioObjects::GetAudioDevice(const std::string& inUID)
|
||||
{
|
||||
auto device = sDevicesByUID.find(inUID);
|
||||
|
||||
if(device != sDevicesByUID.end())
|
||||
{
|
||||
return device->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
std::shared_ptr<MockAudioDevice>
|
||||
MockAudioObjects::GetAudioDeviceOrNull(AudioObjectID inAudioObjectID)
|
||||
{
|
||||
auto device = sDevices.find(inAudioObjectID);
|
||||
|
||||
if(device != sDevices.end())
|
||||
{
|
||||
return device->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
90
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObjects.h
Normal file
90
BGMApp/BGMAppTests/UnitTests/Mocks/MockAudioObjects.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// MockAudioObjects.h
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
#ifndef BGMAppUnitTests__MockAudioObjects
|
||||
#define BGMAppUnitTests__MockAudioObjects
|
||||
|
||||
// Local Includes
|
||||
#include "MockAudioObject.h"
|
||||
#include "MockAudioDevice.h"
|
||||
|
||||
// STL Includes
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// System Includes
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
|
||||
|
||||
class MockAudioObjects
|
||||
{
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Create a mock audio device in the mock CoreAudio HAL.
|
||||
*
|
||||
* The mock device will then be accessible using GetAudioObject and GetAudioDevice. The
|
||||
* Mock_CAHAL* implementations will access the mock device when they query the mock HAL.
|
||||
*
|
||||
* Unit tests can check the mock device to verify the code they're testing has called the mocked
|
||||
* CAHAL classes correctly. They can also modify the mock device to control the Mock_CAHAL*
|
||||
* implementations, e.g. to have CAHALAudioDevice::IsAlive return false so the test can cover
|
||||
* the case where a device is being removed from the system.
|
||||
*
|
||||
* @param inUID The UID string to give the device. The UID is a persistent token used to
|
||||
* identify a particular audio device across boot sessions.
|
||||
* @return The mock device.
|
||||
*/
|
||||
static std::shared_ptr<MockAudioDevice> CreateMockDevice(const std::string& inUID);
|
||||
|
||||
/*!
|
||||
* Remove all mock audio objects from the mock HAL. (Currently, mock devices are the only mock
|
||||
* objects that can be created.)
|
||||
*/
|
||||
static void DestroyMocks();
|
||||
|
||||
/*! Get a mock audio object by its ID. */
|
||||
static std::shared_ptr<MockAudioObject> GetAudioObject(AudioObjectID inAudioObjectID);
|
||||
|
||||
/*! Get a mock audio device by its ID. */
|
||||
static std::shared_ptr<MockAudioDevice> GetAudioDevice(AudioObjectID inAudioDeviceID);
|
||||
/*! Get a mock audio device by its UID. */
|
||||
static std::shared_ptr<MockAudioDevice> GetAudioDevice(const std::string& inUID);
|
||||
/*! Get a mock audio device by its UID. */
|
||||
static std::shared_ptr<MockAudioDevice> GetAudioDevice(CFStringRef inUID);
|
||||
|
||||
private:
|
||||
typedef std::map<AudioObjectID, std::shared_ptr<MockAudioDevice>> MockDeviceMap;
|
||||
typedef std::map<std::string, std::shared_ptr<MockAudioDevice>> MockDeviceMapByUID;
|
||||
|
||||
static std::shared_ptr<MockAudioDevice> GetAudioDeviceOrNull(AudioObjectID inAudioDeviceID);
|
||||
|
||||
/*! Maps IDs to mocked audio devices. */
|
||||
static MockDeviceMap sDevices;
|
||||
/*! Maps UIDs (ID strings) to mocked audio devices. */
|
||||
static MockDeviceMapByUID sDevicesByUID;
|
||||
|
||||
};
|
||||
|
||||
#endif /* BGMAppUnitTests__MockAudioObjects */
|
||||
|
691
BGMApp/BGMAppTests/UnitTests/Mocks/Mock_CAHALAudioDevice.cpp
Normal file
691
BGMApp/BGMAppTests/UnitTests/Mocks/Mock_CAHALAudioDevice.cpp
Normal file
|
@ -0,0 +1,691 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// Mock_CAHALAudioDevice.cpp
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "CAHALAudioDevice.h"
|
||||
|
||||
// Local Includes
|
||||
#include "MockAudioDevice.h"
|
||||
#include "MockAudioObjects.h"
|
||||
|
||||
// BGM Includes
|
||||
#include "BGM_Types.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CACFString.h"
|
||||
#include "CAHALAudioSystemObject.h"
|
||||
#include "CAPropertyAddress.h"
|
||||
|
||||
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
CAHALAudioDevice::CAHALAudioDevice(AudioObjectID inObjectID)
|
||||
:
|
||||
CAHALAudioObject(inObjectID)
|
||||
{
|
||||
}
|
||||
|
||||
CAHALAudioDevice::CAHALAudioDevice(CFStringRef inUID)
|
||||
:
|
||||
CAHALAudioObject(CAHALAudioSystemObject().GetAudioDeviceForUID(inUID))
|
||||
{
|
||||
}
|
||||
|
||||
CAHALAudioDevice::~CAHALAudioDevice()
|
||||
{
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetCurrentVirtualFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const
|
||||
{
|
||||
ioNumberStreams = 1;
|
||||
CAPropertyAddress theAddress(kAudioStreamPropertyVirtualFormat);
|
||||
UInt32 theSize = sizeof(AudioStreamBasicDescription);
|
||||
GetPropertyData(theAddress, 0, NULL, theSize, outFormats);
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetIOBufferSize() const
|
||||
{
|
||||
return MockAudioObjects::GetAudioDevice(GetObjectID())->mIOBufferSize;
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetIOBufferSize(UInt32 inBufferSize)
|
||||
{
|
||||
MockAudioObjects::GetAudioDevice(GetObjectID())->mIOBufferSize = inBufferSize;
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::IsAlive() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AudioDeviceIOProcID CAHALAudioDevice::CreateIOProcID(AudioDeviceIOProc inIOProc, void* inClientData)
|
||||
{
|
||||
return reinterpret_cast<AudioDeviceIOProcID>(0x99990000);
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::DestroyIOProcID(AudioDeviceIOProcID inIOProcID)
|
||||
{
|
||||
}
|
||||
|
||||
Float64 CAHALAudioDevice::GetNominalSampleRate() const
|
||||
{
|
||||
return MockAudioObjects::GetAudioDevice(GetObjectID())->mNominalSampleRate;
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetNominalSampleRate(Float64 inSampleRate)
|
||||
{
|
||||
MockAudioObjects::GetAudioDevice(GetObjectID())->mNominalSampleRate = inSampleRate;
|
||||
}
|
||||
|
||||
CFStringRef CAHALAudioDevice::CopyDeviceUID() const
|
||||
{
|
||||
std::string uid = MockAudioObjects::GetAudioDevice(GetObjectID())->mUID;
|
||||
return CACFString(uid.c_str()).CopyCFString();
|
||||
}
|
||||
|
||||
#pragma mark Unimplemented Methods
|
||||
|
||||
bool CAHALAudioDevice::HasModelUID() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
CFStringRef CAHALAudioDevice::CopyModelUID() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
CFStringRef CAHALAudioDevice::CopyConfigurationApplicationBundleID() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
CFURLRef CAHALAudioDevice::CopyIconLocation() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetTransportType() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::CanBeDefaultDevice(bool inIsInput, bool inIsSystem) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasDevicePlugInStatus() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
OSStatus CAHALAudioDevice::GetDevicePlugInStatus() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::IsHidden() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
pid_t CAHALAudioDevice::GetHogModeOwner() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::IsHogModeSettable() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::TakeHogMode()
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::ReleaseHogMode()
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasPreferredStereoChannels(bool inIsInput) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetPreferredStereoChannels(bool inIsInput, UInt32& outLeft, UInt32& outRight) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetPreferredStereoChannels(bool inIsInput, UInt32 inLeft, UInt32 inRight)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasPreferredChannelLayout(bool inIsInput) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetPreferredChannelLayout(bool inIsInput, AudioChannelLayout& outChannelLayout) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetPreferredStereoChannels(bool inIsInput, AudioChannelLayout& inChannelLayout)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetNumberRelatedAudioDevices() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetRelatedAudioDevices(UInt32& ioNumberRelatedDevices, AudioObjectID* outRelatedDevices) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
AudioObjectID CAHALAudioDevice::GetRelatedAudioDeviceByIndex(UInt32 inIndex) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetNumberStreams(bool inIsInput) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetStreams(bool inIsInput, UInt32& ioNumberStreams, AudioObjectID* outStreamList) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
AudioObjectID CAHALAudioDevice::GetStreamByIndex(bool inIsInput, UInt32 inIndex) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetTotalNumberChannels(bool inIsInput) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetCurrentPhysicalFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::IsRunning() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::IsRunningSomewhere() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetLatency(bool inIsInput) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetSafetyOffset(bool inIsInput) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasClockDomain() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetClockDomain() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float64 CAHALAudioDevice::GetActualSampleRate() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetNumberAvailableNominalSampleRateRanges() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetAvailableNominalSampleRateRanges(UInt32& ioNumberRanges, AudioValueRange* outRanges) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetAvailableNominalSampleRateRangeByIndex(UInt32 inIndex, Float64& outMinimum, Float64& outMaximum) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::IsValidNominalSampleRate(Float64 inSampleRate) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::IsIOBufferSizeSettable() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::UsesVariableIOBufferSizes() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetMaximumVariableIOBufferSize() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasIOBufferSizeRange() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetIOBufferSizeRange(UInt32& outMinimum, UInt32& outMaximum) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::StartIOProc(AudioDeviceIOProcID inIOProcID)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::StartIOProcAtTime(AudioDeviceIOProcID inIOProcID, AudioTimeStamp& ioStartTime, bool inIsInput, bool inIgnoreHardware)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::StopIOProc(AudioDeviceIOProcID inIOProcID)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, bool* outStreamUsage) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, const bool* inStreamUsage)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetIOCycleUsage() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetIOCycleUsage(Float32 inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetCurrentTime(AudioTimeStamp& outTime)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::TranslateTime(const AudioTimeStamp& inTime, AudioTimeStamp& outTime)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetNearestStartTime(AudioTimeStamp& ioTime, bool inIsInput, bool inIgnoreHardware)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::VolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasSubVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::SubVolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetSubVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetSubVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::MuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::GetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasSoloControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::SoloControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::GetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasStereoPanControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::StereoPanControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
Float32 CAHALAudioDevice::GetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetStereoPanControlChannels(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& outLeftChannel, UInt32& outRightChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasJackControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::GetJackControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasSubMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::SubMuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::GetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasiSubOwnerControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::iSubOwnerControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::GetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasDataSourceControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::DataSourceControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetCurrentDataSourceID(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetCurrentDataSourceByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetNumberAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberSources, UInt32* outSources) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetAvailableDataSourceByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
CFStringRef CAHALAudioDevice::CopyDataSourceNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasDataDestinationControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::DataDestinationControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetCurrentDataDestinationID(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetCurrentDataDestinationByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetNumberAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberDestinations, UInt32* outDestinations) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetAvailableDataDestinationByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
CFStringRef CAHALAudioDevice::CopyDataDestinationNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::HasClockSourceControl() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
bool CAHALAudioDevice::ClockSourceControlIsSettable() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetCurrentClockSourceID() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::SetCurrentClockSourceByID(UInt32 inID)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetNumberAvailableClockSources() const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioDevice::GetAvailableClockSources(UInt32& ioNumberSources, UInt32* outSources) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetAvailableClockSourceByIndex(UInt32 inIndex) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
CFStringRef CAHALAudioDevice::CopyClockSourceNameForID(UInt32 inID) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioDevice::GetClockSourceKindForID(UInt32 inID) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
|
@ -17,25 +17,24 @@
|
|||
// Mock_CAHALAudioObject.cpp
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2016 Kyle Neideck
|
||||
// Copyright © 2016, 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self include
|
||||
// Self Include
|
||||
#include "CAHALAudioObject.h"
|
||||
|
||||
// Local Includes
|
||||
#include "MockAudioObjects.h"
|
||||
|
||||
// BGM Includes
|
||||
#include "BGM_Types.h"
|
||||
|
||||
// System includes
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
// PublicUtility Includes
|
||||
#include "CACFString.h"
|
||||
|
||||
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
// The value of the music player bundle ID property. Tests should set this back to "" when they finish. (Has
|
||||
// to be static because we can't add to the real class's interface.)
|
||||
static CFStringRef playerBundleID = CFSTR("");
|
||||
|
||||
CAHALAudioObject::CAHALAudioObject(AudioObjectID inObjectID)
|
||||
:
|
||||
mObjectID(inObjectID)
|
||||
|
@ -53,21 +52,89 @@ AudioObjectID CAHALAudioObject::GetObjectID() const
|
|||
|
||||
void CAHALAudioObject::GetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32& ioDataSize, void* outData) const
|
||||
{
|
||||
if(inAddress.mSelector == kAudioDeviceCustomPropertyMusicPlayerBundleID)
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
*reinterpret_cast<CFStringRef*>(outData) = playerBundleID;
|
||||
case kAudioDeviceCustomPropertyMusicPlayerBundleID:
|
||||
*reinterpret_cast<CFStringRef*>(outData) =
|
||||
MockAudioObjects::GetAudioDevice(GetObjectID())->
|
||||
GetPlayerBundleID().CopyCFString();
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyStreams:
|
||||
reinterpret_cast<AudioObjectID*>(outData)[0] = 1;
|
||||
if(inAddress.mScope == kAudioObjectPropertyScopeGlobal)
|
||||
{
|
||||
reinterpret_cast<AudioObjectID*>(outData)[1] = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyBufferFrameSize:
|
||||
*reinterpret_cast<UInt32*>(outData) = 512;
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
*reinterpret_cast<UInt32*>(outData) = 1;
|
||||
break;
|
||||
|
||||
case kAudioStreamPropertyVirtualFormat:
|
||||
{
|
||||
AudioStreamBasicDescription* outASBD =
|
||||
reinterpret_cast<AudioStreamBasicDescription*>(outData);
|
||||
outASBD->mSampleRate = 44100.0;
|
||||
outASBD->mFormatID = kAudioFormatLinearPCM;
|
||||
outASBD->mFormatFlags =
|
||||
kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
|
||||
outASBD->mBytesPerPacket = 8;
|
||||
outASBD->mFramesPerPacket = 1;
|
||||
outASBD->mBytesPerFrame = 8;
|
||||
outASBD->mChannelsPerFrame = 2;
|
||||
outASBD->mBitsPerChannel = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
}
|
||||
|
||||
void CAHALAudioObject::SetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData)
|
||||
{
|
||||
if(inAddress.mSelector == kAudioDeviceCustomPropertyMusicPlayerBundleID)
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
playerBundleID = *reinterpret_cast<const CFStringRef*>(inData);
|
||||
case kAudioDeviceCustomPropertyMusicPlayerBundleID:
|
||||
MockAudioObjects::GetAudioDevice(GetObjectID())->SetPlayerBundleID(
|
||||
CACFString(*reinterpret_cast<const CFStringRef*>(inData), false));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Unimplemented methods
|
||||
UInt32 CAHALAudioObject::GetPropertyDataSize(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData) const
|
||||
{
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioDevicePropertyStreams:
|
||||
return (inAddress.mScope == kAudioObjectPropertyScopeGlobal ? 2 : 1) *
|
||||
sizeof(AudioObjectID);
|
||||
default:
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
}
|
||||
|
||||
void CAHALAudioObject::AddPropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData)
|
||||
{
|
||||
MockAudioObjects::GetAudioObject(GetObjectID())->
|
||||
mPropertiesWithListeners.insert(inAddress.mSelector);
|
||||
}
|
||||
|
||||
void CAHALAudioObject::RemovePropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData)
|
||||
{
|
||||
MockAudioObjects::GetAudioObject(GetObjectID())->
|
||||
mPropertiesWithListeners.erase(inAddress.mSelector);
|
||||
}
|
||||
|
||||
#pragma mark Unimplemented Methods
|
||||
|
||||
void CAHALAudioObject::SetObjectID(AudioObjectID inObjectID)
|
||||
{
|
||||
|
@ -144,18 +211,3 @@ bool CAHALAudioObject::IsPropertySettable(const AudioObjectPropertyAddress& inAd
|
|||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
UInt32 CAHALAudioObject::GetPropertyDataSize(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData) const
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioObject::AddPropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
||||
void CAHALAudioObject::RemovePropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData)
|
||||
{
|
||||
Throw(new CAException(kAudio_UnimplementedError));
|
||||
}
|
||||
|
|
@ -17,12 +17,18 @@
|
|||
// Mock_CAHALAudioSystemObject.cpp
|
||||
// BGMAppUnitTests
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
// Copyright © 2017, 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self include
|
||||
#include "CAHALAudioSystemObject.h"
|
||||
|
||||
// BGM Includes
|
||||
#include "BGM_Types.h"
|
||||
|
||||
// Local Includes
|
||||
#include "MockAudioObjects.h"
|
||||
|
||||
|
||||
CAHALAudioSystemObject::CAHALAudioSystemObject()
|
||||
:
|
||||
|
@ -36,19 +42,17 @@ CAHALAudioSystemObject::~CAHALAudioSystemObject()
|
|||
|
||||
AudioObjectID CAHALAudioSystemObject::GetAudioDeviceForUID(CFStringRef inUID) const
|
||||
{
|
||||
AudioObjectID id = kAudioObjectUnknown;
|
||||
auto device = MockAudioObjects::GetAudioDevice(inUID);
|
||||
|
||||
// Generate a deterministic and random-ish ID from the UID string. Ideally we would ensure the
|
||||
// IDs are unique, but this is probably fine.
|
||||
for(int i = 0; i < CFStringGetLength(inUID); i++)
|
||||
if(device)
|
||||
{
|
||||
id += 37 * CFStringGetCharacterAtIndex(inUID, i);
|
||||
return device->GetObjectID();
|
||||
}
|
||||
|
||||
return id;
|
||||
return kAudioObjectUnknown;
|
||||
}
|
||||
|
||||
#pragma mark Unimplemented methods
|
||||
#pragma mark Unimplemented Methods
|
||||
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016-2019 Background Music contributors</string>
|
||||
<string>Copyright © 2016-2020 Background Music contributors</string>
|
||||
<key>XPCService</key>
|
||||
<dict>
|
||||
<key>ServiceType</key>
|
||||
|
|
50
BGMApp/PublicUtility/BGMDebugLogging.c
Normal file
50
BGMApp/PublicUtility/BGMDebugLogging.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// BGMDebugLogging.c
|
||||
// PublicUtility
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "BGMDebugLogging.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
// It's probably not ideal to use a global variable for this, but it's a lot easier.
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
// Enable debug logging by default in debug builds.
|
||||
int gDebugLoggingIsEnabled = 1;
|
||||
#else
|
||||
int gDebugLoggingIsEnabled = 0;
|
||||
#endif
|
||||
|
||||
// We don't bother synchronising accesses of gDebugLoggingIsEnabled because it isn't really
|
||||
// necessary and would complicate code that accesses it on realtime threads.
|
||||
int BGMDebugLoggingIsEnabled()
|
||||
{
|
||||
return gDebugLoggingIsEnabled;
|
||||
}
|
||||
|
||||
void BGMSetDebugLoggingEnabled(int inEnabled)
|
||||
{
|
||||
gDebugLoggingIsEnabled = inEnabled;
|
||||
}
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
63
BGMApp/PublicUtility/BGMDebugLogging.h
Normal file
63
BGMApp/PublicUtility/BGMDebugLogging.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// BGMDebugLogging.h
|
||||
// PublicUtility
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
// Functions to globally enable/disable debug logging, i.e. more detailed logging to help diagnose
|
||||
// bugs. If debug logging is enabled, the DebugMsg macro from CADebugMacros.h (and possibly others)
|
||||
// will log messages. If not, it won't do anything.
|
||||
//
|
||||
// If the preprocessor macro CoreAudio_UseSysLog is true, which is currently the case for all build
|
||||
// variants (see BGMApp/BGMApp.xcodeproj/project.pbxproj and
|
||||
// BGMDriver/BGMDriver.xcodeproj/project.pbxproj), those messages will be logged using syslog and
|
||||
// can be read using Console.app. Try searching for "background music", "bgm" or "coreaudiod".
|
||||
//
|
||||
// Debug logging is enabled by default in debug builds, but in release builds you have to enable it
|
||||
// by option-clicking the status bar icon and then checking the Debug Logging menu item. Enabling
|
||||
// debug logging probably won't cause glitches, but we don't try to guarantee that and it's not
|
||||
// well tested.
|
||||
//
|
||||
|
||||
#ifndef PublicUtility__BGMDebugLogging
|
||||
#define PublicUtility__BGMDebugLogging
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
/*!
|
||||
* @return Non-zero if debug logging is globally enabled. (Probably -- it's not synchronised.)
|
||||
* Real-time safe.
|
||||
*/
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
int BGMDebugLoggingIsEnabled(void);
|
||||
|
||||
/*!
|
||||
* @param inEnabled Non-zero to globally enable debug logging, zero to disable it. The change might
|
||||
* not be visible to other threads immediately.
|
||||
*/
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
void BGMSetDebugLoggingEnabled(int inEnabled);
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* PublicUtility__BGMDebugLogging */
|
||||
|
|
@ -1,3 +1,28 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// CADebugMacros.h
|
||||
// PublicUtility
|
||||
//
|
||||
// Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
// Copyright © 2016, 2020 Kyle Neideck
|
||||
//
|
||||
// Original license header follows.
|
||||
//
|
||||
|
||||
/*
|
||||
File: CADebugMacros.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
|
@ -57,6 +82,8 @@
|
|||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
//=============================================================================
|
||||
// CADebugMacros
|
||||
//=============================================================================
|
||||
|
@ -92,42 +119,41 @@
|
|||
|
||||
#pragma mark Basic Definitions
|
||||
|
||||
// basic debugging print routines
|
||||
#if TARGET_OS_MAC && !TARGET_API_MAC_CARBON
|
||||
extern void DebugStr(const unsigned char* debuggerMsg);
|
||||
#define DebugMessage(msg) DebugStr("\p"msg)
|
||||
#define DebugMessageN1(msg, N1)
|
||||
#define DebugMessageN2(msg, N1, N2)
|
||||
#define DebugMessageN3(msg, N1, N2, N3)
|
||||
#else
|
||||
#if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile)
|
||||
#define FlushRtn ,fflush(DebugPrintfFile)
|
||||
#else
|
||||
#define FlushRtn
|
||||
#endif
|
||||
|
||||
#if CoreAudio_ThreadStampMessages
|
||||
#include <pthread.h>
|
||||
#include "CAHostTimeBase.h"
|
||||
#if TARGET_RT_64_BIT
|
||||
#define DebugPrintfThreadIDFormat "%16p"
|
||||
#else
|
||||
#define DebugPrintfThreadIDFormat "%8p"
|
||||
#endif
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " DebugPrintfThreadIDFormat " " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), ## __VA_ARGS__) FlushRtn
|
||||
#elif CoreAudio_TimeStampMessages
|
||||
#include "CAHostTimeBase.h"
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), ## __VA_ARGS__) FlushRtn
|
||||
#else
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf(inFormat, ## __VA_ARGS__) FlushRtn
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
// can be used to break into debugger immediately, also see CADebugger
|
||||
#define BusError() { long* p=NULL; *p=0; }
|
||||
|
||||
// basic debugging print routines
|
||||
#if TARGET_OS_MAC && !TARGET_API_MAC_CARBON
|
||||
extern void DebugStr(const unsigned char* debuggerMsg);
|
||||
#define DebugMessage(msg) DebugStr("\p"msg)
|
||||
#define DebugMessageN1(msg, N1)
|
||||
#define DebugMessageN2(msg, N1, N2)
|
||||
#define DebugMessageN3(msg, N1, N2, N3)
|
||||
#else
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
#if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile)
|
||||
#define FlushRtn ,fflush(DebugPrintfFile)
|
||||
#else
|
||||
#define FlushRtn
|
||||
#endif
|
||||
|
||||
#if CoreAudio_ThreadStampMessages
|
||||
#include <pthread.h>
|
||||
#include "CAHostTimeBase.h"
|
||||
#if TARGET_RT_64_BIT
|
||||
#define DebugPrintfThreadIDFormat "%16p"
|
||||
#else
|
||||
#define DebugPrintfThreadIDFormat "%8p"
|
||||
#endif
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " DebugPrintfThreadIDFormat " " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), ## __VA_ARGS__) FlushRtn
|
||||
#elif CoreAudio_TimeStampMessages
|
||||
#include "CAHostTimeBase.h"
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), ## __VA_ARGS__) FlushRtn
|
||||
#else
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf(inFormat, ## __VA_ARGS__) FlushRtn
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void DebugPrint(const char *fmt, ...); // can be used like printf
|
||||
#ifndef DEBUGPRINT
|
||||
#define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h)
|
||||
|
@ -172,7 +198,7 @@
|
|||
#endif
|
||||
|
||||
#else
|
||||
#define DebugMsg(inFormat, ...)
|
||||
|
||||
#ifndef DEBUGPRINT
|
||||
#define DEBUGPRINT(msg)
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,28 @@
|
|||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// CADebugPrintf.cpp
|
||||
// PublicUtility
|
||||
//
|
||||
// Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
// Original license header follows.
|
||||
//
|
||||
|
||||
/*
|
||||
File: CADebugPrintf.cpp
|
||||
Abstract: CADebugPrintf.h
|
||||
|
@ -51,39 +76,39 @@
|
|||
// Self Include
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <Windows.h>
|
||||
extern "C"
|
||||
int CAWin32DebugPrintf(char* inFormat, ...)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <Windows.h>
|
||||
extern "C"
|
||||
int CAWin32DebugPrintf(char* inFormat, ...)
|
||||
{
|
||||
if (BGMDebugLoggingIsEnabled()) {
|
||||
char theMessage[1024];
|
||||
va_list theArguments;
|
||||
va_start(theArguments, inFormat);
|
||||
_vsnprintf(theMessage, 1024, inFormat, theArguments);
|
||||
va_end(theArguments);
|
||||
OutputDebugString(theMessage);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CoreAudio_UseSideFile)
|
||||
#include <unistd.h>
|
||||
FILE* sDebugPrintfSideFile = NULL;
|
||||
extern "C"
|
||||
void OpenDebugPrintfSideFile()
|
||||
{
|
||||
if(sDebugPrintfSideFile == NULL)
|
||||
{
|
||||
char theFileName[1024];
|
||||
snprintf(theFileName, sizeof(theFileName), CoreAudio_UseSideFile, getpid());
|
||||
sDebugPrintfSideFile = fopen(theFileName, "a+");
|
||||
DebugPrintfRtn(DebugPrintfFileComma "\n------------------------------\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CoreAudio_UseSideFile)
|
||||
#include <unistd.h>
|
||||
FILE* sDebugPrintfSideFile = NULL;
|
||||
extern "C"
|
||||
void OpenDebugPrintfSideFile()
|
||||
{
|
||||
if(sDebugPrintfSideFile == NULL)
|
||||
{
|
||||
char theFileName[1024];
|
||||
snprintf(theFileName, sizeof(theFileName), CoreAudio_UseSideFile, getpid());
|
||||
sDebugPrintfSideFile = fopen(theFileName, "a+");
|
||||
DebugPrintfRtn(DebugPrintfFileComma "\n------------------------------\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
#include "BGMDebugLogging.h"
|
||||
|
||||
//=============================================================================
|
||||
// Macros to redirect debugging output to various logging services
|
||||
//=============================================================================
|
||||
|
@ -64,52 +66,48 @@
|
|||
//#define CoreAudio_UseSysLog 1
|
||||
//#define CoreAudio_UseSideFile "/CoreAudio-%d.txt"
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#if TARGET_OS_WIN32
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
extern int CAWin32DebugPrintf(char* inFormat, ...);
|
||||
#define DebugPrintfRtn CAWin32DebugPrintf
|
||||
#define DebugPrintfFile
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma
|
||||
#else
|
||||
#if CoreAudio_UseSysLog
|
||||
#include <sys/syslog.h>
|
||||
#define DebugPrintfRtn syslog
|
||||
#define DebugPrintfFile LOG_NOTICE
|
||||
#define DebugPrintfLineEnding ""
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#elif defined(CoreAudio_UseSideFile)
|
||||
#include <stdio.h>
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
extern int CAWin32DebugPrintf(char* inFormat, ...);
|
||||
#define DebugPrintfRtn CAWin32DebugPrintf
|
||||
#define DebugPrintfFile
|
||||
void OpenDebugPrintfSideFile();
|
||||
extern FILE* sDebugPrintfSideFile;
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile ((sDebugPrintfSideFile != NULL) ? sDebugPrintfSideFile : stderr)
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#else
|
||||
#if CoreAudio_UseSysLog
|
||||
#include <sys/syslog.h>
|
||||
#define DebugPrintfRtn syslog
|
||||
#define DebugPrintfFile LOG_NOTICE
|
||||
#define DebugPrintfLineEnding ""
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#elif defined(CoreAudio_UseSideFile)
|
||||
#include <stdio.h>
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
void OpenDebugPrintfSideFile();
|
||||
extern FILE* sDebugPrintfSideFile;
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile ((sDebugPrintfSideFile != NULL) ? sDebugPrintfSideFile : stderr)
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile stderr
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile stderr
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#endif
|
||||
|
||||
#define DebugPrintf(inFormat, ...) DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DebugPrintfRtn
|
||||
#define DebugPrintfFile
|
||||
#define DebugPrintfLineEnding
|
||||
#define DebugPrintfFileComma
|
||||
#define DebugPrintf(inFormat, ...)
|
||||
#endif
|
||||
|
||||
#define DebugPrintf(inFormat, ...) \
|
||||
do { \
|
||||
if (BGMDebugLoggingIsEnabled()) { \
|
||||
DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -26,21 +26,12 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
enableAddressSanitizer = "YES"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1C8034D91BDD073B00668E00"
|
||||
BuildableName = "BGMDriverTests.xctest"
|
||||
BlueprintName = "BGMDriverTests"
|
||||
ReferencedContainer = "container:BGMDriver.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
enableUBSanitizer = "YES"
|
||||
codeCoverageEnabled = "YES"
|
||||
onlyGenerateCoverageForSpecifiedTargets = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
|
@ -50,15 +41,38 @@
|
|||
ReferencedContainer = "container:BGMDriver.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1CB8B3631BBBB78D000E2DD1"
|
||||
BuildableName = "Background Music Device.driver"
|
||||
BlueprintName = "Background Music Device"
|
||||
ReferencedContainer = "container:BGMDriver.xcodeproj">
|
||||
</BuildableReference>
|
||||
</CodeCoverageTargets>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES"
|
||||
testExecutionOrdering = "random">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1C8034D91BDD073B00668E00"
|
||||
BuildableName = "BGMDriverTests.xctest"
|
||||
BlueprintName = "BGMDriverTests"
|
||||
ReferencedContainer = "container:BGMDriver.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
debugAsWhichUser = "root"
|
||||
language = ""
|
||||
enableAddressSanitizer = "YES"
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
enableUBSanitizer = "YES"
|
||||
launchStyle = "1"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -85,8 +99,6 @@
|
|||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
|
|
@ -26,19 +26,22 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
enableAddressSanitizer = "YES"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
enableUBSanitizer = "YES"
|
||||
disableMainThreadChecker = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
enableAddressSanitizer = "YES"
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
enableUBSanitizer = "YES"
|
||||
disableMainThreadChecker = "YES"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -61,8 +64,6 @@
|
|||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
// Self Include
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
// Self Include
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
// BGM_Device.cpp
|
||||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
// Copyright © 2016, 2017, 2019 Kyle Neideck
|
||||
// Copyright © 2017 Andrew Tonner
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright © 2019 Gordon Childs
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_Device.cpp from Apple's SimpleAudioDriver Plug-In sample code. Also uses a few sections from Apple's
|
||||
// NullAudio.c sample code (found in the same sample project).
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
// BGM_Device.h
|
||||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright © 2016, 2017, 2019 Kyle Neideck
|
||||
// Copyright © 2019 Gordon Childs
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_Device.h from Apple's SimpleAudioDriver Plug-In sample code.
|
||||
// https://developer.apple.com/library/mac/samplecode/AudioDriverExamples
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_Object.cpp from Apple's SimpleAudioDriver Plug-In sample code.
|
||||
// https://developer.apple.com/library/mac/samplecode/AudioDriverExamples
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_Object.h from Apple's SimpleAudioDriver Plug-In sample code.
|
||||
// https://developer.apple.com/library/mac/samplecode/AudioDriverExamples
|
||||
|
@ -46,7 +46,7 @@
|
|||
//
|
||||
// This is the base class for objects managed by BGM_ObjectMap. It's only job is to ensure that
|
||||
// objects of this type have the proper external semantics for a reference counted object. This
|
||||
// means that the desctructor is protected so that these objects cannot be deleted directly. Also,
|
||||
// means that the destructor is protected so that these objects cannot be deleted directly. Also,
|
||||
// these objects many not make a copy of another object or be assigned from another object. Note
|
||||
// that the reference count of the object is tracked and owned by the BGM_ObjectMap.
|
||||
//
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_PlugIn.cpp from Apple's SimpleAudioDriver Plug-In sample code.
|
||||
// https://developer.apple.com/library/mac/samplecode/AudioDriverExamples
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_PlugIn.h from Apple's SimpleAudioDriver Plug-In sample code.
|
||||
// https://developer.apple.com/library/mac/samplecode/AudioDriverExamples
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_PlugIn.cpp from Apple's SimpleAudioDriver Plug-In sample code.
|
||||
// https://developer.apple.com/library/mac/samplecode/AudioDriverExamples
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
// Self Include
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
// Self Include
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
</array>
|
||||
</dict>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016-2019 Background Music contributors</string>
|
||||
<string>Copyright © 2016-2020 Background Music contributors</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
|
|
|
@ -205,7 +205,7 @@ Some are in listed in [TODO.md](/TODO.md).
|
|||
|
||||
## License
|
||||
|
||||
Copyright © 2016-2019 [Background Music contributors](https://github.com/kyleneideck/BackgroundMusic/graphs/contributors).
|
||||
Copyright © 2016-2020 [Background Music contributors](https://github.com/kyleneideck/BackgroundMusic/graphs/contributors).
|
||||
Licensed under [GPLv2](https://www.gnu.org/licenses/gpl-2.0.html), or any later version.
|
||||
|
||||
**Background Music** includes code from:
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// BGM_Utils.h
|
||||
// SharedSource
|
||||
//
|
||||
// Copyright © 2016-2018 Kyle Neideck
|
||||
// Copyright © 2016-2020 Kyle Neideck
|
||||
//
|
||||
|
||||
#ifndef SharedSource__BGM_Utils
|
||||
|
@ -41,13 +41,21 @@
|
|||
|
||||
#pragma mark Macros
|
||||
|
||||
// The Assert macro from CADebugMacros with support for format strings added.
|
||||
#define BGMAssert(inCondition, inMessage, ...) \
|
||||
if(!(inCondition)) \
|
||||
{ \
|
||||
DebugMsg(inMessage, ## __VA_ARGS__); \
|
||||
__ASSERT_STOP; \
|
||||
}
|
||||
// The Assert macro from CADebugMacros with support for format strings and line numbers added.
|
||||
#if DEBUG
|
||||
#define BGMAssert(inCondition, inMessage, ...) \
|
||||
if(!(inCondition)) \
|
||||
{ \
|
||||
DebugMsg("%s:%d:%s: " inMessage, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
## __VA_ARGS__); \
|
||||
__ASSERT_STOP; \
|
||||
}
|
||||
#else
|
||||
#define BGMAssert(inCondition, inMessage, ...)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#define BGMAssertNonNull(expression) \
|
||||
BGMAssertNonNull2((expression), #expression)
|
||||
|
|
Loading…
Reference in a new issue