diff options
author | Jonathan Marshall <jmarshall@xbmc.org> | 2013-12-30 12:44:48 +1300 |
---|---|---|
committer | Jonathan Marshall <jmarshall@xbmc.org> | 2014-02-22 09:04:47 +1300 |
commit | c13a3d4af22d5a2443fadaeeb4cd70cf2d8154e2 (patch) | |
tree | ea32a98ce6f618518b43dcf0a7c349e01c97c5c8 | |
parent | e585af6237e4f010b564daf04e1560e118fb0dc2 (diff) |
[ios/osx] adds Darwin sinks for ActiveAE and drop the CoreAudio engine.
38 files changed, 1697 insertions, 6765 deletions
diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj index 7c15e43fd9..c3e8eb2c0d 100644 --- a/XBMC.xcodeproj/project.pbxproj +++ b/XBMC.xcodeproj/project.pbxproj @@ -328,6 +328,11 @@ 7C89619213B6A16F003631FE /* GUIWindowScreensaverDim.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C89619013B6A16F003631FE /* GUIWindowScreensaverDim.cpp */; }; 7C8A14571154CB2600E5FCFA /* TextureCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8A14541154CB2600E5FCFA /* TextureCache.cpp */; }; 7C8A187D115B2A8200E5FCFA /* TextureDatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8A187A115B2A8200E5FCFA /* TextureDatabase.cpp */; }; + 7C8AE84E189DE3CD00C33786 /* CoreAudioChannelLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8AE849189DE3CD00C33786 /* CoreAudioChannelLayout.cpp */; }; + 7C8AE84F189DE3CD00C33786 /* CoreAudioDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8AE84A189DE3CD00C33786 /* CoreAudioDevice.cpp */; }; + 7C8AE850189DE3CD00C33786 /* CoreAudioHardware.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8AE84B189DE3CD00C33786 /* CoreAudioHardware.cpp */; }; + 7C8AE851189DE3CD00C33786 /* CoreAudioStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8AE84C189DE3CD00C33786 /* CoreAudioStream.cpp */; }; + 7C8AE854189DE47F00C33786 /* CoreAudioHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8AE852189DE47400C33786 /* CoreAudioHelpers.cpp */; }; 7C8FC6EE1829A4580045153D /* DirectoryProvider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8FC6EC1829A4580045153D /* DirectoryProvider.cpp */; }; 7C8FC6EF1829A4580045153D /* DirectoryProvider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8FC6EC1829A4580045153D /* DirectoryProvider.cpp */; }; 7C8FC6F01829A4580045153D /* DirectoryProvider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8FC6EC1829A4580045153D /* DirectoryProvider.cpp */; }; @@ -457,6 +462,8 @@ DF3488E713FD958F0026A711 /* GUIAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF3488E513FD958F0026A711 /* GUIAction.cpp */; }; DF34892A13FD9C780026A711 /* AirPlayServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF34892813FD9C780026A711 /* AirPlayServer.cpp */; }; DF34898213FDAAF60026A711 /* HttpParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF34898113FDAAF60026A711 /* HttpParser.cpp */; }; + DF374B2418AC2BA20076B514 /* CoreAudioHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8AE852189DE47400C33786 /* CoreAudioHelpers.cpp */; }; + DF374B2518AC2BA20076B514 /* CoreAudioHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C8AE852189DE47400C33786 /* CoreAudioHelpers.cpp */; }; DF3C3C0E1752A7EE000989C3 /* IOSEAGLView.mm in Sources */ = {isa = PBXBuildFile; fileRef = E49910D7174E4A6400741B6D /* IOSEAGLView.mm */; }; DF3C3C0F1752A7EE000989C3 /* IOSExternalTouchController.mm in Sources */ = {isa = PBXBuildFile; fileRef = E49910D9174E4A6400741B6D /* IOSExternalTouchController.mm */; }; DF3C3C101752A7EE000989C3 /* IOSScreenManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = E49910DB174E4A6400741B6D /* IOSScreenManager.mm */; }; @@ -567,12 +574,6 @@ DFB25D48163D4743006C4A48 /* WindowXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF1AD1EC15FCE77900E10810 /* WindowXML.cpp */; }; DFB65FB515373AE7006B8FF1 /* AEFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6515373AE7006B8FF1 /* AEFactory.cpp */; }; DFB65FB715373AE7006B8FF1 /* AEEncoderFFmpeg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6A15373AE7006B8FF1 /* AEEncoderFFmpeg.cpp */; }; - DFB65FB815373AE7006B8FF1 /* CoreAudioAE.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6D15373AE7006B8FF1 /* CoreAudioAE.cpp */; }; - DFB65FB915373AE7006B8FF1 /* CoreAudioAEHAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6F15373AE7006B8FF1 /* CoreAudioAEHAL.cpp */; }; - DFB65FBA15373AE7006B8FF1 /* CoreAudioAEHALIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7115373AE7006B8FF1 /* CoreAudioAEHALIOS.cpp */; }; - DFB65FBB15373AE7006B8FF1 /* CoreAudioAEHALOSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7315373AE7006B8FF1 /* CoreAudioAEHALOSX.cpp */; }; - DFB65FBC15373AE7006B8FF1 /* CoreAudioAESound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7515373AE7006B8FF1 /* CoreAudioAESound.cpp */; }; - DFB65FBD15373AE7006B8FF1 /* CoreAudioAEStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7715373AE7006B8FF1 /* CoreAudioAEStream.cpp */; }; DFB65FCC15373AE7006B8FF1 /* AEBitstreamPacker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65FA315373AE7006B8FF1 /* AEBitstreamPacker.cpp */; }; DFB65FCD15373AE7006B8FF1 /* AEBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65FA515373AE7006B8FF1 /* AEBuffer.cpp */; }; DFB65FCE15373AE7006B8FF1 /* AEChannelInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65FA715373AE7006B8FF1 /* AEChannelInfo.cpp */; }; @@ -796,11 +797,6 @@ DFF0F13617528350002DA3A4 /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DE0443315828F4B005DDB4D /* Exception.cpp */; }; DFF0F13717528350002DA3A4 /* ilog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC720A8D155091BB00FFD782 /* ilog.cpp */; }; DFF0F13817528350002DA3A4 /* AEEncoderFFmpeg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6A15373AE7006B8FF1 /* AEEncoderFFmpeg.cpp */; }; - DFF0F13917528350002DA3A4 /* CoreAudioAE.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6D15373AE7006B8FF1 /* CoreAudioAE.cpp */; }; - DFF0F13A17528350002DA3A4 /* CoreAudioAEHAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6F15373AE7006B8FF1 /* CoreAudioAEHAL.cpp */; }; - DFF0F13B17528350002DA3A4 /* CoreAudioAEHALIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7115373AE7006B8FF1 /* CoreAudioAEHALIOS.cpp */; }; - DFF0F13C17528350002DA3A4 /* CoreAudioAESound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7515373AE7006B8FF1 /* CoreAudioAESound.cpp */; }; - DFF0F13D17528350002DA3A4 /* CoreAudioAEStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7715373AE7006B8FF1 /* CoreAudioAEStream.cpp */; }; DFF0F13E17528350002DA3A4 /* AEBitstreamPacker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65FA315373AE7006B8FF1 /* AEBitstreamPacker.cpp */; }; DFF0F13F17528350002DA3A4 /* AEBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65FA515373AE7006B8FF1 /* AEBuffer.cpp */; }; DFF0F14017528350002DA3A4 /* AEChannelInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65FA715373AE7006B8FF1 /* AEChannelInfo.cpp */; }; @@ -2210,11 +2206,6 @@ E4991196174E5CEB00741B6D /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DE0443315828F4B005DDB4D /* Exception.cpp */; }; E4991197174E5CEB00741B6D /* ilog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC720A8D155091BB00FFD782 /* ilog.cpp */; }; E4991198174E5CF600741B6D /* AEEncoderFFmpeg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6A15373AE7006B8FF1 /* AEEncoderFFmpeg.cpp */; }; - E4991199174E5CFA00741B6D /* CoreAudioAE.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6D15373AE7006B8FF1 /* CoreAudioAE.cpp */; }; - E499119A174E5CFA00741B6D /* CoreAudioAEHAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F6F15373AE7006B8FF1 /* CoreAudioAEHAL.cpp */; }; - E499119B174E5CFA00741B6D /* CoreAudioAEHALIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7115373AE7006B8FF1 /* CoreAudioAEHALIOS.cpp */; }; - E499119D174E5CFA00741B6D /* CoreAudioAESound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7515373AE7006B8FF1 /* CoreAudioAESound.cpp */; }; - E499119E174E5CFA00741B6D /* CoreAudioAEStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65F7715373AE7006B8FF1 /* CoreAudioAEStream.cpp */; }; E49911A6174E5CFE00741B6D /* AEBitstreamPacker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65FA315373AE7006B8FF1 /* AEBitstreamPacker.cpp */; }; E49911A7174E5CFE00741B6D /* AEBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65FA515373AE7006B8FF1 /* AEBuffer.cpp */; }; E49911A8174E5CFE00741B6D /* AEChannelInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB65FA715373AE7006B8FF1 /* AEChannelInfo.cpp */; }; @@ -3156,6 +3147,9 @@ F5BDB80C120202F400F0B710 /* DVDSubtitleTagSami.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5BDB80B120202F400F0B710 /* DVDSubtitleTagSami.cpp */; }; F5BDB81A1202032400F0B710 /* DVDSubtitleTagMicroDVD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5BDB8191202032400F0B710 /* DVDSubtitleTagMicroDVD.cpp */; }; F5BDB820120203C200F0B710 /* AutoPtrHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5BDB81F120203C200F0B710 /* AutoPtrHandle.cpp */; }; + F5CC228B1814F7E9006B5E91 /* AESinkDARWINOSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC22891814F7E9006B5E91 /* AESinkDARWINOSX.cpp */; }; + F5CC228E1814F7F7006B5E91 /* AESinkDARWINIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC228C1814F7F7006B5E91 /* AESinkDARWINIOS.cpp */; }; + F5CC228F1814F7F7006B5E91 /* AESinkDARWINIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC228C1814F7F7006B5E91 /* AESinkDARWINIOS.cpp */; }; F5CC22DF1814FF3B006B5E91 /* ActiveAE.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC22D31814FF3B006B5E91 /* ActiveAE.cpp */; }; F5CC22E01814FF3B006B5E91 /* ActiveAEBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC22D51814FF3B006B5E91 /* ActiveAEBuffer.cpp */; }; F5CC22E11814FF3B006B5E91 /* ActiveAEResample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5CC22D71814FF3B006B5E91 /* ActiveAEResample.cpp */; }; @@ -3221,13 +3215,6 @@ F5ED8D6C1551F91400842059 /* BlurayDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED8D6A1551F91400842059 /* BlurayDirectory.cpp */; }; F5ED908815538DCE00842059 /* XBMCTinyXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED908615538DCE00842059 /* XBMCTinyXML.cpp */; }; F5ED908E15538E2300842059 /* POUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED908C15538E2300842059 /* POUtils.cpp */; }; - F5ED942E155D729500842059 /* CoreAudioDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED942A155D729500842059 /* CoreAudioDevice.cpp */; }; - F5ED942F155D729500842059 /* CoreAudioHardware.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED942C155D729500842059 /* CoreAudioHardware.cpp */; }; - F5ED943E155D743700842059 /* CoreAudioStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED943C155D743700842059 /* CoreAudioStream.cpp */; }; - F5ED9462155D777B00842059 /* CoreAudioChannelLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED9460155D777B00842059 /* CoreAudioChannelLayout.cpp */; }; - F5ED9496155D7B9900842059 /* CoreAudioMixMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED9494155D7B9900842059 /* CoreAudioMixMap.cpp */; }; - F5ED94AB155D7F8000842059 /* CoreAudioUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED94A9155D7F8000842059 /* CoreAudioUnit.cpp */; }; - F5ED9509155D855200842059 /* CoreAudioGraph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5ED9507155D855200842059 /* CoreAudioGraph.cpp */; }; F5ED9A0C155EBDC000842059 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E38E238E0D2626E600618676 /* CoreAudio.framework */; }; F5ED9A15155EBE0000842059 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88ECB6580DE013C4003396A7 /* DiskArbitration.framework */; }; F5ED9BFB155EC77400842059 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E38E25340D26365C00618676 /* ApplicationServices.framework */; }; @@ -3850,6 +3837,16 @@ 7C8A14551154CB2600E5FCFA /* TextureCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextureCache.h; sourceTree = "<group>"; }; 7C8A187A115B2A8200E5FCFA /* TextureDatabase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextureDatabase.cpp; sourceTree = "<group>"; }; 7C8A187B115B2A8200E5FCFA /* TextureDatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextureDatabase.h; sourceTree = "<group>"; }; + 7C8AE844189DE3CD00C33786 /* CoreAudioChannelLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioChannelLayout.h; path = Sinks/osx/CoreAudioChannelLayout.h; sourceTree = "<group>"; }; + 7C8AE845189DE3CD00C33786 /* CoreAudioDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioDevice.h; path = Sinks/osx/CoreAudioDevice.h; sourceTree = "<group>"; }; + 7C8AE846189DE3CD00C33786 /* CoreAudioHardware.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioHardware.h; path = Sinks/osx/CoreAudioHardware.h; sourceTree = "<group>"; }; + 7C8AE847189DE3CD00C33786 /* CoreAudioStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioStream.h; path = Sinks/osx/CoreAudioStream.h; sourceTree = "<group>"; }; + 7C8AE849189DE3CD00C33786 /* CoreAudioChannelLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioChannelLayout.cpp; path = Sinks/osx/CoreAudioChannelLayout.cpp; sourceTree = "<group>"; }; + 7C8AE84A189DE3CD00C33786 /* CoreAudioDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioDevice.cpp; path = Sinks/osx/CoreAudioDevice.cpp; sourceTree = "<group>"; }; + 7C8AE84B189DE3CD00C33786 /* CoreAudioHardware.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioHardware.cpp; path = Sinks/osx/CoreAudioHardware.cpp; sourceTree = "<group>"; }; + 7C8AE84C189DE3CD00C33786 /* CoreAudioStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioStream.cpp; path = Sinks/osx/CoreAudioStream.cpp; sourceTree = "<group>"; }; + 7C8AE852189DE47400C33786 /* CoreAudioHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioHelpers.cpp; path = Sinks/osx/CoreAudioHelpers.cpp; sourceTree = "<group>"; }; + 7C8AE853189DE47700C33786 /* CoreAudioHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioHelpers.h; path = Sinks/osx/CoreAudioHelpers.h; sourceTree = "<group>"; }; 7C8FC6EC1829A4580045153D /* DirectoryProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DirectoryProvider.cpp; path = xbmc/listproviders/DirectoryProvider.cpp; sourceTree = SOURCE_ROOT; }; 7C8FC6ED1829A4580045153D /* DirectoryProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DirectoryProvider.h; path = xbmc/listproviders/DirectoryProvider.h; sourceTree = SOURCE_ROOT; }; 7C920CF7181669FF00DA1477 /* TextureOperations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextureOperations.cpp; sourceTree = "<group>"; }; @@ -4302,20 +4299,6 @@ DFB65F6615373AE7006B8FF1 /* AEFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AEFactory.h; sourceTree = "<group>"; }; DFB65F6A15373AE7006B8FF1 /* AEEncoderFFmpeg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AEEncoderFFmpeg.cpp; sourceTree = "<group>"; }; DFB65F6B15373AE7006B8FF1 /* AEEncoderFFmpeg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AEEncoderFFmpeg.h; sourceTree = "<group>"; }; - DFB65F6D15373AE7006B8FF1 /* CoreAudioAE.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioAE.cpp; path = CoreAudio/CoreAudioAE.cpp; sourceTree = "<group>"; }; - DFB65F6E15373AE7006B8FF1 /* CoreAudioAE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioAE.h; path = CoreAudio/CoreAudioAE.h; sourceTree = "<group>"; }; - DFB65F6F15373AE7006B8FF1 /* CoreAudioAEHAL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioAEHAL.cpp; path = CoreAudio/CoreAudioAEHAL.cpp; sourceTree = "<group>"; }; - DFB65F7015373AE7006B8FF1 /* CoreAudioAEHAL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioAEHAL.h; path = CoreAudio/CoreAudioAEHAL.h; sourceTree = "<group>"; }; - DFB65F7115373AE7006B8FF1 /* CoreAudioAEHALIOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioAEHALIOS.cpp; path = CoreAudio/CoreAudioAEHALIOS.cpp; sourceTree = "<group>"; }; - DFB65F7215373AE7006B8FF1 /* CoreAudioAEHALIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioAEHALIOS.h; path = CoreAudio/CoreAudioAEHALIOS.h; sourceTree = "<group>"; }; - DFB65F7315373AE7006B8FF1 /* CoreAudioAEHALOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioAEHALOSX.cpp; path = CoreAudio/CoreAudioAEHALOSX.cpp; sourceTree = "<group>"; }; - DFB65F7415373AE7006B8FF1 /* CoreAudioAEHALOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioAEHALOSX.h; path = CoreAudio/CoreAudioAEHALOSX.h; sourceTree = "<group>"; }; - DFB65F7515373AE7006B8FF1 /* CoreAudioAESound.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioAESound.cpp; path = CoreAudio/CoreAudioAESound.cpp; sourceTree = "<group>"; }; - DFB65F7615373AE7006B8FF1 /* CoreAudioAESound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioAESound.h; path = CoreAudio/CoreAudioAESound.h; sourceTree = "<group>"; }; - DFB65F7715373AE7006B8FF1 /* CoreAudioAEStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioAEStream.cpp; path = CoreAudio/CoreAudioAEStream.cpp; sourceTree = "<group>"; }; - DFB65F7815373AE7006B8FF1 /* CoreAudioAEStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioAEStream.h; path = CoreAudio/CoreAudioAEStream.h; sourceTree = "<group>"; }; - DFB65F7A15373AE7006B8FF1 /* ICoreAudioAEHAL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ICoreAudioAEHAL.h; path = CoreAudio/ICoreAudioAEHAL.h; sourceTree = "<group>"; }; - DFB65F7B15373AE7006B8FF1 /* ICoreAudioSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ICoreAudioSource.h; path = CoreAudio/ICoreAudioSource.h; sourceTree = "<group>"; }; DFB65F8915373AE7006B8FF1 /* AE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AE.h; sourceTree = "<group>"; }; DFB65F8A15373AE7006B8FF1 /* AEEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AEEncoder.h; sourceTree = "<group>"; }; DFB65F8C15373AE7006B8FF1 /* AESink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AESink.h; sourceTree = "<group>"; }; @@ -5562,6 +5545,10 @@ F5BDB8191202032400F0B710 /* DVDSubtitleTagMicroDVD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DVDSubtitleTagMicroDVD.cpp; sourceTree = "<group>"; }; F5BDB81E120203C200F0B710 /* AutoPtrHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoPtrHandle.h; sourceTree = "<group>"; }; F5BDB81F120203C200F0B710 /* AutoPtrHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AutoPtrHandle.cpp; sourceTree = "<group>"; }; + F5CC22891814F7E9006B5E91 /* AESinkDARWINOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AESinkDARWINOSX.cpp; path = Sinks/AESinkDARWINOSX.cpp; sourceTree = "<group>"; }; + F5CC228A1814F7E9006B5E91 /* AESinkDARWINOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AESinkDARWINOSX.h; path = Sinks/AESinkDARWINOSX.h; sourceTree = "<group>"; }; + F5CC228C1814F7F7006B5E91 /* AESinkDARWINIOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AESinkDARWINIOS.cpp; path = Sinks/AESinkDARWINIOS.cpp; sourceTree = "<group>"; }; + F5CC228D1814F7F7006B5E91 /* AESinkDARWINIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AESinkDARWINIOS.h; path = Sinks/AESinkDARWINIOS.h; sourceTree = "<group>"; }; F5CC22D31814FF3B006B5E91 /* ActiveAE.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActiveAE.cpp; sourceTree = "<group>"; }; F5CC22D41814FF3B006B5E91 /* ActiveAE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActiveAE.h; sourceTree = "<group>"; }; F5CC22D51814FF3B006B5E91 /* ActiveAEBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActiveAEBuffer.cpp; sourceTree = "<group>"; }; @@ -5648,20 +5635,6 @@ F5ED908715538DCE00842059 /* XBMCTinyXML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMCTinyXML.h; sourceTree = "<group>"; }; F5ED908C15538E2300842059 /* POUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = POUtils.cpp; sourceTree = "<group>"; }; F5ED908D15538E2300842059 /* POUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = POUtils.h; sourceTree = "<group>"; }; - F5ED942A155D729500842059 /* CoreAudioDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioDevice.cpp; path = CoreAudio/CoreAudioDevice.cpp; sourceTree = "<group>"; }; - F5ED942B155D729500842059 /* CoreAudioDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioDevice.h; path = CoreAudio/CoreAudioDevice.h; sourceTree = "<group>"; }; - F5ED942C155D729500842059 /* CoreAudioHardware.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioHardware.cpp; path = CoreAudio/CoreAudioHardware.cpp; sourceTree = "<group>"; }; - F5ED942D155D729500842059 /* CoreAudioHardware.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioHardware.h; path = CoreAudio/CoreAudioHardware.h; sourceTree = "<group>"; }; - F5ED943C155D743700842059 /* CoreAudioStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioStream.cpp; path = CoreAudio/CoreAudioStream.cpp; sourceTree = "<group>"; }; - F5ED943D155D743700842059 /* CoreAudioStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioStream.h; path = CoreAudio/CoreAudioStream.h; sourceTree = "<group>"; }; - F5ED9460155D777B00842059 /* CoreAudioChannelLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioChannelLayout.cpp; path = CoreAudio/CoreAudioChannelLayout.cpp; sourceTree = "<group>"; }; - F5ED9461155D777B00842059 /* CoreAudioChannelLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioChannelLayout.h; path = CoreAudio/CoreAudioChannelLayout.h; sourceTree = "<group>"; }; - F5ED9494155D7B9900842059 /* CoreAudioMixMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioMixMap.cpp; path = CoreAudio/CoreAudioMixMap.cpp; sourceTree = "<group>"; }; - F5ED9495155D7B9900842059 /* CoreAudioMixMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioMixMap.h; path = CoreAudio/CoreAudioMixMap.h; sourceTree = "<group>"; }; - F5ED94A9155D7F8000842059 /* CoreAudioUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioUnit.cpp; path = CoreAudio/CoreAudioUnit.cpp; sourceTree = "<group>"; }; - F5ED94AA155D7F8000842059 /* CoreAudioUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioUnit.h; path = CoreAudio/CoreAudioUnit.h; sourceTree = "<group>"; }; - F5ED9507155D855200842059 /* CoreAudioGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CoreAudioGraph.cpp; path = CoreAudio/CoreAudioGraph.cpp; sourceTree = "<group>"; }; - F5ED9508155D855200842059 /* CoreAudioGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoreAudioGraph.h; path = CoreAudio/CoreAudioGraph.h; sourceTree = "<group>"; }; F5EDC48A1651A6F900B852D8 /* GroupUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GroupUtils.cpp; sourceTree = "<group>"; }; F5EDC48B1651A6F900B852D8 /* GroupUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupUtils.h; sourceTree = "<group>"; }; F5F240EB110A4F76009126C6 /* CrystalHD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CrystalHD.cpp; sourceTree = "<group>"; }; @@ -6816,6 +6789,23 @@ path = info; sourceTree = "<group>"; }; + 7C8AE7FE189DE3A700C33786 /* osx */ = { + isa = PBXGroup; + children = ( + 7C8AE849189DE3CD00C33786 /* CoreAudioChannelLayout.cpp */, + 7C8AE844189DE3CD00C33786 /* CoreAudioChannelLayout.h */, + 7C8AE84A189DE3CD00C33786 /* CoreAudioDevice.cpp */, + 7C8AE845189DE3CD00C33786 /* CoreAudioDevice.h */, + 7C8AE84B189DE3CD00C33786 /* CoreAudioHardware.cpp */, + 7C8AE846189DE3CD00C33786 /* CoreAudioHardware.h */, + 7C8AE852189DE47400C33786 /* CoreAudioHelpers.cpp */, + 7C8AE853189DE47700C33786 /* CoreAudioHelpers.h */, + 7C8AE84C189DE3CD00C33786 /* CoreAudioStream.cpp */, + 7C8AE847189DE3CD00C33786 /* CoreAudioStream.h */, + ); + name = osx; + sourceTree = "<group>"; + }; 810C9F5F0D67BCC80095F5DD /* MediaConnect */ = { isa = PBXGroup; children = ( @@ -7214,7 +7204,6 @@ DFB65F6C15373AE7006B8FF1 /* Engines */ = { isa = PBXGroup; children = ( - F5ED9362155CECC800842059 /* CoreAudio */, F5CC22D21814FF3B006B5E91 /* ActiveAE */, ); path = Engines; @@ -9214,6 +9203,7 @@ F5CC22851814F7B5006B5E91 /* Sinks */ = { isa = PBXGroup; children = ( + 7C8AE7FE189DE3A700C33786 /* osx */, F5CC228C1814F7F7006B5E91 /* AESinkDARWINIOS.cpp */, F5CC228D1814F7F7006B5E91 /* AESinkDARWINIOS.h */, F5CC22891814F7E9006B5E91 /* AESinkDARWINOSX.cpp */, @@ -9432,41 +9422,6 @@ name = playercorefactory; sourceTree = "<group>"; }; - F5ED9362155CECC800842059 /* CoreAudio */ = { - isa = PBXGroup; - children = ( - DFB65F6D15373AE7006B8FF1 /* CoreAudioAE.cpp */, - DFB65F6E15373AE7006B8FF1 /* CoreAudioAE.h */, - DFB65F6F15373AE7006B8FF1 /* CoreAudioAEHAL.cpp */, - DFB65F7015373AE7006B8FF1 /* CoreAudioAEHAL.h */, - DFB65F7115373AE7006B8FF1 /* CoreAudioAEHALIOS.cpp */, - DFB65F7215373AE7006B8FF1 /* CoreAudioAEHALIOS.h */, - DFB65F7315373AE7006B8FF1 /* CoreAudioAEHALOSX.cpp */, - DFB65F7415373AE7006B8FF1 /* CoreAudioAEHALOSX.h */, - DFB65F7515373AE7006B8FF1 /* CoreAudioAESound.cpp */, - DFB65F7615373AE7006B8FF1 /* CoreAudioAESound.h */, - DFB65F7715373AE7006B8FF1 /* CoreAudioAEStream.cpp */, - DFB65F7815373AE7006B8FF1 /* CoreAudioAEStream.h */, - F5ED9460155D777B00842059 /* CoreAudioChannelLayout.cpp */, - F5ED9461155D777B00842059 /* CoreAudioChannelLayout.h */, - F5ED942A155D729500842059 /* CoreAudioDevice.cpp */, - F5ED942B155D729500842059 /* CoreAudioDevice.h */, - F5ED9507155D855200842059 /* CoreAudioGraph.cpp */, - F5ED9508155D855200842059 /* CoreAudioGraph.h */, - F5ED942C155D729500842059 /* CoreAudioHardware.cpp */, - F5ED942D155D729500842059 /* CoreAudioHardware.h */, - F5ED9494155D7B9900842059 /* CoreAudioMixMap.cpp */, - F5ED9495155D7B9900842059 /* CoreAudioMixMap.h */, - F5ED943C155D743700842059 /* CoreAudioStream.cpp */, - F5ED943D155D743700842059 /* CoreAudioStream.h */, - F5ED94A9155D7F8000842059 /* CoreAudioUnit.cpp */, - F5ED94AA155D7F8000842059 /* CoreAudioUnit.h */, - DFB65F7A15373AE7006B8FF1 /* ICoreAudioAEHAL.h */, - DFB65F7B15373AE7006B8FF1 /* ICoreAudioSource.h */, - ); - name = CoreAudio; - sourceTree = "<group>"; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -10611,12 +10566,6 @@ F5ED908E15538E2300842059 /* POUtils.cpp in Sources */, DFB65FB515373AE7006B8FF1 /* AEFactory.cpp in Sources */, DFB65FB715373AE7006B8FF1 /* AEEncoderFFmpeg.cpp in Sources */, - DFB65FB815373AE7006B8FF1 /* CoreAudioAE.cpp in Sources */, - DFB65FB915373AE7006B8FF1 /* CoreAudioAEHAL.cpp in Sources */, - DFB65FBA15373AE7006B8FF1 /* CoreAudioAEHALIOS.cpp in Sources */, - DFB65FBB15373AE7006B8FF1 /* CoreAudioAEHALOSX.cpp in Sources */, - DFB65FBC15373AE7006B8FF1 /* CoreAudioAESound.cpp in Sources */, - DFB65FBD15373AE7006B8FF1 /* CoreAudioAEStream.cpp in Sources */, DFB65FCC15373AE7006B8FF1 /* AEBitstreamPacker.cpp in Sources */, DFB65FCD15373AE7006B8FF1 /* AEBuffer.cpp in Sources */, DFB65FCE15373AE7006B8FF1 /* AEChannelInfo.cpp in Sources */, @@ -10628,13 +10577,6 @@ DFB65FD415373AE7006B8FF1 /* AEWAVLoader.cpp in Sources */, DFB6610915374E80006B8FF1 /* DVDAudioCodecPassthrough.cpp in Sources */, 7C0B98A4154B79C30065A238 /* AEDeviceInfo.cpp in Sources */, - F5ED942E155D729500842059 /* CoreAudioDevice.cpp in Sources */, - F5ED942F155D729500842059 /* CoreAudioHardware.cpp in Sources */, - F5ED943E155D743700842059 /* CoreAudioStream.cpp in Sources */, - F5ED9462155D777B00842059 /* CoreAudioChannelLayout.cpp in Sources */, - F5ED9496155D7B9900842059 /* CoreAudioMixMap.cpp in Sources */, - F5ED94AB155D7F8000842059 /* CoreAudioUnit.cpp in Sources */, - F5ED9509155D855200842059 /* CoreAudioGraph.cpp in Sources */, 7C6EB330155BD1D40080368A /* ImageFile.cpp in Sources */, 7C6EB6FA155F32C30080368A /* HTTPImageHandler.cpp in Sources */, C84828C0156CFCD8005A996F /* PVRClient.cpp in Sources */, @@ -10850,6 +10792,7 @@ 7C1409A9184015C9009F9411 /* InfoExpression.cpp in Sources */, AE32174218313ADF0003FAFC /* XSLTUtils.cpp in Sources */, 7C15DCBC1892481400FCE564 /* InfoBool.cpp in Sources */, + F5CC228B1814F7E9006B5E91 /* AESinkDARWINOSX.cpp in Sources */, F5CC22EB1814FF3B006B5E91 /* ActiveAE.cpp in Sources */, F5CC22EC1814FF3B006B5E91 /* ActiveAEBuffer.cpp in Sources */, F5CC22ED1814FF3B006B5E91 /* ActiveAEResample.cpp in Sources */, @@ -10861,6 +10804,11 @@ F5CC230E18150118006B5E91 /* AESinkFactory.cpp in Sources */, F5CC234918150277006B5E91 /* AESinkNULL.cpp in Sources */, F5CC238A18150768006B5E91 /* AESinkProfiler.cpp in Sources */, + 7C8AE84E189DE3CD00C33786 /* CoreAudioChannelLayout.cpp in Sources */, + 7C8AE84F189DE3CD00C33786 /* CoreAudioDevice.cpp in Sources */, + 7C8AE850189DE3CD00C33786 /* CoreAudioHardware.cpp in Sources */, + 7C8AE851189DE3CD00C33786 /* CoreAudioStream.cpp in Sources */, + 7C8AE854189DE47F00C33786 /* CoreAudioHelpers.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -11027,11 +10975,6 @@ DFF0F13617528350002DA3A4 /* Exception.cpp in Sources */, DFF0F13717528350002DA3A4 /* ilog.cpp in Sources */, DFF0F13817528350002DA3A4 /* AEEncoderFFmpeg.cpp in Sources */, - DFF0F13917528350002DA3A4 /* CoreAudioAE.cpp in Sources */, - DFF0F13A17528350002DA3A4 /* CoreAudioAEHAL.cpp in Sources */, - DFF0F13B17528350002DA3A4 /* CoreAudioAEHALIOS.cpp in Sources */, - DFF0F13C17528350002DA3A4 /* CoreAudioAESound.cpp in Sources */, - DFF0F13D17528350002DA3A4 /* CoreAudioAEStream.cpp in Sources */, DFF0F13E17528350002DA3A4 /* AEBitstreamPacker.cpp in Sources */, DFF0F13F17528350002DA3A4 /* AEBuffer.cpp in Sources */, DFF0F14017528350002DA3A4 /* AEChannelInfo.cpp in Sources */, @@ -11905,6 +11848,7 @@ 7C1409AB184015C9009F9411 /* InfoExpression.cpp in Sources */, AE32174318313AE10003FAFC /* XSLTUtils.cpp in Sources */, 7C15DCBE1892481400FCE564 /* InfoBool.cpp in Sources */, + F5CC228F1814F7F7006B5E91 /* AESinkDARWINIOS.cpp in Sources */, F5CC22E51814FF3B006B5E91 /* ActiveAE.cpp in Sources */, F5CC22E61814FF3B006B5E91 /* ActiveAEBuffer.cpp in Sources */, F5CC22E71814FF3B006B5E91 /* ActiveAEResample.cpp in Sources */, @@ -11916,6 +11860,7 @@ F5CC230D18150118006B5E91 /* AESinkFactory.cpp in Sources */, F5CC234818150277006B5E91 /* AESinkNULL.cpp in Sources */, F5CC238918150768006B5E91 /* AESinkProfiler.cpp in Sources */, + DF374B2518AC2BA20076B514 /* CoreAudioHelpers.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -12089,11 +12034,6 @@ E4991196174E5CEB00741B6D /* Exception.cpp in Sources */, E4991197174E5CEB00741B6D /* ilog.cpp in Sources */, E4991198174E5CF600741B6D /* AEEncoderFFmpeg.cpp in Sources */, - E4991199174E5CFA00741B6D /* CoreAudioAE.cpp in Sources */, - E499119A174E5CFA00741B6D /* CoreAudioAEHAL.cpp in Sources */, - E499119B174E5CFA00741B6D /* CoreAudioAEHALIOS.cpp in Sources */, - E499119D174E5CFA00741B6D /* CoreAudioAESound.cpp in Sources */, - E499119E174E5CFA00741B6D /* CoreAudioAEStream.cpp in Sources */, E49911A6174E5CFE00741B6D /* AEBitstreamPacker.cpp in Sources */, E49911A7174E5CFE00741B6D /* AEBuffer.cpp in Sources */, E49911A8174E5CFE00741B6D /* AEChannelInfo.cpp in Sources */, @@ -12962,6 +12902,7 @@ 7C1409AA184015C9009F9411 /* InfoExpression.cpp in Sources */, AE4E87A717354C4A00D15206 /* XSLTUtils.cpp in Sources */, 7C15DCBD1892481400FCE564 /* InfoBool.cpp in Sources */, + F5CC228E1814F7F7006B5E91 /* AESinkDARWINIOS.cpp in Sources */, F5CC22DF1814FF3B006B5E91 /* ActiveAE.cpp in Sources */, F5CC22E01814FF3B006B5E91 /* ActiveAEBuffer.cpp in Sources */, F5CC22E11814FF3B006B5E91 /* ActiveAEResample.cpp in Sources */, @@ -12973,6 +12914,7 @@ F5CC230C18150118006B5E91 /* AESinkFactory.cpp in Sources */, F5CC234718150277006B5E91 /* AESinkNULL.cpp in Sources */, F5CC238818150768006B5E91 /* AESinkProfiler.cpp in Sources */, + DF374B2418AC2BA20076B514 /* CoreAudioHelpers.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp index fff42a6130..17ebcc9765 100644 --- a/xbmc/cores/AudioEngine/AEFactory.cpp +++ b/xbmc/cores/AudioEngine/AEFactory.cpp @@ -22,12 +22,7 @@ #include "AEFactory.h" #include "Utils/AEUtil.h" -#if defined(TARGET_DARWIN) - #include "Engines/CoreAudio/CoreAudioAE.h" - #include "settings/lib/SettingsManager.h" -#else - #include "Engines/ActiveAE/ActiveAE.h" -#endif +#include "Engines/ActiveAE/ActiveAE.h" #include "guilib/LocalizeStrings.h" #include "settings/lib/Setting.h" @@ -45,11 +40,7 @@ IAE *CAEFactory::GetEngine() bool CAEFactory::LoadEngine() { -#if defined(TARGET_DARWIN) - return CAEFactory::LoadEngine(AE_ENGINE_COREAUDIO); -#else return CAEFactory::LoadEngine(AE_ENGINE_ACTIVE); -#endif } bool CAEFactory::LoadEngine(enum AEEngine engine) @@ -61,11 +52,7 @@ bool CAEFactory::LoadEngine(enum AEEngine engine) switch(engine) { case AE_ENGINE_NULL : -#if defined(TARGET_DARWIN) - case AE_ENGINE_COREAUDIO: AE = new CCoreAudioAE(); break; -#else case AE_ENGINE_ACTIVE : AE = new ActiveAE::CActiveAE(); break; -#endif default: return false; } @@ -355,12 +342,10 @@ void CAEFactory::SettingOptionsAudioDevicesFillerGeneral(const CSetting *setting bool foundValue = false; AEDeviceList sinkList; EnumerateOutputDevices(sinkList, passthrough); -#if !defined(TARGET_DARWIN) if (sinkList.size() == 0) list.push_back(std::make_pair("Error - no devices found", "error")); else { -#endif for (AEDeviceList::const_iterator sink = sinkList.begin(); sink != sinkList.end(); ++sink) { if (sink == sinkList.begin()) @@ -371,9 +356,7 @@ void CAEFactory::SettingOptionsAudioDevicesFillerGeneral(const CSetting *setting if (StringUtils::EqualsNoCase(current, sink->second)) foundValue = true; } -#if !defined(TARGET_DARWIN) } -#endif if (!foundValue) current = firstDevice; diff --git a/xbmc/cores/AudioEngine/AESinkFactory.cpp b/xbmc/cores/AudioEngine/AESinkFactory.cpp index bfd43a0109..128010ea9d 100644 --- a/xbmc/cores/AudioEngine/AESinkFactory.cpp +++ b/xbmc/cores/AudioEngine/AESinkFactory.cpp @@ -27,6 +27,10 @@ #include "Sinks/AESinkAUDIOTRACK.h" #elif defined(TARGET_RASPBERRY_PI) #include "Sinks/AESinkPi.h" +#elif defined(TARGET_DARWIN_IOS) + #include "Sinks/AESinkDARWINIOS.h" +#elif defined(TARGET_DARWIN_OSX) + #include "Sinks/AESinkDARWINOSX.h" #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) #if defined(HAS_ALSA) #include "Sinks/AESinkALSA.h" @@ -62,6 +66,10 @@ void CAESinkFactory::ParseDevice(std::string &device, std::string &driver) driver == "AUDIOTRACK" || #elif defined(TARGET_RASPBERRY_PI) driver == "PI" || +#elif defined(TARGET_DARWIN_IOS) + driver == "DARWINIOS" || +#elif defined(TARGET_DARWIN_OSX) + driver == "DARWINOSX" || #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) #if defined(HAS_ALSA) driver == "ALSA" || @@ -97,6 +105,10 @@ IAESink *CAESinkFactory::TrySink(std::string &driver, std::string &device, AEAud sink = new CAESinkAUDIOTRACK(); #elif defined(TARGET_RASPBERRY_PI) sink = new CAESinkPi(); +#elif defined(TARGET_DARWIN_IOS) + sink = new CAESinkDARWINIOS(); +#elif defined(TARGET_DARWIN_OSX) + sink = new CAESinkDARWINOSX(); #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) #if defined(HAS_PULSEAUDIO) else if (driver == "PULSE") @@ -175,6 +187,22 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force) if(!info.m_deviceInfoList.empty()) list.push_back(info); +#elif defined(TARGET_DARWIN_IOS) + + info.m_deviceInfoList.clear(); + info.m_sinkName = "DARWINIOS"; + CAESinkDARWINIOS::EnumerateDevicesEx(info.m_deviceInfoList, force); + if(!info.m_deviceInfoList.empty()) + list.push_back(info); + +#elif defined(TARGET_DARWIN_OSX) + + info.m_deviceInfoList.clear(); + info.m_sinkName = "DARWINOSX"; + CAESinkDARWINOSX::EnumerateDevicesEx(info.m_deviceInfoList, force); + if(!info.m_deviceInfoList.empty()) + list.push_back(info); + #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) // check if user wants us to do something specific if (getenv("AE_SINK")) diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp deleted file mode 100644 index 1cd49cb1d9..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp +++ /dev/null @@ -1,929 +0,0 @@ -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "system.h" - -#include "CoreAudioAE.h" - -#include "CoreAudioAEStream.h" -#include "CoreAudioAESound.h" -#include "Application.h" -#include "cores/AudioEngine/Utils/AEUtil.h" -#include "settings/AdvancedSettings.h" -#include "settings/Settings.h" -#include "threads/SingleLock.h" -#include "utils/EndianSwap.h" -#include "utils/log.h" -#include "utils/TimeUtils.h" -#include "utils/MathUtils.h" -#include "threads/SystemClock.h" - -#define DELAY_FRAME_TIME 20 -#define BUFFERSIZE 16416 - -// on darwin when the devicelist changes -// reinit by calling opencoreaudio with the last engine parameters -// (this will fallback to default -// device when our current output device vanishes -// and on the other hand will go back to that device -// if it re-appears). -#if defined(TARGET_DARWIN_OSX) -OSStatus deviceChangedCB( AudioObjectID inObjectID, - UInt32 inNumberAddresses, - const AudioObjectPropertyAddress inAddresses[], - void* inClientData) -{ - CCoreAudioAE *pEngine = (CCoreAudioAE *)inClientData; - if (pEngine->GetHAL()) - { - pEngine->AudioDevicesChanged(); - CLog::Log(LOGDEBUG, "CCoreAudioAE - audiodevicelist changed!"); - } - return noErr; -} - -void RegisterDeviceChangedCB(bool bRegister, void *ref) -{ - OSStatus ret = noErr; - const AudioObjectPropertyAddress inAdr = - { - kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - if (bRegister) - ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref); - else - ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref); - - if (ret != noErr) - CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for device changes!", bRegister?"attaching":"removing"); -} -#else//ios -void RegisterDeviceChangedCB(bool bRegister, void *ref){} -#endif - -CCoreAudioAE::CCoreAudioAE() : - m_Initialized (false ), - m_deviceLost (false ), - m_callbackRunning (false ), - m_lastStreamFormat (AE_FMT_INVALID), - m_lastChLayoutCount (0 ), - m_lastSampleRate (0 ), - m_chLayoutCount (0 ), - m_rawPassthrough (false ), - m_volume (1.0f ), - m_volumeBeforeMute (1.0f ), - m_muted (false ), - m_soundMode (AE_SOUND_OFF ), - m_streamsPlaying (false ), - m_isSuspended (false ), - m_softSuspend (false ), - m_softSuspendTimer (0 ) -{ - HAL = new CCoreAudioAEHAL; - - RegisterDeviceChangedCB(true, this); -} - -CCoreAudioAE::~CCoreAudioAE() -{ - RegisterDeviceChangedCB(false, this); - Shutdown(); -} - -void CCoreAudioAE::Shutdown() -{ - CSingleLock engineLock(m_engineLock); - - Stop(); - - Deinitialize(); - - /* free the streams */ - CSingleLock streamLock(m_streamLock); - while (!m_streams.empty()) - { - CCoreAudioAEStream *s = m_streams.front(); - m_sounds.pop_front(); - delete s; - } - - /* free the sounds */ - CSingleLock soundLock(m_soundLock); - while (!m_sounds.empty()) - { - CCoreAudioAESound *s = m_sounds.front(); - m_sounds.pop_front(); - delete s; - } - - delete HAL; - HAL = NULL; -} - -void CCoreAudioAE::AudioDevicesChanged() -{ - if (!m_Initialized && !m_deviceLost) - return; - - CSingleLock engineLock(m_engineLock); - - // re-check initialized since it can have changed when we waited and grabbed the lock - if (!m_Initialized && !m_deviceLost) - return; - - OpenCoreAudio(m_lastSampleRate, COREAUDIO_IS_RAW(m_lastStreamFormat), m_lastStreamFormat, m_transcode); - - // when we tried to open the default device or the last device - // again there was an error preventing us from doing it (mostly - // the device couldn't be found) - in that case - // mark our device as lost and hope that another callback - // for changed device list fires (e.x. device reappears) - if (!m_Initialized) - m_deviceLost = true; - else - m_deviceLost = false; -} - -bool CCoreAudioAE::Initialize() -{ - CSingleLock engineLock(m_engineLock); - - Stop(); - - Deinitialize(); - - bool ret = OpenCoreAudio(44100, false, AE_FMT_FLOAT, false); - m_lastSampleRate = 44100; - m_lastStreamFormat = AE_FMT_FLOAT; - - Start(); - - return ret; -} - -bool CCoreAudioAE::OpenCoreAudio(unsigned int sampleRate, bool forceRaw, - enum AEDataFormat rawDataFormat, bool forceTranscode) -{ - unsigned int maxChannelCountInStreams = 0; - // remove any deleted streams - CSingleLock streamLock(m_streamLock); - for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end();) - { - CCoreAudioAEStream *stream = *itt; - if (stream->IsDestroyed()) - { - itt = m_streams.erase(itt); - delete stream; - continue; - } - else - { - // close all converter - stream->CloseConverter(); - } - - if (stream->GetChannelCount() > maxChannelCountInStreams) - maxChannelCountInStreams = stream->GetChannelCount(); - - ++itt; - } - - /* override the sample rate based on the oldest stream if there is one */ - if (!m_streams.empty()) - sampleRate = m_streams.front()->GetSampleRate(); - - if (forceRaw) - m_rawPassthrough = true; - else - m_rawPassthrough = !m_streams.empty() && m_streams.front()->IsRaw(); - streamLock.Leave(); - - if (m_rawPassthrough) - CLog::Log(LOGINFO, "CCoreAudioAE::OpenCoreAudio - RAW passthrough enabled"); - - m_transcode = forceTranscode; - - if (m_transcode) - CLog::Log(LOGINFO, "CCoreAudioAE::OpenCoreAudio - transcode to ac3 enabled"); - - std::string m_outputDevice = CSettings::Get().GetString("audiooutput.audiodevice"); - - // on iOS devices we set fixed to two channels. - m_stdChLayout = AE_CH_LAYOUT_2_0; -#if defined(TARGET_DARWIN_OSX) - switch (CSettings::Get().GetInt("audiooutput.channels")) - { - default: - case 0: m_stdChLayout = AE_CH_LAYOUT_2_0; break; /* do not allow 1_0 output */ - case 1: m_stdChLayout = AE_CH_LAYOUT_2_0; break; - case 2: m_stdChLayout = AE_CH_LAYOUT_2_1; break; - case 3: m_stdChLayout = AE_CH_LAYOUT_3_0; break; - case 4: m_stdChLayout = AE_CH_LAYOUT_3_1; break; - case 5: m_stdChLayout = AE_CH_LAYOUT_4_0; break; - case 6: m_stdChLayout = AE_CH_LAYOUT_4_1; break; - case 7: m_stdChLayout = AE_CH_LAYOUT_5_0; break; - case 8: m_stdChLayout = AE_CH_LAYOUT_5_1; break; - case 9: m_stdChLayout = AE_CH_LAYOUT_7_0; break; - case 10: m_stdChLayout = AE_CH_LAYOUT_7_1; break; - } -#endif - - // setup the desired format - m_format.m_channelLayout = CAEChannelInfo(m_stdChLayout); - - // if there is an audio resample rate set, use it. - if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED && !m_rawPassthrough) - { - sampleRate = CSettings::Get().GetInt("audiooutput.samplerate"); - CLog::Log(LOGINFO, "CCoreAudioAE::passthrough - Forcing samplerate to %d", sampleRate); - } - - if (m_rawPassthrough && !m_transcode) - { - switch (rawDataFormat) - { - case AE_FMT_AC3: - case AE_FMT_DTS: - m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_2_0); - m_format.m_sampleRate = 48000; - m_format.m_dataFormat = AE_FMT_S16NE; - break; - case AE_FMT_EAC3: - m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_2_0); - m_format.m_sampleRate = 192000; - m_format.m_dataFormat = AE_FMT_S16NE; - break; - case AE_FMT_DTSHD: - case AE_FMT_TRUEHD: - m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_7_1); - m_format.m_sampleRate = 192000; - m_format.m_dataFormat = AE_FMT_S16NE; - break; - case AE_FMT_LPCM: - // audio midi setup can be setup to 2.0 or 7.1 - // if we have the number of max channels from streams we use that for - // selecting either 2.0 or 7.1 setup depending on that. - // This allows DPII modes on amps for enhancing stereo sound - // (when switching to 7.1 - all 8 channels will be pushed out preventing most amps - // to switch to DPII mode) - if (maxChannelCountInStreams == 1 || maxChannelCountInStreams == 2) - m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_2_0); - else - m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_7_1); - m_format.m_sampleRate = sampleRate; - m_format.m_dataFormat = AE_FMT_FLOAT; - break; - default: - break; - } - } - else if (m_transcode) - { - // transcode is to ac3 only, do we copy the ac3 settings from above - m_format.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_2_0); - m_format.m_sampleRate = 48000; - m_format.m_dataFormat = AE_FMT_S16NE; - } - else - { - m_format.m_sampleRate = sampleRate; - m_format.m_channelLayout = CAEChannelInfo(m_stdChLayout); - m_format.m_dataFormat = AE_FMT_FLOAT; - } - - m_format.m_encodedRate = 0; - - if (m_outputDevice.empty()) - m_outputDevice = "default"; - - AEAudioFormat initformat = m_format; - - // initialize audio hardware - m_Initialized = HAL->Initialize(this, m_rawPassthrough || m_transcode, initformat, m_transcode ? AE_FMT_AC3 : rawDataFormat, m_outputDevice, m_volume); - - unsigned int bps = CAEUtil::DataFormatToBits(m_format.m_dataFormat); - m_chLayoutCount = m_format.m_channelLayout.Count(); - m_format.m_frameSize = (bps>>3) * m_chLayoutCount; //initformat.m_frameSize; - //m_format.m_frames = (unsigned int)(((float)m_format.m_sampleRate / 1000.0f) * (float)DELAY_FRAME_TIME); - //m_format.m_frameSamples = m_format.m_frames * m_format.m_channelLayout.Count(); - - if ((initformat.m_channelLayout.Count() != m_chLayoutCount) && !m_rawPassthrough && !m_transcode) - { - /* readjust parameters. hardware didn't accept channel count*/ - CLog::Log(LOGINFO, "CCoreAudioAE::Initialize: Setup channels (%d) greater than possible hardware channels (%d).", - m_chLayoutCount, initformat.m_channelLayout.Count()); - - m_format.m_channelLayout = CAEChannelInfo(initformat.m_channelLayout); - m_chLayoutCount = m_format.m_channelLayout.Count(); - m_format.m_frameSize = (bps>>3) * m_chLayoutCount; //initformat.m_frameSize; - //m_format.m_frameSamples = m_format.m_frames * m_format.m_channelLayout.Count(); - } - - CLog::Log(LOGINFO, "CCoreAudioAE::Initialize:"); - CLog::Log(LOGINFO, " Output Device : %s", m_outputDevice.c_str()); - CLog::Log(LOGINFO, " Sample Rate : %d", m_format.m_sampleRate); - CLog::Log(LOGINFO, " Sample Format : %s", CAEUtil::DataFormatToStr(m_format.m_dataFormat)); - CLog::Log(LOGINFO, " Channel Count : %d", m_chLayoutCount); - CLog::Log(LOGINFO, " Channel Layout: %s", ((std::string)m_format.m_channelLayout).c_str()); - CLog::Log(LOGINFO, " Frame Size : %d", m_format.m_frameSize); - CLog::Log(LOGINFO, " Volume Level : %f", m_volume); - CLog::Log(LOGINFO, " Passthrough : %d", m_rawPassthrough); - CLog::Log(LOGINFO, " Transcode : %d", m_transcode); - - CSingleLock soundLock(m_soundLock); - StopAllSounds(); - - // re-init sounds and unlock - for (SoundList::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt) - (*itt)->Initialize(); - - soundLock.Leave(); - - // if we are not in m_rawPassthrough reinit the streams - if (!m_rawPassthrough) - { - /* re-init streams */ - streamLock.Enter(); - for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt) - (*itt)->Initialize(); - streamLock.Leave(); - } - - return m_Initialized; -} - -void CCoreAudioAE::Deinitialize() -{ - if (!m_Initialized) - return; - - // close all open converters - CSingleLock streamLock(m_streamLock); - for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end();++itt) - (*itt)->CloseConverter(); - streamLock.Leave(); - - m_Initialized = false; - - CSingleLock callbackLock(m_callbackLock); - - /* - while(m_callbackRunning) - Sleep(100); - */ - - HAL->Deinitialize(); -} - -void CCoreAudioAE::OnSettingsChange(const std::string& setting) -{ - if (setting == "audiooutput.dontnormalizelevels") - { - // re-init streams remapper - CSingleLock streamLock(m_streamLock); - for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt) - (*itt)->InitializeRemap(); - streamLock.Leave(); - } - - if (setting == "audiooutput.passthroughdevice" || - setting == "audiooutput.custompassthrough" || - setting == "audiooutput.audiodevice" || - setting == "audiooutput.customdevice" || - setting == "audiooutput.ac3passthrough" || - setting == "audiooutput.eac3passthrough" || - setting == "audiooutput.dtspassthrough" || - setting == "audiooutput.channels" || - setting == "audiooutput.samplerate" || - setting == "audiooutput.config" || - setting == "audiooutput.passthrough" ) - { - // only reinit the engine if we not - // suspended (resume will initialize - // us again in that case) - if (!m_isSuspended) - Initialize(); - } -} - -unsigned int CCoreAudioAE::GetSampleRate() -{ - return m_format.m_sampleRate; -} - -unsigned int CCoreAudioAE::GetEncodedSampleRate() -{ - return m_format.m_encodedRate; -} - -CAEChannelInfo CCoreAudioAE::GetChannelLayout() -{ - return m_format.m_channelLayout; -} - -unsigned int CCoreAudioAE::GetChannelCount() -{ - return m_chLayoutCount; -} - -enum AEDataFormat CCoreAudioAE::GetDataFormat() -{ - return m_format.m_dataFormat; -} - -AEAudioFormat CCoreAudioAE::GetAudioFormat() -{ - return m_format; -} - -double CCoreAudioAE::GetDelay() -{ - return HAL->GetDelay(); -} - -float CCoreAudioAE::GetVolume() -{ - return m_volume; -} - -void CCoreAudioAE::SetVolume(float volume) -{ - if (m_rawPassthrough) - return; - - m_volume = volume; - // track volume if we are not muted - // we need this because m_volume is init'ed via - // SetVolume and need to also init m_volumeBeforeMute. - if (!m_muted) - m_volumeBeforeMute = volume; - - HAL->SetVolume(m_volume); -} - -void CCoreAudioAE::SetMute(const bool enabled) -{ - m_muted = enabled; - if(m_muted) - { - m_volumeBeforeMute = m_volume; - SetVolume(VOLUME_MINIMUM); - } - else - { - SetVolume(m_volumeBeforeMute); - } -} - -bool CCoreAudioAE::IsMuted() -{ - return m_muted; -} - -bool CCoreAudioAE::IsSuspended() -{ - return m_isSuspended; -} - -void CCoreAudioAE::SetSoundMode(const int mode) -{ - m_soundMode = mode; - - /* stop all currently playing sounds if they are being turned off */ - if (mode == AE_SOUND_OFF || (mode == AE_SOUND_IDLE && m_streamsPlaying)) - StopAllSounds(); -} - -bool CCoreAudioAE::SupportsRaw(AEDataFormat format) -{ - switch(format) - { - case AE_FMT_AC3: - case AE_FMT_DTS: - case AE_FMT_EAC3: - case AE_FMT_LPCM: - return true; - default: - return false; - } -} - -bool CCoreAudioAE::IsSettingVisible(const std::string &settingId) -{ - if (settingId == "audiooutput.samplerate") - { - if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED) - return true; - else - return false; - } - else if (settingId == "audiooutput.stereoupmix") - { - if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0) - return true; - } - - return true; -} - -CCoreAudioAEHAL* CCoreAudioAE::GetHAL() -{ - return HAL; -} - -IAEStream* CCoreAudioAE::MakeStream(enum AEDataFormat dataFormat, - unsigned int sampleRate, unsigned int encodedSamplerate, CAEChannelInfo channelLayout, unsigned int options) -{ - // if we are suspended we don't - // want anyone to mess with us - if (m_isSuspended && !m_softSuspend) -#if defined(TARGET_DARWIN_IOS) && !defined(TARGET_DARWIN_IOS_ATV) - Resume(); -#else - return NULL; -#endif - - CAEChannelInfo channelInfo(channelLayout); - CLog::Log(LOGINFO, "CCoreAudioAE::MakeStream - %s, %u, %u, %s", - CAEUtil::DataFormatToStr(dataFormat), sampleRate, encodedSamplerate, ((std::string)channelInfo).c_str()); - - bool multichannelpcm = CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0; //if more then 2 channels are set - assume lpcm capability -#if defined(TARGET_DARWIN_IOS) - multichannelpcm = false; -#endif - // determine if we need to transcode this audio - // when we're called, we'll either get the audio in an encoded form (COREAUDIO_IS_RAW==true) - // that we can passthrough based on user options, or we'll get it unencoded - // if it's unencoded, and is 5.1, we'll transcode it to AC3 if possible - bool transcode = CSettings::Get().GetBool("audiooutput.passthrough") && CSettings::Get().GetBool("audiooutput.ac3passthrough") && !multichannelpcm && - !COREAUDIO_IS_RAW(dataFormat) && - (channelInfo.Count() == 6); - - CCoreAudioAEStream *stream = new CCoreAudioAEStream(dataFormat, sampleRate, encodedSamplerate, channelLayout, options, transcode); - CSingleLock streamLock(m_streamLock); - m_streams.push_back(stream); - streamLock.Leave(); - - if ((options & AESTREAM_PAUSED) == 0) - Stop(); - - // reinit the engine if pcm format changes or always on raw format or always on transcode - if (m_Initialized && ( m_lastStreamFormat != dataFormat || - m_lastChLayoutCount != channelLayout.Count() || - m_lastSampleRate != sampleRate || - COREAUDIO_IS_RAW(dataFormat) || - transcode)) - { - CSingleLock engineLock(m_engineLock); - Stop(); - Deinitialize(); - m_Initialized = OpenCoreAudio(sampleRate, COREAUDIO_IS_RAW(dataFormat), dataFormat, transcode); - m_lastStreamFormat = dataFormat; - m_lastChLayoutCount = channelLayout.Count(); - m_lastSampleRate = sampleRate; - } - - /* if the stream was not initialized, do it now */ - if (!stream->IsValid()) - stream->Initialize(); - - if ((options & AESTREAM_PAUSED) == 0) - Start(); - - m_streamsPlaying = true; - - return stream; -} - -IAEStream* CCoreAudioAE::FreeStream(IAEStream *stream) -{ - CSingleLock streamLock(m_streamLock); - /* ensure the stream still exists */ - for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ) - { - CCoreAudioAEStream *del = *itt; - if (*itt == stream) - { - itt = m_streams.erase(itt); - delete (CCoreAudioAEStream *)stream; - } - else if (del->IsDestroyed()) - { - itt = m_streams.erase(itt); - delete del; - } - else - { - ++itt; - } - - } - m_streamsPlaying = !m_streams.empty(); - - streamLock.Leave(); - - // When we have been in passthrough mode and are not suspended, - // reinit the hardware to come back to anlog out - if (/*m_streams.empty() || */ m_rawPassthrough && !m_isSuspended) - { - CLog::Log(LOGINFO, "CCoreAudioAE::FreeStream Reinit, no streams left" ); - Initialize(); - } - - return NULL; -} - -void CCoreAudioAE::PlaySound(IAESound *sound) -{ - if (m_soundMode == AE_SOUND_OFF || (m_soundMode == AE_SOUND_IDLE && m_streamsPlaying) || (m_isSuspended && !m_softSuspend)) - return; - - float *samples = ((CCoreAudioAESound*)sound)->GetSamples(); - if (!samples && !m_Initialized) - return; - - /* add the sound to the play list */ - CSingleLock soundSampleLock(m_soundSampleLock); - SoundState ss = { - ((CCoreAudioAESound*)sound), - samples, - ((CCoreAudioAESound*)sound)->GetSampleCount() - }; - m_playing_sounds.push_back(ss); -} - -void CCoreAudioAE::StopSound(IAESound *sound) -{ - CSingleLock lock(m_soundSampleLock); - for (SoundStateList::iterator itt = m_playing_sounds.begin(); itt != m_playing_sounds.end(); ) - { - if ((*itt).owner == sound) - { - (*itt).owner->ReleaseSamples(); - itt = m_playing_sounds.erase(itt); - } - else - ++itt; - } -} - -IAESound *CCoreAudioAE::MakeSound(const std::string& file) -{ - // we don't make sounds - // when suspended - if (m_isSuspended) - return NULL; - - CSingleLock soundLock(m_soundLock); - - // first check if we have the file cached - for (SoundList::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt) - { - if ((*itt)->GetFileName() == file) - return *itt; - } - - CCoreAudioAESound *sound = new CCoreAudioAESound(file); - if (!sound->Initialize()) - { - delete sound; - return NULL; - } - - m_sounds.push_back(sound); - return sound; -} - -void CCoreAudioAE::FreeSound(IAESound *sound) -{ - if (!sound) - return; - - sound->Stop(); - CSingleLock soundLock(m_soundLock); - for (SoundList::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt) - if (*itt == sound) - { - m_sounds.erase(itt); - break; - } - - delete (CCoreAudioAESound*)sound; -} - -void CCoreAudioAE::StopAllSounds() -{ - CSingleLock lock(m_soundSampleLock); - while (!m_playing_sounds.empty()) - { - SoundState *ss = &(*m_playing_sounds.begin()); - m_playing_sounds.pop_front(); - ss->owner->ReleaseSamples(); - } -} - -void CCoreAudioAE::MixSounds(float *buffer, unsigned int samples) -{ - if (!m_Initialized) - return; - - SoundStateList::iterator itt; - - CSingleLock lock(m_soundSampleLock); - for (itt = m_playing_sounds.begin(); itt != m_playing_sounds.end(); ) - { - SoundState *ss = &(*itt); - - // no more frames, so remove it from the list - if (ss->sampleCount == 0) - { - ss->owner->ReleaseSamples(); - itt = m_playing_sounds.erase(itt); - continue; - } - - unsigned int mixSamples = std::min(ss->sampleCount, samples); - float volume = ss->owner->GetVolume(); - - for (unsigned int i = 0; i < mixSamples; ++i) - buffer[i] = (buffer[i] + (ss->samples[i] * volume)); - - ss->sampleCount -= mixSamples; - ss->samples += mixSamples; - - ++itt; - } -} - -void CCoreAudioAE::GarbageCollect() -{ -#if defined(TARGET_DARWIN_OSX) - if (CSettings::Get().GetInt("audiooutput.streamsilence") != 0) - return; - - if (!m_streamsPlaying && m_playing_sounds.empty()) - { - if (!m_softSuspend) - { - m_softSuspend = true; - m_softSuspendTimer = XbmcThreads::SystemClockMillis() + 10000; //10.0 second delay for softSuspend - } - } - else - { - if (m_isSuspended) - { - CSingleLock engineLock(m_engineLock); - CLog::Log(LOGDEBUG, "CCoreAudioAE::GarbageCollect - Acquire CA HAL."); - Start(); - m_isSuspended = false; - } - m_softSuspend = false; - } - - unsigned int curSystemClock = XbmcThreads::SystemClockMillis(); - if (!m_isSuspended && m_softSuspend && curSystemClock > m_softSuspendTimer) - { - Suspend();// locks m_engineLock internally - CLog::Log(LOGDEBUG, "CCoreAudioAE::GarbageCollect - Release CA HAL."); - } -#endif // TARGET_DARWIN_OSX -} - -void CCoreAudioAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough) -{ - if (m_isSuspended && !m_softSuspend) - return; - - HAL->EnumerateOutputDevices(devices, passthrough); -} - -void CCoreAudioAE::Start() -{ - if (!m_Initialized) - return; - - HAL->Start(); -} - -void CCoreAudioAE::Stop() -{ - if (!m_Initialized) - return; - - HAL->Stop(); -} - -bool CCoreAudioAE::Suspend() -{ - CSingleLock engineLock(m_engineLock); - CLog::Log(LOGDEBUG, "CCoreAudioAE::Suspend - Suspending AE processing"); - m_isSuspended = true; - // stop all gui sounds - StopAllSounds(); - // stop the CA thread - Stop(); - - return true; -} - -bool CCoreAudioAE::Resume() -{ - // fire up the engine again - bool ret = Initialize(); - CLog::Log(LOGDEBUG, "CCoreAudioAE::Resume - Resuming AE processing"); - m_isSuspended = false; - - return ret; -} - -//*********************************************************************************************** -// Rendering Methods -//*********************************************************************************************** -OSStatus CCoreAudioAE::OnRender(AudioUnitRenderActionFlags *actionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) -{ - UInt32 frames = inNumberFrames; - - unsigned int rSamples = frames * m_chLayoutCount; - int size = frames * m_format.m_frameSize; - //int size = frames * HAL->m_BytesPerFrame; - - for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) - bzero(ioData->mBuffers[i].mData, ioData->mBuffers[i].mDataByteSize); - - if (!m_Initialized) - { - m_callbackRunning = false; - return noErr; - } - - CSingleLock callbackLock(m_callbackLock); - - m_callbackRunning = true; - - /* - CSingleLock streamLock(m_streamLock); - // Remove any destroyed stream - if (!m_streams.empty()) - { - for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end();) - { - CCoreAudioAEStream *stream = *itt; - - if (stream->IsDestroyed()) - { - itt = m_streams.erase(itt); - delete stream; - continue; - } - ++itt; - } - } - streamLock.Leave(); - */ - - // when not in passthrough output mix sounds - if (!m_rawPassthrough && m_soundMode != AE_SOUND_OFF) - { - MixSounds((float *)ioData->mBuffers[0].mData, rSamples); - ioData->mBuffers[0].mDataByteSize = size; - if (!size && actionFlags) - *actionFlags |= kAudioUnitRenderAction_OutputIsSilence; - } - - m_callbackRunning = false; - - return noErr; -} - -// Static Callback from AudioUnit -OSStatus CCoreAudioAE::Render(AudioUnitRenderActionFlags* actionFlags, - const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pBufList) -{ - OSStatus ret = OnRender(actionFlags, pTimeStamp, busNumber, frameCount, pBufList); - - return ret; -} - - diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.h deleted file mode 100644 index 3f465c457c..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.h +++ /dev/null @@ -1,181 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include <list> -#include <map> - -#include "system.h" - -#include "cores/AudioEngine/Interfaces/AE.h" -#include "ICoreAudioAEHAL.h" -#include "ICoreAudioSource.h" -#include "CoreAudioAEStream.h" -#include "CoreAudioAESound.h" -#include "threads/CriticalSection.h" - -#if defined(TARGET_DARWIN_IOS) -#include "CoreAudioAEHALIOS.h" -#else -#include "CoreAudioAEHALOSX.h" -#endif - -#define COREAUDIO_IS_RAW(x) \ -( \ - (x) == AE_FMT_AC3 || \ - (x) == AE_FMT_DTS || \ - (x) == AE_FMT_LPCM || \ - (x) == AE_FMT_EAC3 || \ - (x) == AE_FMT_DTSHD || \ - (x) == AE_FMT_TRUEHD \ -) - -#if defined(TARGET_DARWIN_IOS) -# define CCoreAudioAEHAL CCoreAudioAEHALIOS -#else -# define CCoreAudioAEHAL CCoreAudioAEHALOSX -#endif - -class CCoreAudioAEStream; -class CCoreAudioAESound; -class CCoreAudioAEEventThread; - -class CCoreAudioAE : public IAE, public ICoreAudioSource -{ -protected: - friend class CAEFactory; - CCoreAudioAE(); - virtual ~CCoreAudioAE(); - - // Give the HAL access to the engine - friend class CCoreAudioAEHAL; - CCoreAudioAEHAL *HAL; - -public: - virtual void Shutdown(); - - virtual bool Initialize(); - virtual void OnSettingsChange(const std::string& setting); - - virtual bool Suspend(); /* Suspend output and de-initialize "hog-mode" sink for external players and power savings */ - virtual bool Resume(); /* Resume ouput and re-initialize sink after Suspend() above */ - virtual bool IsSuspended(); /* Returns true if in Suspend mode - used by players */ - - unsigned int GetSampleRate(); - unsigned int GetEncodedSampleRate(); - CAEChannelInfo GetChannelLayout(); - unsigned int GetChannelCount(); - enum AEDataFormat GetDataFormat(); - AEAudioFormat GetAudioFormat(); - - virtual double GetDelay(); - virtual float GetVolume(); - virtual void SetVolume(float volume); - virtual void SetMute(const bool enabled); - virtual bool IsMuted(); - virtual void SetSoundMode(const int mode); - virtual bool SupportsRaw(AEDataFormat format); - virtual bool IsSettingVisible(const std::string &settingId); - virtual bool SupportsDrain() { return true; } - - CCoreAudioAEHAL* GetHAL(); - - // returns a new stream for data in the specified format - virtual IAEStream* MakeStream(enum AEDataFormat dataFormat, - unsigned int sampleRate,unsigned int encodedSamplerate, - CAEChannelInfo channelLayout, unsigned int options = 0); - - virtual IAEStream* FreeStream(IAEStream *stream); - - // returns a new sound object - virtual IAESound* MakeSound(const std::string& file); - void StopAllSounds(); - virtual void FreeSound(IAESound *sound); - virtual void PlaySound(IAESound *sound); - virtual void StopSound(IAESound *sound); - void MixSounds(float *buffer, unsigned int samples); - - // free's sounds that have expired - virtual void GarbageCollect(); - - virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough); - - virtual OSStatus Render(AudioUnitRenderActionFlags* actionFlags, - const AudioTimeStamp* pTimeStamp, UInt32 busNumber, - UInt32 frameCount, AudioBufferList* pBufList); - - void AudioDevicesChanged(); - - -private: - CCriticalSection m_callbackLock; - CCriticalSection m_engineLock; - CCriticalSection m_streamLock; - CCriticalSection m_soundLock; - CCriticalSection m_soundSampleLock; - - // currently playing sounds - typedef struct { - CCoreAudioAESound *owner; - float *samples; - unsigned int sampleCount; - } SoundState; - - typedef std::list<CCoreAudioAEStream*> StreamList; - typedef std::list<CCoreAudioAESound* > SoundList; - typedef std::list<SoundState > SoundStateList; - - StreamList m_streams; - SoundList m_sounds; - SoundStateList m_playing_sounds; - - // Prevent multiple init/deinit - bool m_Initialized; - bool m_deviceLost; - bool m_callbackRunning; - - AEAudioFormat m_format; - enum AEDataFormat m_lastStreamFormat; - unsigned int m_lastChLayoutCount; - unsigned int m_lastSampleRate; - unsigned int m_chLayoutCount; - bool m_rawPassthrough; - bool m_transcode; - - enum AEStdChLayout m_stdChLayout; - - bool OpenCoreAudio(unsigned int sampleRate, bool forceRaw, enum AEDataFormat rawDataFormat, bool forceTranscode); - void Deinitialize(); - void Start(); - void Stop(); - - OSStatus OnRender(AudioUnitRenderActionFlags *actionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, - UInt32 inNumberFrames, AudioBufferList *ioData); - - float m_volume; - float m_volumeBeforeMute; - bool m_muted; - int m_soundMode; - bool m_streamsPlaying; - bool m_isSuspended; - bool m_softSuspend; - unsigned int m_softSuspendTimer; -}; diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALIOS.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALIOS.cpp deleted file mode 100644 index 879b56d535..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALIOS.cpp +++ /dev/null @@ -1,1342 +0,0 @@ -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#if defined(TARGET_DARWIN_IOS) -#include "system.h" - -#include "CoreAudioAEHALIOS.h" - -#include "xbmc/cores/AudioEngine/Utils/AEUtil.h" -#include "AEFactory.h" -#include "CoreAudioAE.h" -#include "utils/log.h" - -#include <math.h> - -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - -// use the maximum frames per slice allows audio play when the screen is locked -#define BUFFERED_FRAMES 4096 - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CIOSCoreAudioHardware -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -AudioComponentInstance CIOSCoreAudioHardware::FindAudioDevice(std::string searchName) -{ - if (!searchName.length()) - return 0; - - AudioComponentInstance defaultDevice = GetDefaultOutputDevice(); - - return defaultDevice; -} - -AudioComponentInstance CIOSCoreAudioHardware::GetDefaultOutputDevice() -{ - AudioComponentInstance ret = (AudioComponentInstance)1; - - return ret; -} - -UInt32 CIOSCoreAudioHardware::GetOutputDevices(IOSCoreAudioDeviceList* pList) -{ - if (!pList) - return 0; - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CCoreAudioUnit -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -CCoreAudioUnit::CCoreAudioUnit() : -m_pSource (NULL ), -m_audioUnit (NULL ), -m_audioNode (NULL ), -m_audioGraph (NULL ), -m_Initialized (false ), -m_renderProc (NULL ), -m_busNumber (INVALID_BUS ) -{ -} - -CCoreAudioUnit::~CCoreAudioUnit() -{ - Close(); -} - -bool CCoreAudioUnit::Open(AUGraph audioGraph, AudioComponentDescription desc) -{ - if (m_audioUnit) - Close(); - - OSStatus ret; - - m_Initialized = false; - - ret = AUGraphAddNode(audioGraph, &desc, &m_audioNode); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error add m_outputNode. Error = %s", GetError(ret).c_str()); - return false; - } - - ret = AUGraphNodeInfo(audioGraph, m_audioNode, NULL, &m_audioUnit); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error getting m_outputNode. Error = %s", GetError(ret).c_str()); - return false; - } - - m_audioGraph = audioGraph; - m_Initialized = true; - - Start(); - - return true; -} - -bool CCoreAudioUnit::Open(AUGraph audioGraph, OSType type, OSType subType, OSType manufacturer) -{ - AudioComponentDescription desc; - desc.componentType = type; - desc.componentSubType = subType; - desc.componentManufacturer = manufacturer; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - return Open(audioGraph, desc); -} - -void CCoreAudioUnit::Close() -{ - if (!m_Initialized && !m_audioUnit) - return; - - if (m_renderProc) - SetInputSource(NULL); - - Stop(); - - if (m_busNumber != INVALID_BUS) - { - OSStatus ret = AUGraphDisconnectNodeInput(m_audioGraph, m_audioNode, m_busNumber); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::Close: Unable to disconnect AudioUnit. Error = %s", GetError(ret).c_str()); - } - - ret = AUGraphRemoveNode(m_audioGraph, m_audioNode); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::Close: Unable to disconnect AudioUnit. Error = %s", GetError(ret).c_str()); - } - } - - AUGraphUpdate(m_audioGraph, NULL); - - m_Initialized = false; - m_audioUnit = NULL; - m_audioNode = NULL; - m_pSource = NULL; -} - -bool CCoreAudioUnit::GetFormat(AudioStreamBasicDescription* pDesc, AudioUnitScope scope, AudioUnitElement bus) -{ - if (!m_audioUnit || !pDesc) - return false; - - UInt32 size = sizeof(AudioStreamBasicDescription); - OSStatus ret = AudioUnitGetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope, bus, pDesc, &size); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::GetFormat: Unable to get AudioUnit format. Bus : %d Scope : %d : Error = %s", (int)scope, (int)bus, GetError(ret).c_str()); - return false; - } - return true; -} - -bool CCoreAudioUnit::SetFormat(AudioStreamBasicDescription* pDesc, AudioUnitScope scope, AudioUnitElement bus) -{ - if (!m_audioUnit || !pDesc) - return false; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope, bus, pDesc, sizeof(AudioStreamBasicDescription)); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetFormat: Unable to set AudioUnit format. Bus : %d Scope : %d : Error = %s", (int)scope, (int)bus, GetError(ret).c_str()); - return false; - } - return true; -} - -bool CCoreAudioUnit::SetMaxFramesPerSlice(UInt32 maxFrames) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFrames, sizeof(UInt32)); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetMaxFramesPerSlice: Unable to set AudioUnit max frames per slice. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - -bool CCoreAudioUnit::SetInputSource(ICoreAudioSource* pSource) -{ - m_pSource = pSource; - if (pSource) - return SetRenderProc(); - else - return RemoveRenderProc(); -} - -bool CCoreAudioUnit::SetRenderProc() -{ - if (!m_audioUnit || m_renderProc) - return false; - - AURenderCallbackStruct callbackInfo; - callbackInfo.inputProc = RenderCallback; // Function to be called each time the AudioUnit needs data - callbackInfo.inputProcRefCon = this; // Pointer to be returned in the callback proc - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, &callbackInfo, sizeof(AURenderCallbackStruct)); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetRenderProc: Unable to set AudioUnit render callback. Error = %s", GetError(ret).c_str()); - return false; - } - - m_renderProc = RenderCallback; - - return true; -} - -bool CCoreAudioUnit::RemoveRenderProc() -{ - if (!m_audioUnit || !m_renderProc) - return false; - - - AURenderCallbackStruct callbackInfo; - callbackInfo.inputProc = nil; - callbackInfo.inputProcRefCon = nil; - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, &callbackInfo, sizeof(AURenderCallbackStruct)); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::RemoveRenderProc: Unable to remove AudioUnit render callback. Error = %s", GetError(ret).c_str()); - return false; - } - - m_renderProc = NULL; - - Sleep(100); - - return true; -} - -OSStatus CCoreAudioUnit::RenderCallback(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData) -{ - OSStatus ret = noErr; - CCoreAudioUnit *audioUnit = (CCoreAudioUnit*)inRefCon; - - if (audioUnit->m_pSource) - { - ret = audioUnit->m_pSource->Render(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); - } - else - { - ioData->mBuffers[0].mDataByteSize = 0; - if (ioActionFlags) - *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence; - } - - - return ret; -} - -void CCoreAudioUnit::GetFormatDesc(AEAudioFormat format, - AudioStreamBasicDescription *streamDesc) -{ - unsigned int bps = CAEUtil::DataFormatToBits(format.m_dataFormat); - - // Set the input stream format for the AudioUnit - // We use the default DefaultOuput AudioUnit, so we only can set the input stream format. - // The autput format is automaticaly set to the input format. - streamDesc->mFormatID = kAudioFormatLinearPCM; // Data encoding format - streamDesc->mFormatFlags = kLinearPCMFormatFlagIsPacked; - switch (format.m_dataFormat) - { - case AE_FMT_FLOAT: - streamDesc->mFormatFlags |= kAudioFormatFlagsNativeEndian; - streamDesc->mFormatFlags |= kAudioFormatFlagIsFloat; - break; - case AE_FMT_S16NE: - case AE_FMT_AC3: - case AE_FMT_DTS: - case AE_FMT_DTSHD: - case AE_FMT_TRUEHD: - case AE_FMT_EAC3: - streamDesc->mFormatFlags |= kAudioFormatFlagsNativeEndian; - streamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; - break; - case AE_FMT_S16LE: - streamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; - break; - case AE_FMT_S16BE: - streamDesc->mFormatFlags |= kAudioFormatFlagIsBigEndian; - streamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; - break; - default: - streamDesc->mFormatFlags |= kAudioFormatFlagsNativeEndian; - streamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; - break; - } - streamDesc->mChannelsPerFrame = format.m_channelLayout.Count(); // Number of interleaved audiochannels - streamDesc->mSampleRate = (Float64)format.m_sampleRate; // the sample rate of the audio stream - streamDesc->mBitsPerChannel = bps; // Number of bits per sample, per channel - streamDesc->mBytesPerFrame = (bps>>3) * format.m_channelLayout.Count(); // Size of a frame == 1 sample per channel - streamDesc->mFramesPerPacket = 1; // The smallest amount of indivisible data. Always 1 for uncompressed audio - streamDesc->mBytesPerPacket = streamDesc->mBytesPerFrame * streamDesc->mFramesPerPacket; - streamDesc->mReserved = 0; -} - -float CCoreAudioUnit::GetLatency() -{ - if (!m_audioUnit) - return 0.0f; - - //kAudioSessionProperty_CurrentHardwareIOBufferDuration - //kAudioSessionProperty_CurrentHardwareOutputLatency - - Float32 preferredBufferSize = 0.0f; - UInt32 size = sizeof(preferredBufferSize); - AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency, &size, &preferredBufferSize); - return preferredBufferSize; -} - -bool CCoreAudioUnit::SetSampleRate(Float64 sampleRate, AudioUnitScope scope, AudioUnitElement bus) -{ - if (!m_audioUnit) - return false; - - UInt32 size = sizeof(Float64); - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_SampleRate, scope, bus, &sampleRate, size); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetSampleRate: Unable to set AudioUnit format. Bus : %d Scope : %d : Error = %s", (int)scope, (int)bus, GetError(ret).c_str()); - return false; - } - return true; -} - -bool CCoreAudioUnit::Stop() -{ - if (!m_audioUnit) - return false; - - AudioOutputUnitStop(m_audioUnit); - - return true; -} - -bool CCoreAudioUnit::Start() -{ - if (!m_audioUnit) - return false; - - AudioOutputUnitStart(m_audioUnit); - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CAUOutputDevice -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -CAUOutputDevice::CAUOutputDevice() -{ -} - -CAUOutputDevice::~CAUOutputDevice() -{ -} - -/* -Float32 CAUOutputDevice::GetCurrentVolume() -{ - if (!m_audioUnit) - return 0.0f; - - Float32 volPct = 0.0f; - OSStatus ret = AudioUnitGetParameter(m_audioUnit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, &volPct); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::GetCurrentVolume: Unable to get AudioUnit volume. Error = %s", GetError(ret).c_str()); - return 0.0f; - } - return volPct; -} - -bool CAUOutputDevice::SetCurrentVolume(Float32 vol) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetParameter(m_audioUnit, kHALOutputParam_Volume, - kAudioUnitScope_Global, 0, vol, 0); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetCurrentVolume: Unable to set AudioUnit volume. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} -*/ - -UInt32 CAUOutputDevice::GetBufferFrameSize() -{ - if (!m_audioUnit) - return 0; - - return BUFFERED_FRAMES; -} - -bool CAUOutputDevice::EnableInputOuput() -{ - if (!m_audioUnit) - return false; - - OSStatus ret; - UInt32 enable; - UInt32 hasio = 0; - UInt32 size=sizeof(UInt32); - - ret = AudioUnitGetProperty(m_audioUnit,kAudioOutputUnitProperty_HasIO,kAudioUnitScope_Input, 1, &hasio, &size); - - if (!ret && hasio) - { - enable = 1; - ret = AudioUnitSetProperty(m_audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &enable, sizeof(enable)); - if (ret) - { - CLog::Log(LOGERROR, "CAUOutputDevice::EnableInputOuput:: Unable to enable input on bus 1. Error = %s", GetError(ret).c_str()); - return false; - } - - enable = 1; - ret = AudioUnitSetProperty(m_audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &enable, sizeof(enable)); - if (ret) - { - CLog::Log(LOGERROR, "CAUOutputDevice::EnableInputOuput:: Unable to disable output on bus 0. Error = %s", GetError(ret).c_str()); - return false; - } - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CAUMultiChannelMixer -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -CAUMultiChannelMixer::CAUMultiChannelMixer() -{ -} - -CAUMultiChannelMixer::~CAUMultiChannelMixer() -{ - -} - -UInt32 CAUMultiChannelMixer::GetInputBusCount() -{ - if (!m_audioUnit) - return 0; - - UInt32 busCount = 0; - UInt32 size = sizeof(busCount); - OSStatus ret = AudioUnitGetProperty(m_audioUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, &size); - if (ret) - { - CLog::Log(LOGERROR, "CAUMultiChannelMixer::GetInputBusCount: Unable to get input bus count. Error = %s", GetError(ret).c_str()); - return 0; - } - return busCount; -} - -bool CAUMultiChannelMixer::SetInputBusFormat(UInt32 busCount, AudioStreamBasicDescription *pFormat) -{ - if (!m_audioUnit) - return false; - - for (UInt32 i = 0; i < busCount; i++) - { - if (!SetFormat(pFormat, kAudioUnitScope_Input, i)) - return false; - } - - return true; -} - -bool CAUMultiChannelMixer::SetInputBusCount(UInt32 busCount) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(UInt32)); - if (ret) - { - CLog::Log(LOGERROR, "CAUMultiChannelMixer::SetInputBusCount: Unable to set input bus count. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - -UInt32 CAUMultiChannelMixer::GetOutputBusCount() -{ - if (!m_audioUnit) - return 0; - - UInt32 busCount = 0; - UInt32 size = sizeof(busCount); - OSStatus ret = AudioUnitGetProperty(m_audioUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Output, 0, &busCount, &size); - if (ret) - { - CLog::Log(LOGERROR, "CAUMultiChannelMixer::GetOutputBusCount: Unable to get output bus count. Error = %s", GetError(ret).c_str()); - return 0; - } - return busCount; -} - -bool CAUMultiChannelMixer::SetOutputBusCount(UInt32 busCount) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Output, 0, &busCount, sizeof(UInt32)); - if (ret) - { - CLog::Log(LOGERROR, "CAUMultiChannelMixer::SetOutputBusCount: Unable to set output bus count. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - -Float32 CAUMultiChannelMixer::GetCurrentVolume() -{ - - if (!m_audioUnit) - return false; - - Float32 volPct = 0.0f; - OSStatus ret = AudioUnitGetParameter(m_audioUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, kInputBus, &volPct); - if (ret) - { - CLog::Log(LOGERROR, "CAUMultiChannelMixer::GetCurrentVolume: Unable to get Mixer volume. Error = %s", GetError(ret).c_str()); - return 0.0f; - } - return volPct; - -} - -bool CAUMultiChannelMixer::SetCurrentVolume(Float32 vol) -{ - - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetParameter(m_audioUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Output, kOutputBus, vol, 0); - if (ret) - { - CLog::Log(LOGERROR, "CAUMultiChannelMixer::SetCurrentVolume: Unable to set Mixer volume. Error = %s", GetError(ret).c_str()); - return false; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CCoreAudioGraph -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -CCoreAudioGraph::CCoreAudioGraph() : -m_audioGraph (NULL ), -m_audioUnit (NULL ), -m_mixerUnit (NULL ), -m_inputUnit (NULL ), -m_initialized (false), -m_allowMixing (false) -{ - for (int i = 0; i < MAX_CONNECTION_LIMIT; i++) - { - m_reservedBusNumber[i] = false; - } -} - -CCoreAudioGraph::~CCoreAudioGraph() -{ - Close(); -} - -bool CCoreAudioGraph::Open(ICoreAudioSource *pSource, AEAudioFormat &format, bool allowMixing, float initVolume) -{ - OSStatus ret; - - AudioStreamBasicDescription inputFormat; - AudioStreamBasicDescription outputFormat; - - m_allowMixing = allowMixing; - - ret = NewAUGraph(&m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error create audio grpah. Error = %s", GetError(ret).c_str()); - return false; - } - ret = AUGraphOpen(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error open audio grpah. Error = %s", GetError(ret).c_str()); - return false; - } - - // get output unit - if (m_audioUnit) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error audio unit already open. double call ?"); - return false; - } - - m_audioUnit = new CAUOutputDevice(); - if (!m_audioUnit->Open(m_audioGraph, kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, kAudioUnitManufacturer_Apple)) - return false; - - UInt32 bufferFrames = m_audioUnit->GetBufferFrameSize(); - - if (!m_audioUnit->EnableInputOuput()) - return false; - - m_audioUnit->SetMaxFramesPerSlice(bufferFrames); - - m_audioUnit->GetFormatDesc(format, &inputFormat); - - //if(!allowMixing) - //{ - if (!m_audioUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) - return false; - - if (!m_audioUnit->SetFormat(&inputFormat, kAudioUnitScope_Output, kInputBus)) - return false; - //} - - if (allowMixing) - { - // get mixer unit - if (m_mixerUnit) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error mixer unit already open. double call ?"); - return false; - } - - m_mixerUnit = new CAUMultiChannelMixer(); - - if (!m_mixerUnit->Open(m_audioGraph, kAudioUnitType_Mixer, kAudioUnitSubType_MultiChannelMixer, kAudioUnitManufacturer_Apple)) - return false; - - m_mixerUnit->SetMaxFramesPerSlice(bufferFrames); - - // set number of input buses - if (!m_mixerUnit->SetInputBusCount(MAX_CONNECTION_LIMIT)) - return false; - - //if(!m_mixerUnit->SetFormat(&fmt, kAudioUnitScope_Output, kOutputBus)) - // return false; - - m_mixerUnit->SetBus(0); - - if (!m_audioUnit->GetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) - return false; - - /* - if(!m_mixerUnit->SetInputBusFormat(MAX_CONNECTION_LIMIT, &outputFormat)) - return false; - */ - - ret = AUGraphConnectNodeInput(m_audioGraph, m_mixerUnit->GetNode(), 0, m_audioUnit->GetNode(), 0); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error connecting m_m_mixerNode. Error = %s", GetError(ret).c_str()); - return false; - } - - // get output unit - if (m_inputUnit) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error mixer unit already open. double call ?"); - return false; - } - - m_inputUnit = new CAUOutputDevice(); - - if (!m_inputUnit->Open(m_audioGraph, kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple)) - return false; - - m_inputUnit->SetMaxFramesPerSlice(bufferFrames); - - if (!m_inputUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) - return false; - - /* - if(!m_inputUnit->SetFormat(&outputFormat, kAudioUnitScope_Output, kOutputBus)) - return false; - */ - - // configure output unit - int busNumber = GetFreeBus(); - - ret = AUGraphConnectNodeInput(m_audioGraph, m_inputUnit->GetNode(), 0, m_mixerUnit->GetNode(), busNumber); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error connecting m_converterNode. Error = %s", GetError(ret).c_str()); - return false; - } - - m_inputUnit->SetBus(busNumber); - - ret = AUGraphUpdate(m_audioGraph, NULL); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error update graph. Error = %s", GetError(ret).c_str()); - return false; - } - ret = AUGraphInitialize(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error initialize graph. Error = %s", GetError(ret).c_str()); - return false; - } - - // Regenerate audio format and copy format for the Output AU - } - - ret = AUGraphUpdate(m_audioGraph, NULL); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error update graph. Error = %s", GetError(ret).c_str()); - return false; - } - - std::string formatString; - AudioStreamBasicDescription inputDesc_end, outputDesc_end; - m_audioUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); - m_audioUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kInputBus); - CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputDesc_end, formatString)); - CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputDesc_end, formatString)); - - if (m_mixerUnit) - { - m_mixerUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); - m_mixerUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kOutputBus); - CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputDesc_end, formatString)); - CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputDesc_end, formatString)); - } - - if (m_inputUnit) - { - m_inputUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); - m_inputUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kOutputBus); - CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputDesc_end, formatString)); - CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputDesc_end, formatString)); - } - - ret = AUGraphInitialize(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error initialize graph. Error = %s", GetError(ret).c_str()); - return false; - } - - SetCurrentVolume(initVolume); - - SetInputSource(pSource); - - ShowGraph(); - - return Start(); -} - -bool CCoreAudioGraph::Close() -{ - if (!m_audioGraph) - return false; - - OSStatus ret; - - Stop(); - - SetInputSource(NULL); - - while (!m_auUnitList.empty()) - { - CAUOutputDevice *d = m_auUnitList.front(); - m_auUnitList.pop_front(); - ReleaseBus(d->GetBus()); - d->Close(); - delete d; - } - - if (m_inputUnit) - { - ReleaseBus(m_inputUnit->GetBus()); - m_inputUnit->Close(); - delete m_inputUnit; - m_inputUnit = NULL; - } - - if (m_mixerUnit) - { - m_mixerUnit->Close(); - delete m_mixerUnit; - m_mixerUnit = NULL; - } - - if (m_audioUnit) - { - m_audioUnit->Close(); - delete m_audioUnit; - m_audioUnit = NULL; - } - - ret = AUGraphUninitialize(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Close: Error unitialize. Error = %s", GetError(ret).c_str()); - } - - ret = AUGraphClose(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Close: Error close. Error = %s", GetError(ret).c_str()); - } - - ret = DisposeAUGraph(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Close: Error dispose. Error = %s", GetError(ret).c_str()); - } - - return true; -} - -bool CCoreAudioGraph::Start() -{ - if (!m_audioGraph) - return false; - - OSStatus ret; - Boolean isRunning = false; - - ret = AUGraphIsRunning(m_audioGraph, &isRunning); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Start: Audio graph not running. Error = %s", GetError(ret).c_str()); - return false; - } - if (!isRunning) - { - - if (m_audioUnit) - m_audioUnit->Start(); - if (m_mixerUnit) - m_mixerUnit->Start(); - if (m_inputUnit) - m_inputUnit->Start(); - - ret = AUGraphStart(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Start: Error starting audio graph. Error = %s", GetError(ret).c_str()); - } - ShowGraph(); - } - - return true; -} - -bool CCoreAudioGraph::Stop() -{ - if (!m_audioGraph) - return false; - - OSStatus ret; - Boolean isRunning = false; - - ret = AUGraphIsRunning(m_audioGraph, &isRunning); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Stop: Audio graph not running. Error = %s", GetError(ret).c_str()); - return false; - } - if (isRunning) - { - - if (m_inputUnit) - m_inputUnit->Stop(); - if (m_mixerUnit) - m_mixerUnit->Stop(); - if (m_audioUnit) - m_audioUnit->Stop(); - - ret = AUGraphStop(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Stop: Error stopping audio graph. Error = %s", GetError(ret).c_str()); - } - } - - return true; -} - -bool CCoreAudioGraph::SetInputSource(ICoreAudioSource* pSource) -{ - if (m_inputUnit) - return m_inputUnit->SetInputSource(pSource); - else if (m_audioUnit) - return m_audioUnit->SetInputSource(pSource); - - return false; -} - -bool CCoreAudioGraph::SetCurrentVolume(Float32 vol) -{ - if (!m_mixerUnit) - return false; - - return m_mixerUnit->SetCurrentVolume(vol); -} - -CAUOutputDevice *CCoreAudioGraph::DestroyUnit(CAUOutputDevice *outputUnit) -{ - if (!outputUnit) - return NULL; - - Stop(); - - for (AUUnitList::iterator itt = m_auUnitList.begin(); itt != m_auUnitList.end(); ++itt) - if (*itt == outputUnit) - { - m_auUnitList.erase(itt); - break; - } - - ReleaseBus(outputUnit->GetBus()); - outputUnit->Close(); - delete outputUnit; - - AUGraphUpdate(m_audioGraph, NULL); - - printf("Remove unit\n\n"); - ShowGraph(); - printf("\n"); - - Start(); - - return NULL; -} - -CAUOutputDevice *CCoreAudioGraph::CreateUnit(AEAudioFormat &format) -{ - if (!m_audioUnit || !m_mixerUnit) - return NULL; - - std::string formatString; - AudioStreamBasicDescription inputFormat; - AudioStreamBasicDescription outputFormat; - - OSStatus ret; - - int busNumber = GetFreeBus(); - if (busNumber == INVALID_BUS) - return NULL; - - // create output unit - CAUOutputDevice *outputUnit = new CAUOutputDevice(); - if (!outputUnit->Open(m_audioGraph, kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple)) - goto error; - - outputUnit->SetMaxFramesPerSlice(m_audioUnit->GetBufferFrameSize()); - - m_audioUnit->GetFormatDesc(format, &inputFormat); - - // get the format frm the mixer - if (!m_mixerUnit->GetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) - goto error; - - if (!outputUnit->SetFormat(&outputFormat, kAudioUnitScope_Output, kOutputBus)) - goto error; - - if (!outputUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) - goto error; - - ret = AUGraphConnectNodeInput(m_audioGraph, outputUnit->GetNode(), 0, m_mixerUnit->GetNode(), busNumber); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::CreateUnit: Error connecting outputUnit. Error = %s", GetError(ret).c_str()); - goto error; - } - - // TODO: setup mixmap, get free bus number for connection - - outputUnit->SetBus(busNumber); - - AUGraphUpdate(m_audioGraph, NULL); - - printf("Add unit\n\n"); - ShowGraph(); - printf("\n"); - - CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputFormat, formatString)); - CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputFormat, formatString)); - - m_auUnitList.push_back(outputUnit); - - return outputUnit; - -error: - delete outputUnit; - return NULL; -} - -int CCoreAudioGraph::GetFreeBus() -{ - for (int i = 0; i < MAX_CONNECTION_LIMIT; i++) - { - if (!m_reservedBusNumber[i]) - { - m_reservedBusNumber[i] = true; - return i; - } - } - return INVALID_BUS; -} - -void CCoreAudioGraph::ReleaseBus(int busNumber) -{ - if (busNumber > MAX_CONNECTION_LIMIT || busNumber < 0) - return; - - m_reservedBusNumber[busNumber] = false; -} - -bool CCoreAudioGraph::IsBusFree(int busNumber) -{ - if (busNumber > MAX_CONNECTION_LIMIT || busNumber < 0) - return false; - return m_reservedBusNumber[busNumber]; -} - -int CCoreAudioGraph::GetMixerChannelOffset(int busNumber) -{ - if (!m_mixerUnit) - return 0; - - int offset = 0; - AudioStreamBasicDescription fmt; - - for (int i = 0; i < busNumber; i++) - { - memset(&fmt, 0x0, sizeof(fmt)); - m_mixerUnit->GetFormat(&fmt, kAudioUnitScope_Input, busNumber); - offset += fmt.mChannelsPerFrame; - } - return offset; -} - -void CCoreAudioGraph::ShowGraph() -{ - CAShow(m_audioGraph); -} - -float CCoreAudioGraph::GetLatency() -{ - float delay = 0.0f; - - if (m_audioUnit) - delay += m_audioUnit->GetLatency(); - - return delay; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CCoreAudioAEHALIOS -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -CCoreAudioAEHALIOS::CCoreAudioAEHALIOS() : -m_audioGraph (NULL ), -m_Initialized (false ), -m_Passthrough (false ), -m_allowMixing (false ), -m_encoded (false ), -m_initVolume (1.0f ), -m_NumLatencyFrames (0 ), -m_OutputBufferIndex (0 ), -m_ae (NULL ) -{ -} - -CCoreAudioAEHALIOS::~CCoreAudioAEHALIOS() -{ - Deinitialize(); - - delete m_audioGraph; -} - -bool CCoreAudioAEHALIOS::InitializePCM(ICoreAudioSource *pSource, AEAudioFormat &format, bool allowMixing) -{ - - if (m_audioGraph) - { - m_audioGraph->Close(); - delete m_audioGraph; - } - m_audioGraph = new CCoreAudioGraph(); - - if (!m_audioGraph) - return false; - - if (!m_audioGraph->Open(pSource, format, allowMixing, m_initVolume)) - { - CLog::Log(LOGERROR, "CCoreAudioAEHALIOS::Initialize: Unable to initialize audio due a missconfiguration. Try 2.0 speaker configuration."); - return false; - } - - m_NumLatencyFrames = 0; - - m_allowMixing = allowMixing; - - return true; -} - -bool CCoreAudioAEHALIOS::InitializePCMEncoded(ICoreAudioSource *pSource, AEAudioFormat &format) -{ - if (!InitializePCM(pSource, format, false)) - return false; - - return true; -} - -bool CCoreAudioAEHALIOS::Initialize(ICoreAudioSource *ae, bool passThrough, AEAudioFormat &format, AEDataFormat rawDataFormat, std::string &device, float initVolume) -{ - m_ae = (CCoreAudioAE *)ae; - - if (!m_ae) - return false; - - m_initformat = format; - m_Passthrough = passThrough; - m_encoded = false; - m_OutputBufferIndex = 0; - m_rawDataFormat = rawDataFormat; - m_initVolume = initVolume; - - if (format.m_channelLayout.Count() == 0) - { - CLog::Log(LOGERROR, "CCoreAudioAEHALIOS::Initialize - Unable to open the requested channel layout"); - return false; - } - - if (device.find("CoreAudio:")) - device.erase(0, strlen("CoreAudio:")); - - // If this is a passthrough (AC3/DTS) stream, attempt to handle it natively - if (m_Passthrough) - { - m_encoded = false; - } - - // If this is a PCM stream, or we failed to handle a passthrough stream natively, - // prepare the standard interleaved PCM interface - if (!m_encoded) - { - // If we are here and this is a passthrough stream, native handling failed. - // Try to handle it as IEC61937 data over straight PCM (DD-Wav) - bool configured = false; - if (m_Passthrough) - { - CLog::Log(LOGERROR, "CCoreAudioAEHALIOS::Initialize: No suitable AC3 output format found. Attempting DD-Wav."); - configured = InitializePCMEncoded(ae, format); - } - else - { - // Standard PCM data - configured = InitializePCM(ae, format, true); - } - - if (!configured) // No suitable output format was able to be configured - return false; - } - - if (m_audioGraph) - m_audioGraph->ShowGraph(); - - m_Initialized = true; - - return true; -} - -CAUOutputDevice *CCoreAudioAEHALIOS::DestroyUnit(CAUOutputDevice *outputUnit) -{ - if (m_audioGraph && outputUnit) - return m_audioGraph->DestroyUnit(outputUnit); - - return NULL; -} - -CAUOutputDevice *CCoreAudioAEHALIOS::CreateUnit(ICoreAudioSource *pSource, AEAudioFormat &format) -{ - CAUOutputDevice *outputUnit = NULL; - - // when HAL is using a mixer, the input is routed through converter units. - // therefore we create a converter unit attach the source and give it back. - if (m_allowMixing && m_audioGraph) - { - outputUnit = m_audioGraph->CreateUnit(format); - - if (pSource && outputUnit) - outputUnit->SetInputSource(pSource); - } - - return outputUnit; -} - -void CCoreAudioAEHALIOS::Deinitialize() -{ - if (!m_Initialized) - return; - - Stop(); - - //if (m_encoded) - - if (m_audioGraph) - m_audioGraph->SetInputSource(NULL); - - if (m_audioGraph) - { - //m_audioGraph->Close(); - delete m_audioGraph; - } - m_audioGraph = NULL; - - m_NumLatencyFrames = 0; - m_OutputBufferIndex = 0; - - m_Initialized = false; - m_Passthrough = false; -} - -void CCoreAudioAEHALIOS::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough) -{ - IOSCoreAudioDeviceList deviceList; - CIOSCoreAudioHardware::GetOutputDevices(&deviceList); - - // Add default output device if GetOutputDevices return nothing - devices.push_back(AEDevice("Default", "IOSCoreAudio:default")); - - std::string deviceName; - for (int i = 0; !deviceList.empty(); i++) - { - std::string deviceName_Internal = std::string("IOSCoreAudio:") + deviceName; - devices.push_back(AEDevice(deviceName, deviceName_Internal)); - - deviceList.pop_front(); - - } -} - -void CCoreAudioAEHALIOS::Stop() -{ - if (!m_Initialized) - return; - - m_audioGraph->Stop(); -} - -bool CCoreAudioAEHALIOS::Start() -{ - if (!m_Initialized) - return false; - - m_audioGraph->Start(); - - return true; -} - -void CCoreAudioAEHALIOS::SetDirectInput(ICoreAudioSource *pSource, AEAudioFormat &format) -{ - if (!m_Initialized) - return; - - // when HAL is initialized encoded we use directIO - // when HAL is not in encoded mode and there is no mixer attach source the audio unit - // when mixing is allowed in HAL, HAL is working with converter units where we attach the source. - - if (!m_encoded && !m_allowMixing) - { - // register render callback for the audio unit - m_audioGraph->SetInputSource(pSource); - } - - if (m_audioGraph) - m_audioGraph->ShowGraph(); - -} - -double CCoreAudioAEHALIOS::GetDelay() -{ - /* - float delay; - - delay = (float)(m_NumLatencyFrames) / (m_initformat.m_sampleRate); - - return delay; - */ - - return (double)(BUFFERED_FRAMES) / (double)(m_initformat.m_sampleRate); -} - -void CCoreAudioAEHALIOS::SetVolume(float volume) -{ - if (!m_encoded) - m_audioGraph->SetCurrentVolume(volume); -} - -unsigned int CCoreAudioAEHALIOS::GetBufferIndex() -{ - return m_OutputBufferIndex; -} - -#endif diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALIOS.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALIOS.h deleted file mode 100644 index 3e39fb4f93..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALIOS.h +++ /dev/null @@ -1,201 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#if defined(TARGET_DARWIN_IOS) - -#include <list> -#include <vector> - -#include "ICoreAudioAEHAL.h" -#include "CoreAudioAEHAL.h" -#include "utils/StdString.h" - -#include <AudioUnit/AudioUnit.h> -#include <AudioUnit/AudioUnitProperties.h> -#include <AudioToolbox/AudioToolbox.h> -#include <AudioToolbox/AudioServices.h> -#include <CoreAudio/CoreAudioTypes.h> - -#define kOutputBus 0 -#define kInputBus 1 -#define MAX_CONNECTION_LIMIT 8 -#define INVALID_BUS -1 - -// Forward declarations -class CCoreAudioAE; -class CIOSCoreAudioConverter; - -typedef std::list<AudioComponentInstance> IOSCoreAudioDeviceList; - -// There is only one AudioSystemObject instance system-side. -// Therefore, all CIOSCoreAudioHardware methods are static -class CIOSCoreAudioHardware -{ -public: - static AudioComponentInstance FindAudioDevice(std::string deviceName); - static AudioComponentInstance GetDefaultOutputDevice(); - static UInt32 GetOutputDevices(IOSCoreAudioDeviceList* pList); -}; - -class CCoreAudioUnit -{ -public: - CCoreAudioUnit(); - virtual ~CCoreAudioUnit(); - - virtual bool Open(AUGraph audioGraph, AudioComponentDescription desc); - virtual bool Open(AUGraph audioGraph, OSType type, OSType subType, OSType manufacturer); - virtual void Close(); - virtual bool SetInputSource(ICoreAudioSource* pSource); - virtual bool IsInitialized() {return m_Initialized;} - virtual bool GetFormat(AudioStreamBasicDescription* pDesc, AudioUnitScope scope, AudioUnitElement bus); - virtual bool SetFormat(AudioStreamBasicDescription* pDesc, AudioUnitScope scope, AudioUnitElement bus); - virtual bool SetMaxFramesPerSlice(UInt32 maxFrames); - virtual void GetFormatDesc(AEAudioFormat format, AudioStreamBasicDescription *streamDesc); - virtual float GetLatency(); - virtual bool SetSampleRate(Float64 sampleRate, AudioUnitScope scope, AudioUnitElement bus); - virtual bool Stop(); - virtual bool Start(); - virtual AudioUnit GetUnit (){return m_audioUnit;} - virtual AUGraph GetGraph (){return m_audioGraph;} - virtual AUNode GetNode (){return m_audioNode;} - virtual int GetBus (){return m_busNumber;} - virtual void SetBus (int busNumber){m_busNumber = busNumber;} -protected: - bool SetRenderProc(); - bool RemoveRenderProc(); - static OSStatus RenderCallback(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData); - ICoreAudioSource* m_pSource; - AudioUnit m_audioUnit; - AUNode m_audioNode; - AUGraph m_audioGraph; - bool m_Initialized; - AURenderCallback m_renderProc; - int m_busNumber; -}; - -class CAUOutputDevice : public CCoreAudioUnit -{ -public: - CAUOutputDevice(); - virtual ~CAUOutputDevice(); - UInt32 GetBufferFrameSize(); - - /* - Float32 GetCurrentVolume(); - bool SetCurrentVolume(Float32 vol); - */ - bool EnableInputOuput(); -}; - -class CAUMultiChannelMixer : public CAUOutputDevice -{ -public: - CAUMultiChannelMixer(); - virtual ~CAUMultiChannelMixer(); - - UInt32 GetInputBusCount(); - bool SetInputBusFormat(UInt32 busCount, AudioStreamBasicDescription *pFormat); - bool SetInputBusCount(UInt32 busCount); - UInt32 GetOutputBusCount(); - bool SetOutputBusCount(UInt32 busCount); - - Float32 GetCurrentVolume(); - bool SetCurrentVolume(Float32 vol); -}; - -class CCoreAudioGraph -{ -private: - AUGraph m_audioGraph; - - CAUOutputDevice *m_audioUnit; - CAUMultiChannelMixer *m_mixerUnit; - CAUOutputDevice *m_inputUnit; - - int m_reservedBusNumber[MAX_CONNECTION_LIMIT]; - bool m_initialized; - bool m_allowMixing; - - typedef std::list<CAUOutputDevice*> AUUnitList; - AUUnitList m_auUnitList; - -public: - CCoreAudioGraph(); - ~CCoreAudioGraph(); - - bool Open(ICoreAudioSource *pSource, AEAudioFormat &format, bool allowMixing, float initVolume); - bool Close(); - bool Start(); - bool Stop(); - bool SetInputSource(ICoreAudioSource* pSource); - bool SetCurrentVolume(Float32 vol); - CAUOutputDevice *DestroyUnit(CAUOutputDevice *outputUnit); - CAUOutputDevice *CreateUnit(AEAudioFormat &format); - int GetFreeBus(); - void ReleaseBus(int busNumber); - bool IsBusFree(int busNumber); - int GetMixerChannelOffset(int busNumber); - void ShowGraph(); - float GetLatency(); -}; - -class CCoreAudioAEHALIOS : public ICoreAudioAEHAL -{ -protected: - CCoreAudioGraph *m_audioGraph; - bool m_Initialized; - bool m_Passthrough; - AEAudioFormat m_initformat; - bool m_allowMixing; - bool m_encoded; - AEDataFormat m_rawDataFormat; - float m_initVolume; -public: - unsigned int m_NumLatencyFrames; - unsigned int m_OutputBufferIndex; - CCoreAudioAE *m_ae; - - CCoreAudioAEHALIOS(); - virtual ~CCoreAudioAEHALIOS(); - - virtual bool InitializePCM(ICoreAudioSource *pSource, AEAudioFormat &format, bool allowMixing); - virtual bool InitializePCMEncoded(ICoreAudioSource *pSource, AEAudioFormat &format); - virtual bool Initialize(ICoreAudioSource *ae, bool passThrough, AEAudioFormat &format, AEDataFormat rawDataFormat, std::string &device, float initVolume); - virtual void Deinitialize(); - virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough); - virtual void SetDirectInput(ICoreAudioSource *pSource, AEAudioFormat &format); - virtual void Stop(); - virtual bool Start(); - virtual double GetDelay(); - virtual void SetVolume(float volume); - virtual unsigned int GetBufferIndex(); - virtual CAUOutputDevice *DestroyUnit(CAUOutputDevice *outputUnit); - virtual CAUOutputDevice *CreateUnit(ICoreAudioSource *pSource, AEAudioFormat &format); - virtual bool AllowMixing() { return m_allowMixing; } -}; - -#endif diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.cpp deleted file mode 100644 index 10025bbde9..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.cpp +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#ifdef TARGET_DARWIN_OSX - -#include "system.h" - -#include "CoreAudioAEHALOSX.h" - -#include "CoreAudioAE.h" -#include "CoreAudioAEHAL.h" -#include "CoreAudioUnit.h" -#include "CoreAudioDevice.h" -#include "CoreAudioGraph.h" -#include "CoreAudioMixMap.h" -#include "CoreAudioHardware.h" -#include "CoreAudioChannelLayout.h" - -#include "cores/AudioEngine/Utils/AEUtil.h" -#include "utils/log.h" -#include "settings/Settings.h" - -CCoreAudioAEHALOSX::CCoreAudioAEHALOSX() : - m_audioGraph (NULL ), - m_Initialized (false ), - m_Passthrough (false ), - m_allowMixing (false ), - m_encoded (false ), - m_initVolume (1.0f ), - m_NumLatencyFrames (0 ), - m_OutputBufferIndex (0 ), - m_ae (NULL ) -{ - m_AudioDevice = new CCoreAudioDevice(); - m_OutputStream = new CCoreAudioStream(); - - SInt32 major, minor; - Gestalt(gestaltSystemVersionMajor, &major); - Gestalt(gestaltSystemVersionMinor, &minor); - - // By default, kAudioHardwarePropertyRunLoop points at the process's main thread on SnowLeopard, - // If your process lacks such a run loop, you can set kAudioHardwarePropertyRunLoop to NULL which - // tells the HAL to run it's own thread for notifications (which was the default prior to SnowLeopard). - // So tell the HAL to use its own thread for similar behavior under all supported versions of OSX. - if (major == 10 && minor >= 6) - { - CFRunLoopRef theRunLoop = NULL; - AudioObjectPropertyAddress theAddress = { - kAudioHardwarePropertyRunLoop, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - OSStatus theError = AudioObjectSetPropertyData(kAudioObjectSystemObject, - &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); - if (theError != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioAE::constructor: kAudioHardwarePropertyRunLoop error."); - } - } -} - -CCoreAudioAEHALOSX::~CCoreAudioAEHALOSX() -{ - Deinitialize(); - - delete m_audioGraph; - delete m_AudioDevice; - delete m_OutputStream; -} - -bool CCoreAudioAEHALOSX::InitializePCM(ICoreAudioSource *pSource, AEAudioFormat &format, bool allowMixing, AudioDeviceID outputDevice, bool encoded) -{ - if (m_audioGraph) - m_audioGraph->Close(), delete m_audioGraph; - m_audioGraph = new CCoreAudioGraph(); - if (!m_audioGraph) - return false; - - AudioChannelLayoutTag layout = g_LayoutMap[ CSettings::Get().GetInt("audiooutput.channels") ]; - // force optical/coax to 2.0 output channels - if (!m_Passthrough && CSettings::Get().GetInt("audiooutput.channels") == AE_CH_LAYOUT_2_0) - layout = g_LayoutMap[1]; - - if (!m_audioGraph->Open(pSource, format, outputDevice, allowMixing, layout, m_initVolume, encoded )) - { - CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::Initialize: " - "Unable to initialize audio due a missconfiguration. Try 2.0 speaker configuration."); - return false; - } - - m_NumLatencyFrames = m_AudioDevice->GetNumLatencyFrames(); - - m_allowMixing = allowMixing; - - return true; -} - -bool CCoreAudioAEHALOSX::InitializePCMEncoded(ICoreAudioSource *pSource, AEAudioFormat &format, AudioDeviceID outputDevice) -{ - // Prevent any other application from using this device. - m_AudioDevice->SetHogStatus(true); - // Try to disable mixing support. Effectiveness depends on the device. - m_AudioDevice->SetMixingSupport(false); - // Set the Sample Rate as defined by the spec. - m_AudioDevice->SetNominalSampleRate((float)format.m_sampleRate); - - if (!InitializePCM(pSource, format, false, outputDevice, true)) - return false; - - return true; -} - -bool CCoreAudioAEHALOSX::InitializeEncoded(AudioDeviceID outputDevice, AEAudioFormat &format) -{ - std::string formatString; - AudioStreamID outputStream = 0; - AudioStreamBasicDescription outputFormat = {0}; - - // Fetch a list of the streams defined by the output device - UInt32 streamIndex = 0; - AudioStreamIdList streams; - m_AudioDevice->GetStreams(&streams); - - m_OutputBufferIndex = 0; - - while (!streams.empty()) - { - // Get the next stream - CCoreAudioStream stream; - stream.Open(streams.front()); - streams.pop_front(); // We copied it, now we are done with it - - // Probe physical formats - StreamFormatList physicalFormats; - stream.GetAvailablePhysicalFormats(&physicalFormats); - while (!physicalFormats.empty()) - { - AudioStreamRangedDescription& desc = physicalFormats.front(); - CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " - "Considering Physical Format: %s", StreamDescriptionToString(desc.mFormat, formatString)); - - if (m_rawDataFormat == AE_FMT_LPCM || m_rawDataFormat == AE_FMT_DTSHD || - m_rawDataFormat == AE_FMT_TRUEHD || m_rawDataFormat == AE_FMT_EAC3) - { - // check pcm output formats - unsigned int bps = CAEUtil::DataFormatToBits(AE_FMT_S16NE); - if (desc.mFormat.mChannelsPerFrame == m_initformat.m_channelLayout.Count() && - desc.mFormat.mBitsPerChannel == bps && - desc.mFormat.mSampleRate == m_initformat.m_sampleRate ) - { - outputFormat = desc.mFormat; // Select this format - m_OutputBufferIndex = streamIndex; - outputStream = stream.GetId(); - break; - } - } - else - { - // check encoded formats - if (desc.mFormat.mFormatID == kAudioFormat60958AC3 || desc.mFormat.mFormatID == 'IAC3') - { - if (desc.mFormat.mChannelsPerFrame == m_initformat.m_channelLayout.Count() && - desc.mFormat.mSampleRate == m_initformat.m_sampleRate ) - { - outputFormat = desc.mFormat; // Select this format - m_OutputBufferIndex = streamIndex; - outputStream = stream.GetId(); - break; - } - } - } - physicalFormats.pop_front(); - } - - // TODO: How do we determine if this is the right stream (not just the right format) to use? - if (outputFormat.mFormatID) - break; // We found a suitable format. No need to continue. - streamIndex++; - } - - if (!outputFormat.mFormatID) // No match found - { - CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " - "Unable to identify suitable output format."); - return false; - } - - CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " - "Selected stream[%u] - id: 0x%04X, Physical Format: %s", - m_OutputBufferIndex, (uint)outputStream, StreamDescriptionToString(outputFormat, formatString)); - - // TODO: Auto hogging sets this for us. Figure out how/when to turn it off or use it - // It appears that leaving this set will aslo restore the previous stream format when the - // Application exits. If auto hogging is set and we try to set hog mode, we will deadlock - // From the SDK docs: "If the AudioDevice is in a non-mixable mode, the HAL will automatically take hog mode on behalf of the first process to start an IOProc." - - // Lock down the device. This MUST be done PRIOR to switching to a non-mixable format, if it is done at all - // If it is attempted after the format change, there is a high likelihood of a deadlock - // We may need to do this sooner to enable mix-disable (i.e. before setting the stream format) - - // Auto-Hog does not always un-hog the device when changing back to a mixable mode. - // Handle this on our own until it is fixed. - CCoreAudioHardware::SetAutoHogMode(false); - bool autoHog = CCoreAudioHardware::GetAutoHogMode(); - CLog::Log(LOGDEBUG, " CoreAudioRenderer::InitializeEncoded: " - "Auto 'hog' mode is set to '%s'.", autoHog ? "On" : "Off"); - if (!autoHog) // Try to handle this ourselves - { - // Hog the device if it is not set to be done automatically - m_AudioDevice->SetHogStatus(true); - // Try to disable mixing. If we cannot, it may not be a problem - m_AudioDevice->SetMixingSupport(false); - } - - m_NumLatencyFrames = m_AudioDevice->GetNumLatencyFrames(); - - // Configure the output stream object, this is the one we will keep - m_OutputStream->Open(outputStream); - - AudioStreamBasicDescription virtualFormat; - m_OutputStream->GetVirtualFormat(&virtualFormat); - CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " - "Previous Virtual Format: %s", StreamDescriptionToString(virtualFormat, formatString)); - - AudioStreamBasicDescription previousPhysicalFormat; - m_OutputStream->GetPhysicalFormat(&previousPhysicalFormat); - CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " - "Previous Physical Format: %s", StreamDescriptionToString(previousPhysicalFormat, formatString)); - - // Set the active format (the old one will be reverted when we close) - m_OutputStream->SetPhysicalFormat(&outputFormat); - m_NumLatencyFrames += m_OutputStream->GetNumLatencyFrames(); - - m_OutputStream->GetVirtualFormat(&virtualFormat); - CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " - "New Virtual Format: %s", StreamDescriptionToString(virtualFormat, formatString)); - CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " - "New Physical Format: %s", StreamDescriptionToString(outputFormat, formatString)); - - m_allowMixing = false; - - return true; -} - -bool CCoreAudioAEHALOSX::Initialize(ICoreAudioSource *ae, bool passThrough, AEAudioFormat &format, AEDataFormat rawDataFormat, std::string &device, float initVolume) -{ - // Reset all the devices to a default 'non-hog' and mixable format. - // If we don't do this we may be unable to find the Default Output device. - // (e.g. if we crashed last time leaving it stuck in AC-3 mode) - - CCoreAudioHardware::ResetAudioDevices(); - - m_ae = (CCoreAudioAE*)ae; - if (!m_ae) - return false; - - m_initformat = format; - m_rawDataFormat = rawDataFormat; - m_Passthrough = passThrough; - m_encoded = false; - m_OutputBufferIndex = 0; - m_initVolume = initVolume; - - if (format.m_channelLayout.Count() == 0) - { - CLog::Log(LOGERROR, "CCoreAudioAEHALOSX::Initialize - " - "Unable to open the requested channel layout"); - return false; - } - - if (device.find("CoreAudio:") != std::string::npos) - device.erase(0, strlen("CoreAudio:")); - - AudioDeviceID outputDevice = CCoreAudioHardware::FindAudioDevice(device); - if (!outputDevice) - { - // Fall back to the default device if no match is found - CLog::Log(LOGWARNING, "CCoreAudioAEHALOSX::Initialize: " - "Unable to locate configured device, falling-back to the system default."); - outputDevice = CCoreAudioHardware::GetDefaultOutputDevice(); - if (!outputDevice) // Not a lot to be done with no device. TODO: Should we just grab the first existing device? - return false; - } - - // Attach our output object to the device - m_AudioDevice->Open(outputDevice); - m_AudioDevice->SetHogStatus(false); - m_AudioDevice->SetMixingSupport(true); - - // If this is a passthrough (AC3/DTS) stream, attempt to handle it natively - if (m_Passthrough) - m_encoded = InitializeEncoded(outputDevice, format); - - // If this is a PCM stream, or we failed to handle a passthrough stream natively, - // prepare the standard interleaved PCM interface - if (!m_encoded) - { - // If we are here and this is a passthrough stream, native handling failed. - // Try to handle it as IEC61937 data over straight PCM (DD-Wav) - bool configured = false; - if (m_Passthrough) - { - CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::Initialize: " - "No suitable AC3 output format found. Attempting DD-Wav."); - configured = InitializePCMEncoded(ae, format, outputDevice); - } - else - { - // Standard PCM data - configured = InitializePCM(ae, format, true, outputDevice); - } - - // No suitable output format was able to be configured - if (!configured) - return false; - } - - m_Initialized = true; - - return true; -} - -CAUOutputDevice *CCoreAudioAEHALOSX::DestroyUnit(CAUOutputDevice *outputUnit) -{ - if (m_audioGraph && outputUnit) - return m_audioGraph->DestroyUnit(outputUnit); - - return NULL; -} - -CAUOutputDevice *CCoreAudioAEHALOSX::CreateUnit(ICoreAudioSource *pSource, AEAudioFormat &format) -{ - CAUOutputDevice *outputUnit = NULL; - - // when HAL is using a mixer, the input is routed through converter units. - // therefore we create a converter unit attach the source and give it back. - if (m_allowMixing && m_audioGraph) - { - outputUnit = m_audioGraph->CreateUnit(format); - - if (pSource && outputUnit) - outputUnit->SetInputSource(pSource); - } - - return outputUnit; -} - -void CCoreAudioAEHALOSX::Deinitialize() -{ - if (!m_Initialized) - return; - - Stop(); - - if (m_encoded) - m_AudioDevice->SetInputSource(NULL, 0, 0); - - if (m_audioGraph) - m_audioGraph->SetInputSource(NULL); - - m_OutputStream->Close(); - m_AudioDevice->Close(); - - if (m_audioGraph) - { - //m_audioGraph->Close(); - delete m_audioGraph; - } - m_audioGraph = NULL; - - m_NumLatencyFrames = 0; - m_OutputBufferIndex = 0; - - m_Initialized = false; - m_Passthrough = false; -} - -void CCoreAudioAEHALOSX::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough) -{ - CoreAudioDeviceList deviceList; - CCoreAudioHardware::GetOutputDevices(&deviceList); - - devices.push_back(AEDevice("Default", "CoreAudio:default")); - - std::string deviceName; - for (int i = 0; !deviceList.empty(); i++) - { - CCoreAudioDevice device(deviceList.front()); - deviceName = device.GetName(); - - std::string deviceName_Internal = std::string("CoreAudio:"); - deviceName_Internal.append(deviceName); - devices.push_back(AEDevice(deviceName, deviceName_Internal)); - - deviceList.pop_front(); - } -} - -void CCoreAudioAEHALOSX::Stop() -{ - if (!m_Initialized) - return; - - if (m_encoded) - m_AudioDevice->Stop(); - else - m_audioGraph->Stop(); -} - -bool CCoreAudioAEHALOSX::Start() -{ - if (!m_Initialized) - return false; - - if (m_encoded) - m_AudioDevice->Start(); - else - m_audioGraph->Start(); - - return true; -} - -void CCoreAudioAEHALOSX::SetDirectInput(ICoreAudioSource *pSource, AEAudioFormat &format) -{ - if (!m_Initialized) - return; - - // when HAL is initialized encoded we use directIO - // when HAL is not in encoded mode and there is no mixer attach source the audio unit - // when mixing is allowed in HAL, HAL is working with converter units where we attach the source. - - if (m_encoded) - { - // register directcallback for the audio HAL - // direct render callback need to know the framesize and buffer index - if (pSource) - m_AudioDevice->SetInputSource(pSource, format.m_frameSize, m_OutputBufferIndex); - else - m_AudioDevice->SetInputSource(pSource, 0, 0); - } - else if (!m_encoded && !m_allowMixing) - { - // register render callback for the audio unit - m_audioGraph->SetInputSource(pSource); - } -} - -double CCoreAudioAEHALOSX::GetDelay() -{ - return (double)(m_NumLatencyFrames) / (m_initformat.m_sampleRate); -} - -void CCoreAudioAEHALOSX::SetVolume(float volume) -{ - if (m_encoded || m_Passthrough) - return; - - m_audioGraph->SetCurrentVolume(volume); -} - -unsigned int CCoreAudioAEHALOSX::GetBufferIndex() -{ - return m_OutputBufferIndex; -} - -#endif diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.h deleted file mode 100644 index c96a4e1bfe..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#if defined(TARGET_DARWIN_OSX) - -#include "ICoreAudioAEHAL.h" -#include "ICoreAudioSource.h" - -#include <CoreAudio/CoreAudio.h> - -// Forward declarations -class CCoreAudioAE; -class CCoreAudioGraph; -class CCoreAudioDevice; -class CCoreAudioStream; - -class CAUOutputDevice; - -class CCoreAudioAEHALOSX : public ICoreAudioAEHAL -{ -protected: - CCoreAudioGraph *m_audioGraph; - CCoreAudioDevice *m_AudioDevice; - CCoreAudioStream *m_OutputStream; - bool m_Initialized; - bool m_Passthrough; - AEAudioFormat m_initformat; - bool m_allowMixing; - bool m_encoded; - AEDataFormat m_rawDataFormat; - float m_initVolume; -public: - unsigned int m_NumLatencyFrames; - unsigned int m_OutputBufferIndex; - CCoreAudioAE *m_ae; - - CCoreAudioAEHALOSX(); - virtual ~CCoreAudioAEHALOSX(); - - virtual bool InitializePCM(ICoreAudioSource *pSource, AEAudioFormat &format, bool allowMixing, AudioDeviceID outputDevice, bool encoded = false); - virtual bool InitializePCMEncoded(ICoreAudioSource *pSource, AEAudioFormat &format, AudioDeviceID outputDevice); - virtual bool InitializeEncoded(AudioDeviceID outputDevice, AEAudioFormat &format); - virtual bool Initialize(ICoreAudioSource *ae, bool passThrough, AEAudioFormat &format, AEDataFormat rawDataFormat, std::string &device, float initVolume); - virtual void Deinitialize(); - virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough); - virtual void SetDirectInput(ICoreAudioSource *pSource, AEAudioFormat &format); - virtual void Stop(); - virtual bool Start(); - virtual double GetDelay(); - virtual void SetVolume(float volume); - virtual unsigned int GetBufferIndex(); - virtual CAUOutputDevice* DestroyUnit(CAUOutputDevice *outputUnit); - virtual CAUOutputDevice* CreateUnit(ICoreAudioSource *pSource, AEAudioFormat &format); - virtual bool AllowMixing() { return m_allowMixing; } -}; - -#endif diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAESound.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAESound.cpp deleted file mode 100644 index e57f26327a..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAESound.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include <samplerate.h> - -#include "CoreAudioAESound.h" - -#include "CoreAudioAE.h" -#include "threads/SingleLock.h" -#include "cores/AudioEngine/AEFactory.h" -#include "cores/AudioEngine/Utils/AEAudioFormat.h" -#include "cores/AudioEngine/Interfaces/AESound.h" -#include "cores/AudioEngine/Utils/AEConvert.h" -#include "cores/AudioEngine/Utils/AERemap.h" -#include "cores/AudioEngine/Utils/AEUtil.h" -#include "utils/log.h" -#include "utils/EndianSwap.h" - -/* typecast AE to CCoreAudioAE */ -#define AE (*(CCoreAudioAE*)CAEFactory::GetEngine()) - -CCoreAudioAESound::CCoreAudioAESound(const std::string &filename) : - IAESound (filename), - m_filename (filename), - m_volume (1.0f ), - m_inUse (0 ) -{ - m_wavLoader.Load(filename); -} - -CCoreAudioAESound::~CCoreAudioAESound() -{ - DeInitialize(); -} - - -std::string CCoreAudioAESound::GetFileName() -{ - return m_filename; -} - -void CCoreAudioAESound::DeInitialize() -{ -} - -bool CCoreAudioAESound::Initialize() -{ - if (!m_wavLoader.IsValid()) - return false; - - return m_wavLoader.Initialize( - AE.GetSampleRate (), - AE.GetChannelLayout(), - AE_CH_LAYOUT_INVALID - ); -} - -void CCoreAudioAESound::SetVolume(float volume) -{ - m_volume = std::max(0.0f, std::min(1.0f, volume)); -} - -float CCoreAudioAESound::GetVolume() -{ - return m_volume; -} - -unsigned int CCoreAudioAESound::GetSampleCount() -{ - CSingleLock cs(m_critSection); - if (m_wavLoader.IsValid()) - return m_wavLoader.GetSampleCount(); - return 0; -} - -float* CCoreAudioAESound::GetSamples() -{ - CSingleLock cs(m_critSection); - if (!m_wavLoader.IsValid()) - return NULL; - - ++m_inUse; - return m_wavLoader.GetSamples(); -} - -void CCoreAudioAESound::ReleaseSamples() -{ - CSingleLock cs(m_critSection); - if(m_inUse > 0) - --m_inUse; -} - -bool CCoreAudioAESound::IsPlaying() -{ - CSingleLock cs(m_critSection); - return (m_inUse > 0); -} - -void CCoreAudioAESound::Play() -{ - AE.PlaySound(this); -} - -void CCoreAudioAESound::Stop() -{ - AE.StopSound(this); -} diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAESound.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAESound.h deleted file mode 100644 index 68fdb2a801..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAESound.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "cores/AudioEngine/Interfaces/AESound.h" -#include "cores/AudioEngine/Utils/AEWAVLoader.h" -#include "threads/CriticalSection.h" - -class CCoreAudioAESound : public IAESound -{ -public: - CCoreAudioAESound(const std::string &filename); - virtual ~CCoreAudioAESound(); - - virtual std::string GetFileName(); - virtual void DeInitialize(); - virtual bool Initialize(); - - virtual void Play(); - virtual void Stop(); - virtual bool IsPlaying(); - - virtual void SetVolume(float volume); - virtual float GetVolume(); - - unsigned int GetSampleCount(); - - /* ReleaseSamples must be called for each time GetSamples has been called */ - virtual float* GetSamples(); - void ReleaseSamples(); - -private: - CCriticalSection m_critSection; - std::string m_filename; - CAEWAVLoader m_wavLoader; - float m_volume; - int m_inUse; -}; - diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.cpp deleted file mode 100644 index 581daf93ec..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.cpp +++ /dev/null @@ -1,921 +0,0 @@ -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "system.h" - -#include "CoreAudioAE.h" -#include "CoreAudioAEStream.h" - -#include "xbmc/cores/AudioEngine/Interfaces/AE.h" -#include "xbmc/cores/AudioEngine/AEFactory.h" -#include "xbmc/cores/AudioEngine/Utils/AEUtil.h" -#include "xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" -#include "settings/Settings.h" -#include "threads/SingleLock.h" -#include "settings/AdvancedSettings.h" -#include "utils/MathUtils.h" -#include "utils/log.h" - - - -// typecast AE to CCoreAudioAE -#define AE (*(CCoreAudioAE*)CAEFactory::GetEngine()) - -void CheckOutputBufferSize(void **buffer, int *oldSize, int newSize) -{ - if (newSize > *oldSize) - { - if (*buffer) - _aligned_free(*buffer); - *buffer = _aligned_malloc(newSize, 16); - *oldSize = newSize; - } - memset(*buffer, 0x0, *oldSize); -} - -using namespace std; - -template <class AudioDataType> -static inline void _Upmix(AudioDataType *input, - unsigned int channelsInput, AudioDataType *output, - unsigned int channelsOutput, unsigned int frames) -{ - unsigned int unused = channelsOutput - channelsInput; - AudioDataType *_input = input; - AudioDataType *_output = output; - - for (unsigned int i = 0; i < frames; i++) - { - // get input channels - for(unsigned int j = 0; j < channelsInput; j++) - *_output++ = *_input++; - // set unused channels - for(unsigned int j = 0; j < unused; j++) - *_output++ = 0; - } -} - -void CCoreAudioAEStream::Upmix(void *input, - unsigned int channelsInput, void *output, - unsigned int channelsOutput, unsigned int frames, AEDataFormat dataFormat) -{ - // input channels must be less than output channels - if (channelsInput >= channelsOutput) - return; - - switch (CAEUtil::DataFormatToBits(dataFormat)) - { - case 8: _Upmix ( (unsigned char *) input, channelsInput, (unsigned char *) output, channelsOutput, frames ); break; - case 16: _Upmix ( (short *) input, channelsInput, (short *) output, channelsOutput, frames ); break; - case 32: _Upmix ( (float *) input, channelsInput, (float *) output, channelsOutput, frames ); break; - default: _Upmix ( (int *) input, channelsInput, (int *) output, channelsOutput, frames ); break; - } -} - -CCoreAudioAEStream::CCoreAudioAEStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSamplerate, CAEChannelInfo channelLayout, unsigned int options, bool transcode) : - m_outputUnit (NULL ), - m_valid (false), - m_delete (false), - m_volume (1.0f ), - m_rgain (1.0f ), - m_slave (NULL ), - m_convertFn (NULL ), - m_Buffer (NULL ), - m_convertBuffer (NULL ), - m_ssrc (NULL ), - m_draining (false), - m_AvgBytesPerSec (0 ), - m_audioCallback (NULL ), - m_fadeRunning (false), - m_frameSize (0 ), - m_doRemap (true ), - m_firstInput (true ), - m_flushRequested (false), - m_encoder (NULL ) -{ - m_ssrcData.data_out = NULL; - m_transcode = transcode; - - if (!transcode) - { - m_rawDataFormat = dataFormat; - m_StreamFormat.m_dataFormat = dataFormat; - m_StreamFormat.m_sampleRate = sampleRate; - m_StreamFormat.m_encodedRate = 0; //we don't support this - m_StreamFormat.m_channelLayout = channelLayout; - m_isRaw = COREAUDIO_IS_RAW(dataFormat); - } - else - { - m_rawDataFormat = AE_FMT_AC3; - m_StreamFormat.m_dataFormat = AE_FMT_AC3; - m_StreamFormat.m_sampleRate = 48000; - m_StreamFormat.m_encodedRate = 0; - enum AEChannel ac3Layout[3] = {AE_CH_RAW, AE_CH_RAW, AE_CH_NULL}; - m_StreamFormat.m_channelLayout = ac3Layout; - m_isRaw = true; - - // setup encoder format - m_encoderFormat.m_dataFormat = dataFormat; - m_encoderFormat.m_sampleRate = sampleRate; - m_encoderFormat.m_encodedRate = 0; - m_encoderFormat.m_channelLayout = channelLayout; - m_encoderFormat.m_frames = 0; - m_encoderFormat.m_frameSamples = 0; - m_encoderFormat.m_frameSize = 0; - } - - m_incomingFormat = dataFormat; - m_chLayoutCountStream = m_StreamFormat.m_channelLayout.Count(); - m_StreamFormat.m_frameSize = (CAEUtil::DataFormatToBits(m_rawDataFormat) >> 3) * m_chLayoutCountStream; - m_OutputFormat = AE.GetAudioFormat(); - m_chLayoutCountOutput = m_OutputFormat.m_channelLayout.Count(); - - //m_forceResample = (options & AESTREAM_FORCE_RESAMPLE) != 0; - m_paused = (options & AESTREAM_PAUSED) != 0; - - m_vizRemapBufferSize = m_remapBufferSize = /*m_resampleBufferSize = */ m_upmixBufferSize = m_convertBufferSize = 16*1024; - m_convertBuffer = (float *)_aligned_malloc(m_convertBufferSize,16); - //m_resampleBuffer = (float *)_aligned_malloc(m_resampleBufferSize,16); - m_upmixBuffer = (uint8_t *)_aligned_malloc(m_upmixBufferSize,16); - m_remapBuffer = (uint8_t *)_aligned_malloc(m_remapBufferSize,16); - m_vizRemapBuffer = (uint8_t *)_aligned_malloc(m_vizRemapBufferSize,16); - - m_limiter.SetSamplerate(AE.GetSampleRate()); -} - -CCoreAudioAEStream::~CCoreAudioAEStream() -{ - CloseConverter(); - - m_delete = true; - m_valid = false; - - InternalFlush(); - - _aligned_free(m_convertBuffer); m_convertBuffer = NULL; - //_aligned_free(m_resampleBuffer); m_resampleBuffer = NULL; - _aligned_free(m_remapBuffer); m_remapBuffer = NULL; - _aligned_free(m_vizRemapBuffer); m_vizRemapBuffer = NULL; - _aligned_free(m_upmixBuffer); m_upmixBuffer = NULL; - - delete m_Buffer; m_Buffer = NULL; - - delete m_encoder; - m_encoder = NULL; - ResetEncoder(); - - m_unencodedBuffer.DeAlloc(); - - /* - if (m_resample) - { - _aligned_free(m_ssrcData.data_out); - src_delete(m_ssrc); - m_ssrc = NULL; - } - */ - - CLog::Log(LOGDEBUG, "CCoreAudioAEStream::~CCoreAudioAEStream - Destructed"); -} - -void CCoreAudioAEStream::InitializeRemap() -{ - if (!m_isRaw) - { - if (m_OutputFormat.m_channelLayout != AE.GetChannelLayout()) - { - m_OutputFormat = AE.GetAudioFormat(); - m_chLayoutCountOutput = m_OutputFormat.m_channelLayout.Count(); - m_OutputBytesPerSample = (CAEUtil::DataFormatToBits(m_OutputFormat.m_dataFormat) >> 3); - - // re-init the remappers - m_remap .Initialize(m_StreamFormat.m_channelLayout, m_OutputFormat.m_channelLayout, false); - m_vizRemap.Initialize(m_StreamFormat.m_channelLayout, CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true); - - InternalFlush(); - } - } -} - -void CCoreAudioAEStream::ReinitConverter() -{ - CloseConverter(); - OpenConverter(); -} - -// The source logic is in the HAL. The only thing we have to do here -// is to allocate the convrter and set the direct input call. -void CCoreAudioAEStream::CloseConverter() -{ - // we have a converter, delete it - if (m_outputUnit) - m_outputUnit = (CAUOutputDevice *) AE.GetHAL()->DestroyUnit(m_outputUnit); - - // it is save to unregister any direct input. the HAL takes care about it. - AE.GetHAL()->SetDirectInput(NULL, m_OutputFormat); -} - -void CCoreAudioAEStream::OpenConverter() -{ - // we always allocate a converter - // the HAL decides if we get converter. - // if there is already a converter delete it. - if (m_outputUnit) - m_outputUnit = (CAUOutputDevice *) AE.GetHAL()->DestroyUnit(m_outputUnit); - - AEAudioFormat format = m_OutputFormat; - - format.m_sampleRate = m_StreamFormat.m_sampleRate; - m_outputUnit = (CAUOutputDevice *) AE.GetHAL()->CreateUnit(this, format); - - // it is safe to register any direct input. the HAL takes care about it. - AE.GetHAL()->SetDirectInput(this, m_OutputFormat); -} - -void CCoreAudioAEStream::Initialize() -{ - if (m_valid) - InternalFlush(); - - m_OutputFormat = AE.GetAudioFormat(); - m_chLayoutCountOutput = m_OutputFormat.m_channelLayout.Count(); - - if (m_rawDataFormat == AE_FMT_LPCM) - m_OutputBytesPerSample = (CAEUtil::DataFormatToBits(AE_FMT_FLOAT) >> 3); - else - m_OutputBytesPerSample = (CAEUtil::DataFormatToBits(m_OutputFormat.m_dataFormat) >> 3); - - if (m_isRaw || m_transcode) - { - // we are raw or transcode, which means we need to work in the output format - if (m_rawDataFormat != AE_FMT_LPCM) - { - m_StreamFormat = AE.GetAudioFormat(); - m_chLayoutCountStream = m_StreamFormat.m_channelLayout.Count(); - } - m_StreamBytesPerSample = (CAEUtil::DataFormatToBits(m_StreamFormat.m_dataFormat) >> 3); - m_doRemap = false; - } - else - { - if (!m_chLayoutCountStream) - { - m_valid = false; - return; - } - // Work around a bug in TrueHD and DTSHD deliver - if (m_StreamFormat.m_dataFormat == AE_FMT_TRUEHD || m_StreamFormat.m_dataFormat == AE_FMT_DTSHD) - m_StreamBytesPerSample = (CAEUtil::DataFormatToBits(AE_FMT_S16NE) >> 3); - else - m_StreamBytesPerSample = (CAEUtil::DataFormatToBits(m_StreamFormat.m_dataFormat) >> 3); - m_StreamFormat.m_frameSize = m_StreamBytesPerSample * m_chLayoutCountStream; - } - - if (!m_isRaw) - { - if (!m_remap.Initialize(m_StreamFormat.m_channelLayout, m_OutputFormat.m_channelLayout, false)) - { - m_valid = false; - return; - } - - m_doRemap = m_chLayoutCountStream != 2; - - if (!m_vizRemap.Initialize(m_OutputFormat.m_channelLayout, CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true)) - { - m_valid = false; - return; - } - } - - // only try to convert if we're not in AE_FMT_FLOAT and (we're not raw or we are transcoding) - m_convert = - (m_StreamFormat.m_dataFormat != AE_FMT_FLOAT && !m_isRaw) - || - (m_incomingFormat != AE_FMT_FLOAT && m_transcode); - - - //m_resample = false; //(m_StreamFormat.m_sampleRate != m_OutputFormat.m_sampleRate) && !m_isRaw; - - // if we need to convert, set it up - if (m_convert) - { - // get the conversion function and allocate a buffer for the data - CLog::Log(LOGDEBUG, "CCoreAudioAEStream::CCoreAudioAEStream - Converting from %s to AE_FMT_FLOAT", CAEUtil::DataFormatToStr(m_StreamFormat.m_dataFormat)); - - if (!m_transcode) - m_convertFn = CAEConvert::ToFloat(m_StreamFormat.m_dataFormat); - else - m_convertFn = CAEConvert::ToFloat(m_incomingFormat); - - if (!m_convertFn) - m_valid = false; - } - - // if we need to transcode, set it up - if (m_transcode) - { - m_unencodedBuffer.Empty(); - - if (!m_encoder || !m_encoder->IsCompatible(m_encoderFormat)) - SetupEncoder(); - } - - // if we need to resample, set it up - /* - if (m_resample) - { - int err; - m_ssrc = src_new(SRC_SINC_MEDIUM_QUALITY, m_chLayoutCountStream, &err); - m_ssrcData.src_ratio = (double)m_OutputFormat.m_sampleRate / (double)m_StreamFormat.m_sampleRate; - m_ssrcData.data_in = m_convertBuffer; - m_ssrcData.end_of_input = 0; - } - */ - - // m_AvgBytesPerSec is calculated based on the output format. - // we have to keep in mind that we convert our data to the output format - m_AvgBytesPerSec = m_OutputFormat.m_frameSize * m_OutputFormat.m_sampleRate; - - delete m_Buffer; - m_Buffer = new AERingBuffer(m_AvgBytesPerSec); - - m_fadeRunning = false; - - OpenConverter(); - - m_valid = true; -} - -void CCoreAudioAEStream::Destroy() -{ - m_valid = false; - m_delete = true; - InternalFlush(); -} - -unsigned int CCoreAudioAEStream::AddData(void *data, unsigned int size) -{ - unsigned int frames = size / m_StreamFormat.m_frameSize; - unsigned int samples = size / m_StreamBytesPerSample; - uint8_t *adddata = (uint8_t *)data; - unsigned int addsize = size; - unsigned int channelsInBuffer = m_chLayoutCountStream; - - if (m_flushRequested && m_paused) - InternalFlush(); - - if (!m_valid || size == 0 || data == NULL || !m_Buffer || m_flushRequested) - return 0; - - // if the stream is draining - if (m_draining) - { - // if the stream has finished draining, cork it - if (m_Buffer && m_Buffer->GetReadSize() == 0) - m_draining = false; - else - return 0; - } - - // convert the data if we need to - if (m_convert) - { - CheckOutputBufferSize((void **)&m_convertBuffer, &m_convertBufferSize, frames * channelsInBuffer * m_OutputBytesPerSample); - - samples = m_convertFn(adddata, size / m_StreamBytesPerSample, m_convertBuffer); - frames = samples / channelsInBuffer; - addsize = frames * channelsInBuffer * m_OutputBytesPerSample; - adddata = (uint8_t *)m_convertBuffer; - } - else - { - samples = size / m_StreamBytesPerSample; - adddata = (uint8_t *)data; - addsize = size; - } - - if (samples == 0) - return 0; - - // transcode if we need to - if (m_transcode && m_encoder) - { - // put adddata in the unencodedBuffer - if (m_unencodedBuffer.Free() < addsize) - m_unencodedBuffer.ReAlloc(m_unencodedBuffer.Used() + addsize); - - m_unencodedBuffer.Push(adddata, addsize); - - unsigned int block = m_encoderFormat.m_frames * m_encoderFormat.m_frameSize; - - // only try to encode if we have enough data - if (m_unencodedBuffer.Used() >= block) - { - frames = m_encoder->Encode((float *)m_unencodedBuffer.Raw(block), m_encoderFormat.m_frames); - m_unencodedBuffer.Shift(NULL, frames * m_encoderFormat.m_frameSize); - addsize = m_encoder->GetData(&adddata); - samples = addsize / m_OutputBytesPerSample; - } - else - // return size here or whoever calling us will block if we return 0 - // we have essentially been successful, because we add the audio to our buffer to encode - return size; - } - - if (samples == 0) - return 0; - - - // resample it if we need to - /* - if (m_resample) - { - unsigned int resample_frames = samples / m_chLayoutCountStream; - - CheckOutputBufferSize((void **)&m_resampleBuffer, &m_resampleBufferSize, - resample_frames * std::ceil(m_ssrcData.src_ratio) * sizeof(float) * 2); - - m_ssrcData.input_frames = resample_frames; - m_ssrcData.output_frames = resample_frames * std::ceil(m_ssrcData.src_ratio); - m_ssrcData.data_in = (float *)adddata; - m_ssrcData.data_out = m_resampleBuffer; - - if (src_process(m_ssrc, &m_ssrcData) != 0) - return 0; - - frames = m_ssrcData.output_frames_gen; - samples = frames * m_chLayoutCountStream; - adddata = (uint8_t *)m_ssrcData.data_out; - } - else - { - frames = samples / m_chLayoutCountStream; - samples = frames * m_chLayoutCountStream; - } - */ - - if (m_doRemap) - { - addsize = frames * m_OutputBytesPerSample * m_chLayoutCountOutput; - CheckOutputBufferSize((void **)&m_remapBuffer, &m_remapBufferSize, addsize); - - // downmix/remap the data - m_remap.Remap((float *)adddata, (float *)m_remapBuffer, frames); - adddata = (uint8_t *)m_remapBuffer; - channelsInBuffer = m_OutputFormat.m_channelLayout.Count(); - } - - // upmix the ouput to output channels - if ( (!m_isRaw || m_rawDataFormat == AE_FMT_LPCM) && (m_chLayoutCountOutput > channelsInBuffer) ) - { - CheckOutputBufferSize((void **)&m_upmixBuffer, &m_upmixBufferSize, frames * m_chLayoutCountOutput * sizeof(float)); - Upmix(adddata, channelsInBuffer, m_upmixBuffer, m_chLayoutCountOutput, frames, m_OutputFormat.m_dataFormat); - adddata = m_upmixBuffer; - addsize = frames * m_chLayoutCountOutput * sizeof(float); - } - - unsigned int total_ms_sleep = 0; - unsigned int room = m_Buffer->GetWriteSize(); - while (addsize > room && !m_paused && total_ms_sleep < 100) - { - // we got deleted - if (!m_valid || !m_Buffer || m_draining ) - return 0; - - unsigned int ms_sleep_time = (1000 * room) / m_AvgBytesPerSec; - if (ms_sleep_time == 0) - ms_sleep_time++; - - // sleep until we have space (estimated) or 1ms min - Sleep(ms_sleep_time); - total_ms_sleep += ms_sleep_time; - - room = m_Buffer->GetWriteSize(); - } - - if (addsize > room) - size = 0; - else - m_Buffer->Write(adddata, addsize); - - // still only return size to indicate success - // we likely wrote something !size to m_Buffer, but our called doesn't realy care - return size; -} - -// this is only called on the context of the coreaudio thread! -unsigned int CCoreAudioAEStream::GetFrames(uint8_t *buffer, unsigned int size) -{ - // if we have been deleted - if (!m_valid || m_delete || !m_Buffer || m_paused) - return 0; - - if (m_flushRequested) - { - InternalFlush(); - return 0; - } - - unsigned int readsize = std::min(m_Buffer->GetReadSize(), size); - m_Buffer->Read(buffer, readsize); - - if (!m_isRaw) - { - float *floatBuffer = (float *)buffer; - unsigned int samples = readsize / m_OutputBytesPerSample; - unsigned int frames = samples / m_chLayoutCountOutput; - - // we have a frame, if we have a viz we need to hand the data to it. - // Keep in mind that our buffer is already in output format. - // So we remap output format to viz format !!! - if (m_OutputFormat.m_dataFormat == AE_FMT_FLOAT) - { - // TODO : Why the hell is vizdata limited ? - unsigned int samplesClamped = (samples > 512) ? 512 : samples; - if (samplesClamped) - { - // Viz channel count is 2 - CheckOutputBufferSize((void **)&m_vizRemapBuffer, &m_vizRemapBufferSize, frames * 2 * sizeof(float)); - - m_vizRemap.Remap(floatBuffer, (float*)m_vizRemapBuffer, frames); - if (m_audioCallback) - m_audioCallback->OnAudioData((float *)m_vizRemapBuffer, samplesClamped); - } - } - - // if we are fading - if (m_fadeRunning) - { - // TODO: check if we correctly respect the amount of our blockoperation - m_volume += (m_fadeStep * ((float)readsize / (float)m_OutputFormat.m_frameSize)); - m_volume = std::min(1.0f, std::max(0.0f, m_volume)); - if (m_fadeDirUp) - { - if (m_volume >= m_fadeTarget) - m_fadeRunning = false; - } - else - { - if (m_volume <= m_fadeTarget) - m_fadeRunning = false; - } - } - - if (m_volume < 1.0f) - { -#ifdef __SSE__ - CAEUtil::SSEMulArray(floatBuffer, m_volume, samples); -#else - for(unsigned int i = 0; i < samples; i++) - floatBuffer[i] *= m_volume; -#endif - CAEUtil::ClampArray(floatBuffer, samples); - } - // apply volume amplification by using the sogt limiter - // TODO - maybe reinvent the coreaudio compressor for this after frodo - else if (GetAmplification() != 1.0f) - { - for(unsigned int i = 0; i < frames; i++) - { - int frameIdx = i*m_chLayoutCountOutput; - float amplification = RunLimiter(&floatBuffer[frameIdx], m_chLayoutCountOutput); - float *frameStart = &floatBuffer[frameIdx]; -#ifdef __SSE___ - CAEUtil::SSEMulArray(frameStart, amplification, m_chLayoutCountOutput); -#else - for(unsigned int n = 0; n < m_chLayoutCountOutput; n++) - frameStart[n] *= amplification; -#endif - - } - } - } - - return readsize; -} - -const unsigned int CCoreAudioAEStream::GetFrameSize() const -{ - return m_OutputFormat.m_frameSize; -} - -unsigned int CCoreAudioAEStream::GetSpace() -{ - if (!m_valid || m_draining) - return 0; - - return m_Buffer->GetWriteSize() / m_OutputBytesPerSample * m_StreamBytesPerSample; -} - -double CCoreAudioAEStream::GetDelay() -{ - if (m_delete || !m_Buffer || m_flushRequested) - return 0.0f; - - double delayBuffer = (double)(m_Buffer->GetReadSize()) / (double)m_AvgBytesPerSec; - double delayTranscoder = 0.0; - - if (m_transcode) - delayTranscoder = (double)(m_unencodedBuffer.Used()) / (double)(m_encoderFormat.m_frameSize * m_encoderFormat.m_sampleRate); - - return AE.GetDelay() + delayBuffer + delayTranscoder; -} - -bool CCoreAudioAEStream::IsBuffering() -{ - return (m_Buffer->GetReadSize() == 0 && m_unencodedBuffer.Used() == 0); -} - -double CCoreAudioAEStream::GetCacheTime() -{ - if (m_delete || !m_Buffer || m_flushRequested) - return 0.0f; - double delayBuffer = (double)(m_Buffer->GetReadSize()) / (double)m_AvgBytesPerSec; - double delayTranscoder = 0.0; - - if (m_transcode) - delayTranscoder = (double)(m_unencodedBuffer.Used()) / (double)(m_encoderFormat.m_frameSize * m_encoderFormat.m_sampleRate); - - return AE.GetDelay() + delayBuffer + delayTranscoder; -} - -double CCoreAudioAEStream::GetCacheTotal() -{ - if (m_delete || !m_Buffer) - return 0.0f; - - return (double)m_Buffer->GetMaxSize() / (double)m_AvgBytesPerSec; -} - - -bool CCoreAudioAEStream::IsPaused() -{ - return m_paused; -} - -bool CCoreAudioAEStream::IsDraining() -{ - return m_draining; -} - -bool CCoreAudioAEStream::IsDestroyed() -{ - return m_delete; -} - -bool CCoreAudioAEStream::IsValid() -{ - return m_valid; -} - -void CCoreAudioAEStream::Pause() -{ - m_paused = true; -} - -void CCoreAudioAEStream::Resume() -{ -#if defined(TARGET_DARWIN_IOS) && !defined(TARGET_DARWIN_IOS_ATV) - if (CAEFactory::IsSuspended()) - CAEFactory::Resume(); -#endif - m_paused = false; -} - -void CCoreAudioAEStream::Drain(bool wait) -{ - m_draining = true; -} - -bool CCoreAudioAEStream::IsDrained() -{ - return m_Buffer->GetReadSize() == 0; -} - -void CCoreAudioAEStream::Flush() -{ - if (m_Buffer) - m_flushRequested = true; -} - -float CCoreAudioAEStream::GetVolume() -{ - return m_volume; -} - -float CCoreAudioAEStream::GetReplayGain() -{ - return m_rgain; -} - -void CCoreAudioAEStream::SetVolume(float volume) -{ - m_volume = std::max( 0.0f, std::min(1.0f, volume)); -} - -void CCoreAudioAEStream::SetReplayGain(float factor) -{ - m_rgain = std::max(-1.0f, std::max(1.0f, factor)); -} - -void CCoreAudioAEStream::InternalFlush() -{ - // reset the resampler - /* - if (m_resample) { - m_ssrcData.end_of_input = 0; - src_reset(m_ssrc); - } - */ - - // Read the buffer empty to avoid Reset - // Reset is not lock free. - if (m_Buffer) - { - unsigned int readsize = m_Buffer->GetReadSize(); - if (readsize) - { - uint8_t *buffer = (uint8_t *)_aligned_malloc(readsize, 16); - m_Buffer->Read(buffer, readsize); - _aligned_free(buffer); - } - - // if we are draining and are out of packets, tell the slave to resume - if (m_draining && m_slave) - { - m_slave->Resume(); - m_slave = NULL; - } - } - - m_flushRequested = false; - //if (m_Buffer) - // m_Buffer->Reset(); -} - -const unsigned int CCoreAudioAEStream::GetChannelCount() const -{ - return m_chLayoutCountStream; -} - -const unsigned int CCoreAudioAEStream::GetSampleRate() const -{ - return m_StreamFormat.m_sampleRate; -} - -const unsigned int CCoreAudioAEStream::GetEncodedSampleRate() const -{ - return m_StreamFormat.m_encodedRate; -} - -const enum AEDataFormat CCoreAudioAEStream::GetDataFormat() const -{ - return m_StreamFormat.m_dataFormat; -} - -const bool CCoreAudioAEStream::IsRaw() const -{ - return m_isRaw; -} - -double CCoreAudioAEStream::GetResampleRatio() -{ - /* - if (!m_resample) - return 1.0f; - - double ret = m_ssrcData.src_ratio; - return ret; - */ - - return 1.0f; -} - -bool CCoreAudioAEStream::SetResampleRatio(double ratio) -{ - return false; - /* - if (!m_resample) - return; - - src_set_ratio(m_ssrc, ratio); - m_ssrcData.src_ratio = ratio; - */ -} - -void CCoreAudioAEStream::RegisterAudioCallback(IAudioCallback* pCallback) -{ - m_audioCallback = pCallback; - if (m_audioCallback) - m_audioCallback->OnInitialize(2, m_StreamFormat.m_sampleRate, 32); -} - -void CCoreAudioAEStream::UnRegisterAudioCallback() -{ - m_audioCallback = NULL; -} - -void CCoreAudioAEStream::FadeVolume(float from, float target, unsigned int time) -{ - if (m_isRaw) - { - m_fadeRunning = false; - } - else - { - float delta = target - from; - m_fadeDirUp = target > from; - m_fadeTarget = target; - m_fadeStep = delta / (((float)m_OutputFormat.m_sampleRate / 1000.0f) * (float)time); - m_fadeRunning = true; - } -} - -bool CCoreAudioAEStream::IsFading() -{ - return m_fadeRunning; -} - -void CCoreAudioAEStream::RegisterSlave(IAEStream *stream) -{ - m_slave = stream; -} - -OSStatus CCoreAudioAEStream::Render(AudioUnitRenderActionFlags* actionFlags, - const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pBufList) -{ - OSStatus ret = OnRender(actionFlags, pTimeStamp, busNumber, frameCount, pBufList); - return ret; -} - -OSStatus CCoreAudioAEStream::OnRender(AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) -{ - // if we have no valid data output silence - if (!m_valid || m_delete || !m_Buffer || m_firstInput || m_paused) - { - for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) - bzero(ioData->mBuffers[i].mData, ioData->mBuffers[i].mDataByteSize); - if (ioActionFlags) - *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence; - m_firstInput = false; - return noErr; - } - - unsigned int size = inNumberFrames * m_OutputFormat.m_frameSize; - //unsigned int size = inNumberFrames * m_StreamFormat.m_frameSize; - - // the index is important if we run encoded - unsigned int outputBufferIndex = AE.GetHAL()->GetBufferIndex(); - - ioData->mBuffers[outputBufferIndex].mDataByteSize = GetFrames( - (uint8_t*)ioData->mBuffers[outputBufferIndex].mData, size); - if (!ioData->mBuffers[outputBufferIndex].mDataByteSize && ioActionFlags) - *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence; - - return noErr; -} - -void CCoreAudioAEStream::ResetEncoder() -{ - if (m_encoder) - m_encoder->Reset(); - m_unencodedBuffer.Empty(); -} - -bool CCoreAudioAEStream::SetupEncoder() -{ - ResetEncoder(); - delete m_encoder; - m_encoder = NULL; - - if (!m_transcode) - return false; - - m_encoder = new CAEEncoderFFmpeg(); - if (m_encoder && m_encoder->Initialize(m_encoderFormat)) - return true; - - delete m_encoder; - m_encoder = NULL; - return false; -} diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.h deleted file mode 100644 index ebb7201adf..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.h +++ /dev/null @@ -1,189 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include <samplerate.h> -#include <list> - -#include "ICoreAudioSource.h" -#include "cores/AudioEngine/Utils/AEAudioFormat.h" -#include "cores/AudioEngine/Interfaces/AEStream.h" -#include "cores/AudioEngine/Utils/AEConvert.h" -#include "cores/AudioEngine/Utils/AERemap.h" -#include "cores/AudioEngine/Utils/AELimiter.h" -#include "cores/AudioEngine/Utils/AERingBuffer.h" -#include "cores/AudioEngine/Utils/AEBuffer.h" - -#if defined(TARGET_DARWIN_IOS) -# include "CoreAudioAEHALIOS.h" -#else -# include "CoreAudioAEHALOSX.h" -#endif - -class AERingBuffer; -class CoreAudioRingBuffer; -class IAEEncoder; - -class CCoreAudioAEStream : public IAEStream, public ICoreAudioSource -{ -protected: - friend class CCoreAudioAE; - CCoreAudioAEStream(enum AEDataFormat format, unsigned int sampleRate, unsigned int encodedSamplerate, CAEChannelInfo channelLayout, unsigned int options, bool transcode); - virtual ~CCoreAudioAEStream(); - - CAUOutputDevice *m_outputUnit; - -public: - void ReinitConverter(); - void CloseConverter(); - void OpenConverter(); - - void Initialize(); - void InitializeRemap(); - virtual void Destroy(); - - virtual const unsigned int GetFrameSize() const; - virtual unsigned int GetSpace(); - virtual unsigned int AddData(void *data, unsigned int size); - unsigned int GetFrames(uint8_t *buffer, unsigned int size); - virtual double GetDelay(); - virtual bool IsBuffering(); - virtual double GetCacheTime(); - virtual double GetCacheTotal(); - - bool IsPaused(); - virtual bool IsDraining(); - virtual bool IsDrained(); - bool IsDestroyed(); - bool IsValid(); - - virtual void Pause(); - virtual void Resume(); - virtual void Drain(bool wait); - virtual void Flush(); - - virtual float GetVolume(); - virtual float GetReplayGain(); - virtual float GetAmplification() { return m_limiter.GetAmplification(); } - virtual void SetVolume(float volume); - virtual void SetReplayGain(float factor); - virtual void SetAmplification(float amplify){ m_limiter.SetAmplification(amplify); } - - virtual float RunLimiter(float* frame, int channels) { return m_limiter.Run(&frame, channels); } - - virtual const unsigned int GetChannelCount() const; - virtual const unsigned int GetSampleRate() const; - virtual const unsigned int GetEncodedSampleRate() const; - virtual const enum AEDataFormat GetDataFormat() const; - virtual const bool IsRaw() const; - - /* for dynamic sample rate changes (smoothvideo) */ - virtual double GetResampleRatio(); - virtual bool SetResampleRatio(double ratio); - - virtual void RegisterAudioCallback(IAudioCallback* pCallback); - virtual void UnRegisterAudioCallback(); - - virtual void FadeVolume(float from, float to, unsigned int time); - virtual bool IsFading(); - virtual void RegisterSlave(IAEStream *stream); - - OSStatus Render(AudioUnitRenderActionFlags* actionFlags, - const AudioTimeStamp* pTimeStamp, - UInt32 busNumber, - UInt32 frameCount, - AudioBufferList* pBufList); - -private: - void InternalFlush(); - void ResetEncoder(); - bool SetupEncoder(); - - OSStatus OnRender(AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData); - - AEDataFormat m_rawDataFormat; /* the format we're output if we're outputting in raw mode */ - AEDataFormat m_incomingFormat; /* the format of the stream being sent to us */ - - AEAudioFormat m_OutputFormat; - unsigned int m_chLayoutCountOutput; - AEAudioFormat m_StreamFormat; - unsigned int m_chLayoutCountStream; - unsigned int m_StreamBytesPerSample; - unsigned int m_OutputBytesPerSample; - - //bool m_forceResample; /* true if we are to force resample even when the rates match */ - //bool m_resample; /* true if the audio needs to be resampled */ - bool m_transcode; /* true if we need to transcode to ac3 */ - bool m_convert; /* true if the bitspersample needs converting */ - bool m_valid; /* true if the stream is valid */ - bool m_delete; /* true if CCoreAudioAE is to free this object */ - CAERemap m_remap; /* the remapper */ - float m_volume; /* the volume level */ - float m_rgain; /* replay gain level */ - CAELimiter m_limiter; /* volume amplification/limiter*/ - IAEStream *m_slave; /* slave aestream */ - - CAEConvert::AEConvertToFn m_convertFn; - - AERingBuffer *m_Buffer; - float *m_convertBuffer; /* buffer for converted data */ - int m_convertBufferSize; - //float *m_resampleBuffer; /* buffer for resample data */ - //int m_resampleBufferSize; - uint8_t *m_upmixBuffer; /* buffer for remap data */ - int m_upmixBufferSize; - uint8_t *m_remapBuffer; /* buffer for remap data */ - int m_remapBufferSize; - uint8_t *m_vizRemapBuffer; /* buffer for remap data */ - int m_vizRemapBufferSize; - - SRC_STATE *m_ssrc; - SRC_DATA m_ssrcData; - bool m_paused; - bool m_draining; - unsigned int m_AvgBytesPerSec; - - /* vizualization internals */ - CAERemap m_vizRemap; - IAudioCallback *m_audioCallback; - - /* fade values */ - bool m_fadeRunning; - bool m_fadeDirUp; - float m_fadeStep; - float m_fadeTarget; - unsigned int m_fadeTime; - bool m_isRaw; - unsigned int m_frameSize; - bool m_doRemap; - void Upmix(void *input, unsigned int channelsInput, void *output, unsigned int channelsOutput, unsigned int frames, AEDataFormat dataFormat); - bool m_firstInput; - bool m_flushRequested; - - /* the encoder */ - AEAudioFormat m_encoderFormat; - IAEEncoder *m_encoder; - CAEBuffer m_unencodedBuffer; /* this spools up the data before we encode it */ -}; - diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioGraph.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioGraph.cpp deleted file mode 100644 index e55e3000f6..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioGraph.cpp +++ /dev/null @@ -1,581 +0,0 @@ -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "CoreAudioGraph.h" - -#include "CoreAudioAEHAL.h" -#include "CoreAudioMixMap.h" -#include "CoreAudioUnit.h" - -#include "utils/log.h" -#include "utils/SystemInfo.h" - -CCoreAudioGraph::CCoreAudioGraph() : - m_audioGraph (NULL ), - m_inputUnit (NULL ), - m_audioUnit (NULL ), - m_mixerUnit (NULL ), - m_initialized (false), - m_deviceId (NULL ), - m_allowMixing (false), - m_mixMap (NULL ) -{ - for (int i = 0; i < MAX_CONNECTION_LIMIT; i++) - { - m_reservedBusNumber[i] = false; - } -} - -CCoreAudioGraph::~CCoreAudioGraph() -{ - Close(); - - delete m_mixMap; -} - -bool CCoreAudioGraph::Open(ICoreAudioSource *pSource, AEAudioFormat &format, - AudioDeviceID deviceId, bool allowMixing, AudioChannelLayoutTag layoutTag, float initVolume, bool encoded) -{ - AudioStreamBasicDescription fmt = {0}; - AudioStreamBasicDescription inputFormat = {0}; - AudioStreamBasicDescription outputFormat = {0}; - - m_deviceId = deviceId; - m_allowMixing = allowMixing; - - OSStatus ret = NewAUGraph(&m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error create audio grpah. Error = %s", GetError(ret).c_str()); - return false; - } - ret = AUGraphOpen(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error open audio grpah. Error = %s", GetError(ret).c_str()); - return false; - } - - // get output unit - if (m_audioUnit) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error audio unit already open. double call ?"); - return false; - } - - m_audioUnit = new CAUOutputDevice(); - if (!m_audioUnit->Open(m_audioGraph, - kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple)) - return false; - m_audioUnit->SetBus(GetFreeBus()); - - m_audioUnit->GetFormatDesc(format, &inputFormat, &fmt, encoded); - - if (!m_audioUnit->EnableInputOuput()) - return false; - - if (!m_audioUnit->SetCurrentDevice(deviceId)) - return false; - - SetCurrentVolume(initVolume); - - if (allowMixing) - { - delete m_mixMap; - m_mixMap = CCoreAudioMixMap::CreateMixMap(m_audioUnit, format, layoutTag); - - if (m_mixMap && m_mixMap->IsValid()) - { - // maximum input channel ber input bus - //fmt.mChannelsPerFrame = MAXIMUM_MIXER_CHANNELS; - - // get output unit - if (m_inputUnit) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error mixer unit already open. double call ?"); - return false; - } - - m_inputUnit = new CAUOutputDevice(); - - if (!m_inputUnit->Open(m_audioGraph, - kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple)) - return false; - - if (!m_inputUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) - return false; - - if (!m_inputUnit->SetFormat(&fmt, kAudioUnitScope_Output, kOutputBus)) - return false; - - // get mixer unit - if (m_mixerUnit) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error mixer unit already open. double call ?"); - return false; - } - - m_mixerUnit = new CAUMatrixMixer(); - - if (!m_mixerUnit->Open(m_audioGraph, - kAudioUnitType_Mixer, kAudioUnitSubType_MatrixMixer, kAudioUnitManufacturer_Apple)) - return false; - - // set number of input buses - if (!m_mixerUnit->SetInputBusCount(MAX_CONNECTION_LIMIT)) - return false; - - // set number of output buses - if (!m_mixerUnit->SetOutputBusCount(1)) - return false; - - if (!m_mixerUnit->SetInputBusFormat(MAX_CONNECTION_LIMIT, &fmt)) - return false; - - // Update format structure to reflect the desired format from the mixer - // The output format of the mixer is identical to the input format, except for the channel count - AudioStreamBasicDescription mixOutput(fmt); - mixOutput.mChannelsPerFrame = m_mixMap->GetOutputChannels(); - - if (!m_mixerUnit->SetFormat(&mixOutput, kAudioUnitScope_Output, kOutputBus)) - return false; - - ret = AUGraphConnectNodeInput(m_audioGraph, m_mixerUnit->GetNode(), 0, m_audioUnit->GetNode(), 0); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error connecting m_m_mixerNode. Error = %s", GetError(ret).c_str()); - return false; - } - - m_mixerUnit->SetBus(0); - - // configure output unit - int busNumber = GetFreeBus(); - - ret = AUGraphConnectNodeInput(m_audioGraph, m_inputUnit->GetNode(), 0, m_mixerUnit->GetNode(), busNumber); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error connecting m_converterNode. Error = %s", GetError(ret).c_str()); - return false; - } - - m_inputUnit->SetBus(busNumber); - - ret = AUGraphUpdate(m_audioGraph, NULL); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error update graph. Error = %s", GetError(ret).c_str()); - return false; - } - ret = AUGraphInitialize(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error initialize graph. Error = %s", GetError(ret).c_str()); - return false; - } - - UInt32 inputNumber = m_inputUnit->GetBus(); - int channelOffset = GetMixerChannelOffset(inputNumber); - if (!CCoreAudioMixMap::SetMixingMatrix(m_mixerUnit, m_mixMap, &fmt, &mixOutput, channelOffset)) - return false; - - // Regenerate audio format and copy format for the Output AU - outputFormat = mixOutput; - } - else - { - outputFormat = inputFormat; - } - - } - else - { - outputFormat = inputFormat; - } - - if (!m_audioUnit->SetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error setting input format on audio device. Channel count %d, set it to %d", - (int)outputFormat.mChannelsPerFrame, format.m_channelLayout.Count()); - outputFormat.mChannelsPerFrame = format.m_channelLayout.Count(); - if (!m_audioUnit->SetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) - return false; - } - - std::string formatString; - // asume we are in dd-wave mode - if (!m_inputUnit) - { - if (!m_audioUnit->SetFormat(&inputFormat, kAudioUnitScope_Output, kInputBus)) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error setting Device Output Stream Format %s", - StreamDescriptionToString(inputFormat, formatString)); - } - } - - ret = AUGraphUpdate(m_audioGraph, NULL); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error update graph. Error = %s", GetError(ret).c_str()); - return false; - } - - AudioStreamBasicDescription inputDesc_end, outputDesc_end; - m_audioUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); - m_audioUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kInputBus); - CLog::Log(LOGDEBUG, "CCoreAudioGraph::Open: audioUnit, Input Stream Format %s", - StreamDescriptionToString(inputDesc_end, formatString)); - CLog::Log(LOGDEBUG, "CCoreAudioGraph::Open: audioUnit, Output Stream Format %s", - StreamDescriptionToString(outputDesc_end, formatString)); - - if (m_mixerUnit) - { - m_mixerUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); - m_mixerUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kOutputBus); - CLog::Log(LOGDEBUG, "CCoreAudioGraph::Open: mixerUnit, Input Stream Format %s", - StreamDescriptionToString(inputDesc_end, formatString)); - CLog::Log(LOGDEBUG, "CCoreAudioGraph::Open: mixerUnit, Output Stream Format %s", - StreamDescriptionToString(outputDesc_end, formatString)); - } - - if (m_inputUnit) - { - m_inputUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); - m_inputUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kOutputBus); - CLog::Log(LOGDEBUG, "CCoreAudioGraph::Open: inputUnit, Input Stream Format %s", - StreamDescriptionToString(inputDesc_end, formatString)); - CLog::Log(LOGDEBUG, "CCoreAudioGraph::Open: inputUnit, Output Stream Format %s", - StreamDescriptionToString(outputDesc_end, formatString)); - } - - ret = AUGraphInitialize(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error initialize graph. Error = %s", GetError(ret).c_str()); - return false; - } - - UInt32 bufferFrames = m_audioUnit->GetBufferFrameSize(); - if (!m_audioUnit->SetMaxFramesPerSlice(bufferFrames)) - return false; - - SetInputSource(pSource); - - return Start(); -} - -bool CCoreAudioGraph::Close() -{ - if (!m_audioGraph) - return false; - - Stop(); - - SetInputSource(NULL); - - while (!m_auUnitList.empty()) - { - CAUOutputDevice *d = m_auUnitList.front(); - m_auUnitList.pop_front(); - ReleaseBus(d->GetBus()); - d->SetInputSource(NULL); - d->Close(); - delete d; - } - - if (m_inputUnit) - { - ReleaseBus(m_inputUnit->GetBus()); - m_inputUnit->Close(); - delete m_inputUnit; - m_inputUnit = NULL; - } - - if (m_mixerUnit) - { - m_mixerUnit->Close(); - delete m_mixerUnit; - m_mixerUnit = NULL; - } - - if (m_audioUnit) - { - m_audioUnit->Close(); - delete m_audioUnit; - m_audioUnit = NULL; - } - - OSStatus ret = AUGraphUninitialize(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Close: " - "Error unitialize. Error = %s", GetError(ret).c_str()); - } - - ret = AUGraphClose(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Close: " - "Error close. Error = %s", GetError(ret).c_str()); - } - - ret = DisposeAUGraph(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Close: " - "Error dispose. Error = %s", GetError(ret).c_str()); - } - - return true; -} - -bool CCoreAudioGraph::Start() -{ - if (!m_audioGraph) - return false; - - Boolean isRunning = false; - OSStatus ret = AUGraphIsRunning(m_audioGraph, &isRunning); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Start: " - "Audio graph not running. Error = %s", GetError(ret).c_str()); - return false; - } - if (!isRunning) - { - if (m_audioUnit) - m_audioUnit->Start(); - if (m_mixerUnit) - m_mixerUnit->Start(); - if (m_inputUnit) - m_inputUnit->Start(); - - ret = AUGraphStart(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Start: " - "Error starting audio graph. Error = %s", GetError(ret).c_str()); - } - } - - return true; -} - -bool CCoreAudioGraph::Stop() -{ - if (!m_audioGraph) - return false; - - Boolean isRunning = false; - OSStatus ret = AUGraphIsRunning(m_audioGraph, &isRunning); - if (ret) - { - if (m_inputUnit) - m_inputUnit->Stop(); - if (m_mixerUnit) - m_mixerUnit->Stop(); - if (m_audioUnit) - m_audioUnit->Stop(); - - CLog::Log(LOGERROR, "CCoreAudioGraph::Stop: " - "Audio graph not running. Error = %s", GetError(ret).c_str()); - return false; - } - if (isRunning) - { - ret = AUGraphStop(m_audioGraph); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Stop: " - "Error stopping audio graph. Error = %s", GetError(ret).c_str()); - } - } - - return true; -} - -AudioChannelLayoutTag CCoreAudioGraph::GetChannelLayoutTag(int layout) -{ - return g_LayoutMap[layout]; -} - -bool CCoreAudioGraph::SetInputSource(ICoreAudioSource* pSource) -{ - if (m_inputUnit) - return m_inputUnit->SetInputSource(pSource); - else if (m_audioUnit) - return m_audioUnit->SetInputSource(pSource); - - return false; -} - -bool CCoreAudioGraph::SetCurrentVolume(Float32 vol) -{ - if (!m_audioUnit) - return false; - - return m_audioUnit->SetCurrentVolume(vol); -} - -CAUOutputDevice *CCoreAudioGraph::DestroyUnit(CAUOutputDevice *outputUnit) -{ - if (!outputUnit) - return NULL; - - Stop(); - - for (AUUnitList::iterator itt = m_auUnitList.begin(); itt != m_auUnitList.end(); ++itt) - { - if (*itt == outputUnit) - { - m_auUnitList.erase(itt); - break; - } - } - - ReleaseBus(outputUnit->GetBus()); - outputUnit->SetInputSource(NULL); - outputUnit->Close(); - delete outputUnit; - - AUGraphUpdate(m_audioGraph, NULL); - - Start(); - - return NULL; -} - -CAUOutputDevice *CCoreAudioGraph::CreateUnit(AEAudioFormat &format) -{ - if (!m_audioUnit || !m_mixerUnit) - return NULL; - - AudioStreamBasicDescription fmt = {0}; - AudioStreamBasicDescription inputFormat = {0}; - AudioStreamBasicDescription outputFormat = {0}; - - int busNumber = GetFreeBus(); - if (busNumber == INVALID_BUS) - return NULL; - - OSStatus ret; - // create output unit - CAUOutputDevice *outputUnit = new CAUOutputDevice(); - if (!outputUnit->Open(m_audioGraph, - kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple)) - goto error; - - m_audioUnit->GetFormatDesc(format, &inputFormat, &fmt); - - // get the format frm the mixer - if (!m_mixerUnit->GetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) - goto error; - - if (!outputUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) - goto error; - - if (!outputUnit->SetFormat(&outputFormat, kAudioUnitScope_Output, kOutputBus)) - goto error; - - ret = AUGraphConnectNodeInput(m_audioGraph, outputUnit->GetNode(), 0, m_mixerUnit->GetNode(), busNumber); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::CreateUnit: " - "Error connecting outputUnit. Error = %s", GetError(ret).c_str()); - goto error; - } - - // TODO: setup mixmap, get free bus number for connection - - outputUnit->SetBus(busNumber); - - if (m_mixMap || m_mixMap->IsValid()) - { - UInt32 inputNumber = outputUnit->GetBus(); - int channelOffset = GetMixerChannelOffset(inputNumber); - CCoreAudioMixMap::SetMixingMatrix(m_mixerUnit, m_mixMap, &inputFormat, &fmt, channelOffset); - } - - AUGraphUpdate(m_audioGraph, NULL); - m_auUnitList.push_back(outputUnit); - - return outputUnit; - -error: - delete outputUnit; - return NULL; -} - -int CCoreAudioGraph::GetFreeBus() -{ - for (int i = 0; i < MAX_CONNECTION_LIMIT; i++) - { - if (!m_reservedBusNumber[i]) - { - m_reservedBusNumber[i] = true; - return i; - } - } - return INVALID_BUS; -} - -void CCoreAudioGraph::ReleaseBus(int busNumber) -{ - if (busNumber > MAX_CONNECTION_LIMIT || busNumber < 0) - return; - - m_reservedBusNumber[busNumber] = false; -} - -bool CCoreAudioGraph::IsBusFree(int busNumber) -{ - if (busNumber > MAX_CONNECTION_LIMIT || busNumber < 0) - return false; - return m_reservedBusNumber[busNumber]; -} - -int CCoreAudioGraph::GetMixerChannelOffset(int busNumber) -{ - if (!m_mixerUnit) - return 0; - - int offset = 0; - AudioStreamBasicDescription fmt = {0}; - - for (int i = 0; i < busNumber; i++) - { - memset(&fmt, 0x0, sizeof(fmt)); - m_mixerUnit->GetFormat(&fmt, kAudioUnitScope_Input, busNumber); - offset += fmt.mChannelsPerFrame; - } - return offset; -} diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioGraph.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioGraph.h deleted file mode 100644 index d704ac6dfc..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioGraph.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "system.h" - -#if defined(TARGET_DARWIN_OSX) -#include <list> - -#include "ICoreAudioSource.h" -#include <AudioToolbox/AUGraph.h> -#include <CoreAudio/CoreAudio.h> - -#define MAX_CONNECTION_LIMIT 8 -#define MAXIMUM_MIXER_CHANNELS 9 - -class CAUMatrixMixer; -class CAUOutputDevice; -class CCoreAudioMixMap; - -class CCoreAudioGraph -{ -public: - CCoreAudioGraph(); - ~CCoreAudioGraph(); - - bool Open(ICoreAudioSource *pSource, AEAudioFormat &format, AudioDeviceID deviceId, - bool allowMixing, AudioChannelLayoutTag layoutTag, float initVolume, bool encoded); - bool Close(); - bool Start(); - bool Stop(); - static AudioChannelLayoutTag GetChannelLayoutTag(int layout); - bool SetInputSource(ICoreAudioSource *pSource); - bool SetCurrentVolume(Float32 vol); - CAUOutputDevice* DestroyUnit(CAUOutputDevice *outputUnit); - CAUOutputDevice* CreateUnit(AEAudioFormat &format); - int GetFreeBus(); - void ReleaseBus(int busNumber); - bool IsBusFree(int busNumber); - int GetMixerChannelOffset(int busNumber); - -private: - AUGraph m_audioGraph; - - CAUOutputDevice *m_inputUnit; - CAUOutputDevice *m_audioUnit; - CAUMatrixMixer *m_mixerUnit; - - int m_reservedBusNumber[MAX_CONNECTION_LIMIT]; - bool m_initialized; - AudioDeviceID m_deviceId; - bool m_allowMixing; - CCoreAudioMixMap *m_mixMap; - - typedef std::list<CAUOutputDevice*> AUUnitList; - AUUnitList m_auUnitList; -}; - -#endif diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioMixMap.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioMixMap.cpp deleted file mode 100644 index b045ed07de..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioMixMap.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "CoreAudioMixMap.h" - -#include "CoreAudioUnit.h" -#include "CoreAudioAEHAL.h" -#include "utils/log.h" - - -#include <AudioToolbox/AudioToolbox.h> -#include <sstream> - -CCoreAudioMixMap::CCoreAudioMixMap() : - m_isValid(false) -{ - m_pMap = (Float32*)calloc(sizeof(AudioChannelLayout), 1); -} - -CCoreAudioMixMap::CCoreAudioMixMap(AudioChannelLayout& inLayout, AudioChannelLayout& outLayout) : - m_isValid(false) -{ - Rebuild(inLayout, outLayout); -} - -CCoreAudioMixMap::~CCoreAudioMixMap() -{ - free(m_pMap); - m_pMap = NULL; -} - -void CCoreAudioMixMap::Rebuild(AudioChannelLayout& inLayout, AudioChannelLayout& outLayout) -{ - // map[in][out] = mix-level of input_channel[in] into output_channel[out] - - free(m_pMap); - m_pMap = NULL; - - m_inChannels = CCoreAudioChannelLayout::GetChannelCountForLayout(inLayout); - m_outChannels = CCoreAudioChannelLayout::GetChannelCountForLayout(outLayout); - - // Try to find a 'well-known' matrix - const AudioChannelLayout* layouts[] = {&inLayout, &outLayout}; - UInt32 propSize = 0; - AudioFormatGetPropertyInfo(kAudioFormatProperty_MatrixMixMap, - sizeof(layouts), layouts, &propSize); - m_pMap = (Float32*)calloc(1,propSize); - - // Try and get a predefined mixmap - OSStatus ret = AudioFormatGetProperty(kAudioFormatProperty_MatrixMixMap, - sizeof(layouts), layouts, &propSize, m_pMap); - if (ret) - { - // If we for some reason don't find a predefined matrix let's build a diagonal matrix, - // basically guessing here, but we need to have a mixmap that matches the output and input - CLog::Log(LOGDEBUG, "CCoreAudioMixMap::CreateMap: No pre-defined mapping from %d to %d channels, building diagonal matrix.", m_inChannels, m_outChannels); - for (UInt32 chan = 0; chan < std::min(m_inChannels, m_outChannels); ++chan) - { - Float32 *vol = m_pMap + (chan * m_outChannels + chan); - CLog::Log(LOGDEBUG, "CCoreAudioMixMap::Rebuild %d = %f", chan, *vol); - *vol = 1.; - } - } - m_isValid = true; -} - -CCoreAudioMixMap *CCoreAudioMixMap::CreateMixMap(CAUOutputDevice *audioUnit, AEAudioFormat &format, AudioChannelLayoutTag layoutTag) -{ - if (!audioUnit) - return NULL; - - AudioStreamBasicDescription fmt; - AudioStreamBasicDescription inputFormat; - - // get the stream input format - audioUnit->GetFormatDesc(format, &inputFormat, &fmt); - - unsigned int channels = format.m_channelLayout.Count(); - CAEChannelInfo channelLayout = format.m_channelLayout; - bool hasLFE = false; - // Convert XBMC input channel layout format to CoreAudio layout format - AudioChannelLayout* pInLayout = (AudioChannelLayout*)malloc(sizeof(AudioChannelLayout) + sizeof(AudioChannelDescription) * channels); - pInLayout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions; - pInLayout->mChannelBitmap = 0; - pInLayout->mNumberChannelDescriptions = channels; - for (unsigned int chan=0; chan < channels; chan++) - { - AudioChannelDescription* pDesc = &pInLayout->mChannelDescriptions[chan]; - // Convert from XBMC channel tag to CoreAudio channel tag - pDesc->mChannelLabel = g_LabelMap[(unsigned int)channelLayout[chan]]; - pDesc->mChannelFlags = kAudioChannelFlags_AllOff; - pDesc->mCoordinates[0] = 0.0f; - pDesc->mCoordinates[1] = 0.0f; - pDesc->mCoordinates[2] = 0.0f; - if (pDesc->mChannelLabel == kAudioChannelLabel_LFEScreen) - hasLFE = true; - } - // HACK: Fix broken channel layouts coming from some aac sources - // that include rear channel but no side channels. - // 5.1 streams should include front and side channels. - // Rear channels are added by 6.1 and 7.1, so any 5.1 - // source that claims to have rear channels is wrong. - if (inputFormat.mChannelsPerFrame == 6 && hasLFE) - { - // Check for 5.1 configuration (as best we can without getting too silly) - for (unsigned int chan=0; chan < inputFormat.mChannelsPerFrame; chan++) - { - AudioChannelDescription* pDesc = &pInLayout->mChannelDescriptions[chan]; - if (pDesc->mChannelLabel == kAudioChannelLabel_LeftSurround || pDesc->mChannelLabel == kAudioChannelLabel_RightSurround) - break; // Required condition cannot be true - - if (pDesc->mChannelLabel == kAudioChannelLabel_LeftSurroundDirect) - { - // Change [Back Left] to [Side Left] - pDesc->mChannelLabel = kAudioChannelLabel_LeftSurround; - CLog::Log(LOGINFO, "CCoreAudioGraph::CreateMixMap: " - "Detected faulty input channel map...fixing(Back Left-->Side Left)"); - } - if (pDesc->mChannelLabel == kAudioChannelLabel_RightSurroundDirect) - { - // Change [Back Left] to [Side Left] - pDesc->mChannelLabel = kAudioChannelLabel_RightSurround; - CLog::Log(LOGINFO, "CCoreAudioGraph::CreateMixMap: " - "Detected faulty input channel map...fixing(Back Right-->Side Right)"); - } - } - } - - CCoreAudioChannelLayout sourceLayout(*pInLayout); - free(pInLayout); - pInLayout = NULL; - - std::string strInLayout; - CLog::Log(LOGDEBUG, "CCoreAudioGraph::CreateMixMap: Source Stream Layout: %s", - CCoreAudioChannelLayout::ChannelLayoutToString(*(AudioChannelLayout*)sourceLayout, strInLayout)); - - // Get User-Configured (XBMC) Speaker Configuration - AudioChannelLayout guiLayout; - guiLayout.mChannelLayoutTag = layoutTag; - CCoreAudioChannelLayout userLayout(guiLayout); - std::string strUserLayout; - CLog::Log(LOGDEBUG, "CCoreAudioGraph::CreateMixMap: User-Configured Speaker Layout: %s", - CCoreAudioChannelLayout::ChannelLayoutToString(*(AudioChannelLayout*)userLayout, strUserLayout)); - - // Get OS-Configured (Audio MIDI Setup) Speaker Configuration (Channel Layout) - CCoreAudioChannelLayout deviceLayout; - if (!audioUnit->GetPreferredChannelLayout(deviceLayout)) - return NULL; - - // When all channels on the output device are unknown take the gui layout - //if(deviceLayout.AllChannelUnknown()) - // deviceLayout.CopyLayout(guiLayout); - - std::string strOutLayout; - CLog::Log(LOGDEBUG, "CCoreAudioGraph::CreateMixMap: Output Device Layout: %s", - CCoreAudioChannelLayout::ChannelLayoutToString(*(AudioChannelLayout*)deviceLayout, strOutLayout)); - - // TODO: - // Reconcile the OS and GUI layout configurations. Clamp to the minimum number of speakers - // For each OS-defined output, see if it exists in the GUI configuration - // If it does, add it to the 'union' layout (bitmap?) - // User may have configured 5.1 in GUI, but only 2.0 in OS - // Resulting layout would be {FL, FR} - // User may have configured 2.0 in GUI, and 5.1 in OS - // Resulting layout would be {FL, FR} - - // Correct any configuration incompatibilities - //if (CCoreAudioChannelLayout::GetChannelCountForLayout(guiLayout) < CCoreAudioChannelLayout::GetChannelCountForLayout(deviceLayout)) - // deviceLayout.CopyLayout(guiLayout); - - // TODO: Skip matrix mixer if input/output are compatible - CCoreAudioMixMap *mixMap = new CCoreAudioMixMap(); - mixMap->Rebuild(*sourceLayout, *(AudioChannelLayout*)deviceLayout); - return mixMap; -} - -bool CCoreAudioMixMap::SetMixingMatrix(CAUMatrixMixer *mixerUnit, - CCoreAudioMixMap *mixMap, AudioStreamBasicDescription *inputFormat, - AudioStreamBasicDescription *fmt, int channelOffset) -{ - if (!mixerUnit || !inputFormat || !fmt) - return false; - - // Fetch the mixing unit size - UInt32 dims[2]; - UInt32 size = sizeof(dims); - AudioUnitGetProperty(mixerUnit->GetUnit(), - kAudioUnitProperty_MatrixDimensions, kAudioUnitScope_Global, 0, dims, &size); - - if(inputFormat->mChannelsPerFrame + channelOffset > dims[0]) - { - CLog::Log(LOGERROR, "CCoreAudioMixMap::SetMixingMatrix - input format doesn't fit mixer size %u+%u > %u" - , inputFormat->mChannelsPerFrame, channelOffset, dims[0]); - return false; - } - - if(fmt->mChannelsPerFrame > dims[1]) - { - CLog::Log(LOGERROR, "CCoreAudioMixMap::SetMixingMatrix - ouput format doesn't fit mixer size %u > %u" - , fmt->mChannelsPerFrame, dims[1]); - return false; - } - - if(fmt->mChannelsPerFrame < dims[1]) - { - CLog::Log(LOGWARNING, "CCoreAudioMixMap::SetMixingMatrix - ouput format doesn't specify all outputs %u < %u" - , fmt->mChannelsPerFrame, dims[1]); - } - - // Configure the mixing matrix - // The return from kAudioFormatProperty_MatrixMixMap (See Rebuild above) - // is a Float32* which is laid out like this: - // - // mapping 2 chan -> 2 chan - // 1 0 0 1 - // - // or better represented in a tow dimensional array: - // - // 1 0 - // 0 1 - // - // mapping 6 chan -> 6 chan: - // 1 0 0 0 0 0 - // 0 1 0 0 0 0 - // 0 0 1 0 0 0 - // .... - - Float32* val = (Float32*)*mixMap; - for (UInt32 i = 0; i < inputFormat->mChannelsPerFrame; ++i) - { - UInt32 j = 0; - std::stringstream layoutStr; - for (; j < fmt->mChannelsPerFrame; ++j) - { - Float32 *vol = val + (i * mixMap->m_outChannels + j); - layoutStr << *vol << ", "; - AudioUnitSetParameter(mixerUnit->GetUnit(), - kMatrixMixerParam_Volume, kAudioUnitScope_Global, ( (i + channelOffset) << 16 ) | j, *vol, 0); - } - // zero out additional outputs from this input - for (; j < dims[1]; ++j) - { - AudioUnitSetParameter(mixerUnit->GetUnit(), - kMatrixMixerParam_Volume, kAudioUnitScope_Global, ( (i + channelOffset) << 16 ) | j, 0.0f, 0); - layoutStr << "0, "; - } - - CLog::Log(LOGDEBUG, "CCoreAudioMixMap::SetMixingMatrix channel %d = [%s]", i, layoutStr.str().c_str()); - } - - CLog::Log(LOGDEBUG, "CCoreAudioGraph::Open: " - "Mixer Output Format: %d channels, %0.1f kHz, %d bits, %d bytes per frame", - (int)fmt->mChannelsPerFrame, fmt->mSampleRate / 1000.0f, (int)fmt->mBitsPerChannel, (int)fmt->mBytesPerFrame); - - if (!mixerUnit->InitMatrixMixerVolumes()) - return false; - - return true; -} - diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioMixMap.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioMixMap.h deleted file mode 100644 index a24de7f3ad..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioMixMap.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "system.h" - -#if defined(TARGET_DARWIN_OSX) - -#include "cores/AudioEngine/Utils/AEAudioFormat.h" - -#include <CoreAudio/CoreAudio.h> - -class CAUMatrixMixer; -class CAUOutputDevice; - -class CCoreAudioMixMap -{ -public: - CCoreAudioMixMap(); - CCoreAudioMixMap(AudioChannelLayout& inLayout, AudioChannelLayout& outLayout); - virtual ~CCoreAudioMixMap(); - - operator Float32*() const {return m_pMap;} - - const Float32* GetBuffer() {return m_pMap;} - UInt32 GetInputChannels() {return m_inChannels;} - UInt32 GetOutputChannels() {return m_outChannels;} - bool IsValid() {return m_isValid;} - void Rebuild(AudioChannelLayout& inLayout, AudioChannelLayout& outLayout); - static CCoreAudioMixMap *CreateMixMap(CAUOutputDevice *audioUnit, - AEAudioFormat &format, AudioChannelLayoutTag layoutTag); - static bool SetMixingMatrix(CAUMatrixMixer *mixerUnit, CCoreAudioMixMap *mixMap, - AudioStreamBasicDescription *inputFormat, AudioStreamBasicDescription *fmt, int channelOffset); -private: - Float32 *m_pMap; - UInt32 m_inChannels; - UInt32 m_outChannels; - bool m_isValid; -}; - -#endif diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioUnit.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioUnit.cpp deleted file mode 100644 index 03b2fdce7c..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioUnit.cpp +++ /dev/null @@ -1,816 +0,0 @@ -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "CoreAudioUnit.h" - -#include "CoreAudioAEHAL.h" -#include "cores/AudioEngine/Utils/AEUtil.h" -#include "utils/log.h" - -#include <AudioToolbox/AUGraph.h> - -CCoreAudioUnit::CCoreAudioUnit() : - m_pSource (NULL ), - m_audioUnit (NULL ), - m_audioNode (NULL ), - m_audioGraph (NULL ), - m_Initialized (false ), - m_renderProc (NULL ), - m_busNumber (INVALID_BUS ) -{ -} - -CCoreAudioUnit::~CCoreAudioUnit() -{ - Close(); -} - -bool CCoreAudioUnit::Open(AUGraph audioGraph, AudioComponentDescription desc) -{ - if (m_audioUnit) - Close(); - - OSStatus ret; - - m_Initialized = false; - - ret = AUGraphAddNode(audioGraph, &desc, &m_audioNode); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error add m_outputNode. Error = %s", GetError(ret).c_str()); - return false; - } - - ret = AUGraphNodeInfo(audioGraph, m_audioNode, 0, &m_audioUnit); - if (ret) - { - CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " - "Error getting m_outputNode. Error = %s", GetError(ret).c_str()); - return false; - } - - m_audioGraph = audioGraph; - m_Initialized = true; - - return true; -} - -bool CCoreAudioUnit::Open(AUGraph audioGraph, OSType type, OSType subType, OSType manufacturer) -{ - AudioComponentDescription desc = {0}; - desc.componentType = type; - desc.componentSubType = subType; - desc.componentManufacturer = manufacturer; - - return Open(audioGraph, desc); -} - -void CCoreAudioUnit::Close() -{ - if (!m_Initialized && !m_audioUnit) - return; - - if (m_renderProc) - SetInputSource(NULL); - - Stop(); - - if (m_busNumber != INVALID_BUS) - { - OSStatus ret = AUGraphDisconnectNodeInput(m_audioGraph, m_audioNode, m_busNumber); - if (ret && ret != kAUGraphErr_NodeNotFound) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::Close: " - "Unable to disconnect AudioUnit. Error = %s", GetError(ret).c_str()); - } - - ret = AUGraphRemoveNode(m_audioGraph, m_audioNode); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::Close: " - "Unable to remove AudioUnit. Error = %s", GetError(ret).c_str()); - } - } - - AUGraphUpdate(m_audioGraph, NULL); - - m_Initialized = false; - m_audioUnit = NULL; - m_audioNode = NULL; - m_pSource = NULL; -} - -bool CCoreAudioUnit::GetFormat(AudioStreamBasicDescription* pDesc, AudioUnitScope scope, AudioUnitElement bus) -{ - if (!m_audioUnit || !pDesc) - return false; - - UInt32 size = sizeof(AudioStreamBasicDescription); - OSStatus ret = AudioUnitGetProperty(m_audioUnit, - kAudioUnitProperty_StreamFormat, scope, bus, pDesc, &size); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::GetFormat: " - "Unable to get AudioUnit format. Bus : %d Scope : %d : Error = %s", - (int)bus, (int)scope, GetError(ret).c_str()); - return false; - } - return true; -} - -bool CCoreAudioUnit::SetFormat(AudioStreamBasicDescription* pDesc, AudioUnitScope scope, AudioUnitElement bus) -{ - if (!m_audioUnit || !pDesc) - return false; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, - kAudioUnitProperty_StreamFormat, scope, bus, pDesc, sizeof(AudioStreamBasicDescription)); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetFormat: " - "Unable to set AudioUnit format. Bus : %d Scope : %d : Error = %s", - (int)bus, (int)scope, GetError(ret).c_str()); - return false; - } - return true; -} - -bool CCoreAudioUnit::SetMaxFramesPerSlice(UInt32 maxFrames) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, - kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFrames, sizeof(UInt32)); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetMaxFramesPerSlice: " - "Unable to set AudioUnit max frames per slice. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - -bool CCoreAudioUnit::GetSupportedChannelLayouts(AudioChannelLayoutList* pLayouts) -{ - if (!m_audioUnit || !pLayouts) - return false; - - UInt32 propSize = 0; - Boolean writable = false; - OSStatus ret = AudioUnitGetPropertyInfo(m_audioUnit, - kAudioUnitProperty_SupportedChannelLayoutTags, kAudioUnitScope_Input, 0, &propSize, &writable); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::GetSupportedChannelLayouts: " - "Unable to retrieve supported channel layout property info. Error = %s", GetError(ret).c_str()); - return false; - } - UInt32 layoutCount = propSize / sizeof(AudioChannelLayoutTag); - AudioChannelLayoutTag* pSuppLayouts = new AudioChannelLayoutTag[layoutCount]; - ret = AudioUnitGetProperty(m_audioUnit, - kAudioUnitProperty_SupportedChannelLayoutTags, kAudioUnitScope_Output, 0, pSuppLayouts, &propSize); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::GetSupportedChannelLayouts: " - "Unable to retrieve supported channel layouts. Error = %s", GetError(ret).c_str()); - return false; - } - for (UInt32 layout = 0; layout < layoutCount; layout++) - pLayouts->push_back(pSuppLayouts[layout]); - delete[] pSuppLayouts; - return true; -} - -bool CCoreAudioUnit::SetInputSource(ICoreAudioSource* pSource) -{ - m_pSource = pSource; - if (pSource) - return SetRenderProc(); - else - return RemoveRenderProc(); -} - -bool CCoreAudioUnit::SetRenderProc() -{ - if (!m_audioUnit || m_renderProc) - return false; - - AURenderCallbackStruct callbackInfo; - callbackInfo.inputProc = RenderCallback; // Function to be called each time the AudioUnit needs data - callbackInfo.inputProcRefCon = this; // Pointer to be returned in the callback proc - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, &callbackInfo, sizeof(AURenderCallbackStruct)); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetRenderProc: " - "Unable to set AudioUnit render callback. Error = %s", GetError(ret).c_str()); - return false; - } - - m_renderProc = RenderCallback; - - return true; -} - -bool CCoreAudioUnit::RemoveRenderProc() -{ - if (!m_audioUnit || !m_renderProc) - return false; - - AudioUnitInitialize(m_audioUnit); - - AURenderCallbackStruct callbackInfo; - callbackInfo.inputProc = nil; - callbackInfo.inputProcRefCon = nil; - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, &callbackInfo, sizeof(AURenderCallbackStruct)); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::RemoveRenderProc: " - "Unable to remove AudioUnit render callback. Error = %s", GetError(ret).c_str()); - return false; - } - - m_renderProc = NULL; - Sleep(100); - - return true; -} - -OSStatus CCoreAudioUnit::RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) -{ - OSStatus ret = noErr; - CCoreAudioUnit *audioUnit = (CCoreAudioUnit*)inRefCon; - - if (audioUnit->m_pSource) - { - ret = audioUnit->m_pSource->Render(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); - } - else - { - ioData->mBuffers[0].mDataByteSize = 0; - if (ioActionFlags) - *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence; - } - - - return ret; -} - -void CCoreAudioUnit::GetFormatDesc(AEAudioFormat format, - AudioStreamBasicDescription *streamDesc, AudioStreamBasicDescription *coreaudioDesc, bool encoded) -{ - unsigned int bps = CAEUtil::DataFormatToBits(format.m_dataFormat); - - // Set the input stream format for the AudioUnit - // We use the default DefaultOuput AudioUnit, so we only can set the input stream format. - // The autput format is automaticaly set to the input format. - streamDesc->mFormatID = kAudioFormatLinearPCM; // Data encoding format - streamDesc->mFormatFlags = kLinearPCMFormatFlagIsPacked; - switch (format.m_dataFormat) - { - case AE_FMT_FLOAT: - case AE_FMT_LPCM: - streamDesc->mFormatFlags |= kAudioFormatFlagsNativeEndian; - streamDesc->mFormatFlags |= kAudioFormatFlagIsFloat; - break; - case AE_FMT_AC3: - case AE_FMT_DTS: - case AE_FMT_DTSHD: - case AE_FMT_TRUEHD: - case AE_FMT_EAC3: - streamDesc->mFormatFlags |= kAudioFormatFlagsNativeEndian; - streamDesc->mFormatFlags |= kAudioFormatFlagsAudioUnitCanonical; - break; - case AE_FMT_S16LE: - if (encoded) - streamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; - else - streamDesc->mFormatFlags |= kAudioFormatFlagsAudioUnitCanonical; - break; - case AE_FMT_S16BE: - streamDesc->mFormatFlags |= kAudioFormatFlagIsBigEndian; - if (encoded) - streamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; - else - streamDesc->mFormatFlags |= kAudioFormatFlagsAudioUnitCanonical; - break; - default: - streamDesc->mFormatFlags |= kAudioFormatFlagsNativeEndian; - if (encoded) - streamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger; - else - streamDesc->mFormatFlags |= kAudioFormatFlagsAudioUnitCanonical; - break; - } - streamDesc->mChannelsPerFrame = format.m_channelLayout.Count(); // Number of interleaved audiochannels - streamDesc->mSampleRate = (Float64)format.m_sampleRate; // the sample rate of the audio stream - streamDesc->mBitsPerChannel = bps; // Number of bits per sample, per channel - streamDesc->mBytesPerFrame = (bps>>3) * format.m_channelLayout.Count(); // Size of a frame == 1 sample per channel - streamDesc->mFramesPerPacket = 1; // The smallest amount of indivisible data. Always 1 for uncompressed audio - streamDesc->mBytesPerPacket = streamDesc->mBytesPerFrame * streamDesc->mFramesPerPacket; - streamDesc->mReserved = 0; - - // Audio units use noninterleaved 32-bit floating point - // linear PCM data for input and output, ...except in the - // case of an audio unit that is a data format converter, - // which converts to or from this format. - coreaudioDesc->mFormatID = kAudioFormatLinearPCM; - coreaudioDesc->mFormatFlags = kAudioFormatFlagsNativeEndian | - kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved; - switch (format.m_dataFormat) - { - case AE_FMT_FLOAT: - coreaudioDesc->mFormatFlags |= kAudioFormatFlagIsFloat; - default: - coreaudioDesc->mFormatFlags |= kAudioFormatFlagsAudioUnitCanonical; - break; - } - coreaudioDesc->mBitsPerChannel = bps; //sizeof(Float32)<<3; - coreaudioDesc->mSampleRate = (Float64)format.m_sampleRate;; - coreaudioDesc->mFramesPerPacket = 1; - coreaudioDesc->mChannelsPerFrame = streamDesc->mChannelsPerFrame; - coreaudioDesc->mBytesPerFrame = (bps>>3); //sizeof(Float32); - coreaudioDesc->mBytesPerPacket = (bps>>3); //sizeof(Float32); -} - -float CCoreAudioUnit::GetLatency() -{ - if (!m_audioUnit) - return 0.0f; - - Float64 latency; - UInt32 size = sizeof(latency); - - OSStatus ret = AudioUnitGetProperty(m_audioUnit, - kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, &latency, &size); - - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::GetLatency: " - "Unable to set AudioUnit latency. Error = %s", GetError(ret).c_str()); - return 0.0f; - } - - return latency; -} - -bool CCoreAudioUnit::Stop() -{ - if (!m_audioUnit) - return false; - - AudioOutputUnitStop(m_audioUnit); - - return true; -} - -bool CCoreAudioUnit::Start() -{ - if (!m_audioUnit) - return false; - - AudioOutputUnitStart(m_audioUnit); - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CAUOutputDevice -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -CAUOutputDevice::CAUOutputDevice() : - m_DeviceId (NULL ) -{ -} - -CAUOutputDevice::~CAUOutputDevice() -{ -} - -bool CAUOutputDevice::SetCurrentDevice(AudioDeviceID deviceId) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, kOutputBus, &deviceId, sizeof(AudioDeviceID)); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetCurrentDevice: " - "Unable to set current device. Error = %s", GetError(ret).c_str()); - return false; - } - - m_DeviceId = deviceId; - - return true; -} - -bool CAUOutputDevice::GetChannelMap(CoreAudioChannelList* pChannelMap) -{ - if (!m_audioUnit) - return false; - - UInt32 size = 0; - Boolean writable = false; - AudioUnitGetPropertyInfo(m_audioUnit, - kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Input, 0, &size, &writable); - - UInt32 channels = size/sizeof(SInt32); - SInt32* pMap = new SInt32[channels]; - OSStatus ret = AudioUnitGetProperty(m_audioUnit, - kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Input, 0, pMap, &size); - if (ret != noErr) - CLog::Log(LOGERROR, "CCoreAudioUnit::GetInputChannelMap: " - "Unable to retrieve AudioUnit input channel map. Error = %s", GetError(ret).c_str()); - else - for (UInt32 i = 0; i < channels; i++) - pChannelMap->push_back(pMap[i]); - delete[] pMap; - return (!ret); -} - -bool CAUOutputDevice::SetChannelMap(CoreAudioChannelList* pChannelMap) -{ - // The number of array elements must match the - // number of output channels provided by the device - if (!m_audioUnit || !pChannelMap) - return false; - - UInt32 channels = pChannelMap->size(); - UInt32 size = sizeof(SInt32) * channels; - SInt32* pMap = new SInt32[channels]; - for (UInt32 i = 0; i < channels; i++) - pMap[i] = (*pChannelMap)[i]; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, - kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Input, 0, pMap, size); - if (ret != noErr) - CLog::Log(LOGERROR, "CCoreAudioUnit::GetBufferFrameSize: " - "Unable to get current device's buffer size. Error = %s", GetError(ret).c_str()); - delete[] pMap; - return (!ret); -} - -Float32 CAUOutputDevice::GetCurrentVolume() -{ - if (!m_audioUnit) - return 0.0f; - - Float32 volPct = 0.0f; - OSStatus ret = AudioUnitGetParameter(m_audioUnit, - kHALOutputParam_Volume, kAudioUnitScope_Global, 0, &volPct); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::GetCurrentVolume: " - "Unable to get AudioUnit volume. Error = %s", GetError(ret).c_str()); - return 0.0f; - } - return volPct; -} - -bool CAUOutputDevice::SetCurrentVolume(Float32 vol) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetParameter(m_audioUnit, kHALOutputParam_Volume, - kAudioUnitScope_Global, 0, vol, 0); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::SetCurrentVolume: " - "Unable to set AudioUnit volume. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - -UInt32 CAUOutputDevice::GetBufferFrameSize() -{ - if (!m_audioUnit) - return 0; - - UInt32 bufferSize = 0; - UInt32 size = sizeof(UInt32); - - OSStatus ret = AudioUnitGetProperty(m_audioUnit, - kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Input, 0, &bufferSize, &size); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CCoreAudioUnit::GetBufferFrameSize: " - "Unable to get current device's buffer size. Error = %s", GetError(ret).c_str()); - return 0; - } - return bufferSize; -} - -bool CAUOutputDevice::EnableInputOuput() -{ - if (!m_audioUnit) - return false; - - UInt32 hasio; - UInt32 size=sizeof(UInt32); - OSStatus ret = AudioUnitGetProperty(m_audioUnit, - kAudioOutputUnitProperty_HasIO,kAudioUnitScope_Input, 1, &hasio, &size); - - if (hasio) - { - UInt32 enable; - enable = 0; - ret = AudioUnitSetProperty(m_audioUnit, - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &enable, sizeof(enable)); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CAUOutputDevice::EnableInputOuput:: " - "Unable to enable input on bus 1. Error = %s", GetError(ret).c_str()); - return false; - } - - enable = 1; - ret = AudioUnitSetProperty(m_audioUnit, - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &enable, sizeof(enable)); - if (ret != noErr) - { - CLog::Log(LOGERROR, "CAUOutputDevice::EnableInputOuput:: " - "Unable to disable output on bus 0. Error = %s", GetError(ret).c_str()); - return false; - } - } - - return true; -} - -bool CAUOutputDevice::GetPreferredChannelLayout(CCoreAudioChannelLayout& layout) -{ - if (!m_DeviceId) - return false; - - AudioObjectPropertyAddress propertyAddress; - propertyAddress.mScope = kAudioDevicePropertyScopeOutput; - propertyAddress.mElement = 0; - propertyAddress.mSelector = kAudioDevicePropertyPreferredChannelLayout; - if (!AudioObjectHasProperty(m_DeviceId, &propertyAddress)) - return false; - - UInt32 propertySize = 0; - OSStatus ret = AudioObjectGetPropertyDataSize(m_DeviceId, &propertyAddress, 0, NULL, &propertySize); - if (ret != noErr) - CLog::Log(LOGERROR, "CAUOutputDevice::GetPreferredChannelLayout: " - "Unable to retrieve preferred channel layout size. Error = %s", GetError(ret).c_str()); - - void *pBuf = malloc(propertySize); - ret = AudioObjectGetPropertyData(m_DeviceId, &propertyAddress, 0, NULL, &propertySize, pBuf); - if (ret != noErr) - CLog::Log(LOGERROR, "CAUOutputDevice::GetPreferredChannelLayout: " - "Unable to retrieve preferred channel layout. Error = %s", GetError(ret).c_str()); - else - { - // Copy the result into the caller's instance - layout.CopyLayout(*((AudioChannelLayout*)pBuf)); - } - free(pBuf); - return (ret == noErr); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CAUMatrixMixer -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -CAUMatrixMixer::CAUMatrixMixer() -{ -} - -CAUMatrixMixer::~CAUMatrixMixer() -{ -} - -bool CAUMatrixMixer::InitMatrixMixerVolumes() -{ - // Fetch thechannel configuration - UInt32 dims[2]; - UInt32 size = sizeof(dims); - OSStatus ret = AudioUnitGetProperty(m_audioUnit, - kAudioUnitProperty_MatrixDimensions, kAudioUnitScope_Global, 0, dims, &size); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::Initialize:: " - "Get matrix dimesion. Error = %s", GetError(ret).c_str()); - return false; - } - - // Initialize global, input, and output levels - if (!SetGlobalVolume(1.0f)) - return false; - for (UInt32 i = 0; i < dims[0]; i++) - if (!SetInputVolume(i, 1.0f)) - return false; - for (UInt32 i = 0; i < dims[1]; i++) - if (!SetOutputVolume(i, 1.0f)) - return false; - - return true; -} - -UInt32 CAUMatrixMixer::GetInputBusCount() -{ - if (!m_audioUnit) - return 0; - - UInt32 busCount = 0; - UInt32 size = sizeof(busCount); - OSStatus ret = AudioUnitGetProperty(m_audioUnit, - kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, &size); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::GetInputBusCount: " - "Unable to get input bus count. Error = %s", GetError(ret).c_str()); - return 0; - } - return busCount; -} - -bool CAUMatrixMixer::SetInputBusFormat(UInt32 busCount, AudioStreamBasicDescription *pFormat) -{ - if (!m_audioUnit) - return false; - - UInt32 enable = 1; - for (UInt32 i = 0; i < busCount; i++) - { - AudioUnitSetParameter(m_audioUnit, kMatrixMixerParam_Enable, kAudioUnitScope_Input, i, enable, 0); - if (!SetFormat(pFormat, kAudioUnitScope_Input, i)) - return false; - } - - return true; -} - -bool CAUMatrixMixer::SetInputBusCount(UInt32 busCount) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, - kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(UInt32)); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::SetInputBusCount: " - "Unable to set input bus count. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - -UInt32 CAUMatrixMixer::GetOutputBusCount() -{ - if (!m_audioUnit) - return 0; - - UInt32 busCount = 0; - UInt32 size = sizeof(busCount); - OSStatus ret = AudioUnitGetProperty(m_audioUnit, - kAudioUnitProperty_ElementCount, kAudioUnitScope_Output, 0, &busCount, &size); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::GetOutputBusCount: " - "Unable to get output bus count. Error = %s", GetError(ret).c_str()); - return 0; - } - return busCount; -} - -bool CAUMatrixMixer::SetOutputBusCount(UInt32 busCount) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetProperty(m_audioUnit, - kAudioUnitProperty_BusCount, kAudioUnitScope_Output, 0, &busCount, sizeof(UInt32)); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::SetOutputBusCount: " - "Unable to set output bus count. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - -Float32 CAUMatrixMixer::GetGlobalVolume() -{ - if (!m_audioUnit) - return 0.0f; - - Float32 vol = 0.0f; - OSStatus ret = AudioUnitGetParameter(m_audioUnit, - kMatrixMixerParam_Volume, kAudioUnitScope_Global, 0xFFFFFFFF, &vol); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::GetGlobalVolume: " - "Unable to get global volume. Error = %s", GetError(ret).c_str()); - return 0.0f; - } - return vol; -} - -bool CAUMatrixMixer::SetGlobalVolume(Float32 vol) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetParameter(m_audioUnit, - kMatrixMixerParam_Volume, kAudioUnitScope_Global, 0xFFFFFFFF, vol, 0); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::SetGlobalVolume: " - "Unable to set global volume. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - -Float32 CAUMatrixMixer::GetInputVolume(UInt32 element) -{ - if (!m_audioUnit) - return 0.0f; - - Float32 vol = 0.0f; - OSStatus ret = AudioUnitGetParameter(m_audioUnit, - kMatrixMixerParam_Volume, kAudioUnitScope_Input, element, &vol); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::GetInputVolume: " - "Unable to get input volume. Error = %s", GetError(ret).c_str()); - return 0.0f; - } - return vol; -} - -bool CAUMatrixMixer::SetInputVolume(UInt32 element, Float32 vol) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetParameter(m_audioUnit, - kMatrixMixerParam_Volume, kAudioUnitScope_Input, element, vol, 0); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::SetInputVolume: " - "Unable to set input volume. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - -Float32 CAUMatrixMixer::GetOutputVolume(UInt32 element) -{ - if (!m_audioUnit) - return 0.0f; - - Float32 vol = 0.0f; - OSStatus ret = AudioUnitGetParameter(m_audioUnit, - kMatrixMixerParam_Volume, kAudioUnitScope_Output, element, &vol); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::GetOutputVolume: " - "Unable to get output volume. Error = %s", GetError(ret).c_str()); - return 0.0f; - } - return vol; -} - -bool CAUMatrixMixer::SetOutputVolume(UInt32 element, Float32 vol) -{ - if (!m_audioUnit) - return false; - - OSStatus ret = AudioUnitSetParameter(m_audioUnit, - kMatrixMixerParam_Volume, kAudioUnitScope_Output, element, vol, 0); - if (ret) - { - CLog::Log(LOGERROR, "CAUMatrixMixer::SetOutputVolume: " - "Unable to set output volume. Error = %s", GetError(ret).c_str()); - return false; - } - return true; -} - diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioUnit.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioUnit.h deleted file mode 100644 index d300a18104..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioUnit.h +++ /dev/null @@ -1,121 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "system.h" - -#if defined(TARGET_DARWIN_OSX) - -#define INVALID_BUS -1 -#define kOutputBus 0 -#define kInputBus 1 - -#include "ICoreAudioSource.h" -#include "CoreAudioChannelLayout.h" - -#include <AudioToolbox/AUGraph.h> -#include <CoreAudio/CoreAudio.h> -#include <CoreServices/CoreServices.h> - -class CCoreAudioUnit -{ -public: - CCoreAudioUnit(); - virtual ~CCoreAudioUnit(); - - virtual bool Open(AUGraph audioGraph, AudioComponentDescription desc); - virtual bool Open(AUGraph audioGraph, OSType type, OSType subType, OSType manufacturer); - virtual void Close(); - virtual bool SetInputSource(ICoreAudioSource *pSource); - virtual bool IsInitialized() {return m_Initialized;} - virtual bool GetFormat(AudioStreamBasicDescription *pDesc, AudioUnitScope scope, AudioUnitElement bus); - virtual bool SetFormat(AudioStreamBasicDescription *pDesc, AudioUnitScope scope, AudioUnitElement bus); - virtual bool SetMaxFramesPerSlice(UInt32 maxFrames); - virtual bool GetSupportedChannelLayouts(AudioChannelLayoutList* pLayouts); - virtual void GetFormatDesc(AEAudioFormat format, - AudioStreamBasicDescription *streamDesc, AudioStreamBasicDescription *coreaudioDesc, bool encoded = false); - virtual float GetLatency(); - virtual bool Stop(); - virtual bool Start(); - virtual AudioUnit GetUnit (){return m_audioUnit;} - virtual AUGraph GetGraph (){return m_audioGraph;} - virtual AUNode GetNode (){return m_audioNode;} - virtual int GetBus (){return m_busNumber;} - virtual void SetBus (int busNumber){m_busNumber = busNumber;} - -protected: - bool SetRenderProc(); - bool RemoveRenderProc(); - static OSStatus RenderCallback(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); - - ICoreAudioSource* m_pSource; - AudioUnit m_audioUnit; - AUNode m_audioNode; - AUGraph m_audioGraph; - bool m_Initialized; - AURenderCallback m_renderProc; - int m_busNumber; -}; - -class CAUOutputDevice : public CCoreAudioUnit -{ -public: - CAUOutputDevice(); - virtual ~CAUOutputDevice(); - - bool SetCurrentDevice(AudioDeviceID deviceId); - bool GetChannelMap(CoreAudioChannelList *pChannelMap); - bool SetChannelMap(CoreAudioChannelList *pChannelMap); - UInt32 GetBufferFrameSize(); - - Float32 GetCurrentVolume(); - bool SetCurrentVolume(Float32 vol); - bool EnableInputOuput(); - virtual bool GetPreferredChannelLayout(CCoreAudioChannelLayout &layout); - -protected: - AudioDeviceID m_DeviceId; -}; - -class CAUMatrixMixer : public CAUOutputDevice -{ -public: - CAUMatrixMixer(); - virtual ~CAUMatrixMixer(); - - bool InitMatrixMixerVolumes(); - - UInt32 GetInputBusCount(); - bool SetInputBusFormat(UInt32 busCount, AudioStreamBasicDescription *pFormat); - bool SetInputBusCount(UInt32 busCount); - UInt32 GetOutputBusCount(); - bool SetOutputBusCount(UInt32 busCount); - - Float32 GetGlobalVolume(); - bool SetGlobalVolume(Float32 vol); - Float32 GetInputVolume(UInt32 element); - bool SetInputVolume(UInt32 element, Float32 vol); - Float32 GetOutputVolume(UInt32 element); - bool SetOutputVolume(UInt32 element, Float32 vol); -}; - -#endif
\ No newline at end of file diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/ICoreAudioAEHAL.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/ICoreAudioAEHAL.h deleted file mode 100644 index 9c6936cbca..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/ICoreAudioAEHAL.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "cores/AudioEngine/Utils/AEAudioFormat.h" -#include "cores/AudioEngine/Interfaces/AE.h" -#include "ICoreAudioSource.h" - -class ICoreAudioAEHAL; -class CAUOutputDevice; - -/** - * ICoreAudioAEHAL Interface - */ -class ICoreAudioAEHAL -{ -protected: - ICoreAudioAEHAL() {} - virtual ~ICoreAudioAEHAL() {} - -public: - virtual bool Initialize(ICoreAudioSource *ae, bool passThrough, AEAudioFormat &format, AEDataFormat rawDataFormat, std::string &device, float initVolume) = 0; - virtual void Deinitialize() = 0; - virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough) = 0; - //virtual CAUOutputDevice *DestroyUnit(CAUOutputDevice *outputUnit); - //virtual CAUOutputDevice *CreateUnit(ICoreAudioSource *pSource, AEAudioFormat &format); - //virtual void SetDirectInput(ICoreAudioSource *pSource, AEAudioFormat &format); - virtual void Stop() = 0; - virtual bool Start() = 0; - virtual double GetDelay() = 0; - virtual void SetVolume(float volume) = 0; -}; diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/ICoreAudioSource.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/ICoreAudioSource.h deleted file mode 100644 index 5930ec282b..0000000000 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/ICoreAudioSource.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -/* - * Copyright (C) 2011-2013 Team XBMC - * http://xbmc.org - * - * This Program 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, or (at your option) - * any later version. - * - * This Program 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 XBMC; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include <AudioUnit/AudioUnit.h> - -#include "cores/AudioEngine/Utils/AEAudioFormat.h" -#include "cores/AudioEngine/Interfaces/AE.h" -#include "utils/StdString.h" - -class ICoreAudioSource; - -/** - * ICoreAudioSource Interface - */ -class ICoreAudioSource -{ -private: - std::string m_inputName; - AudioUnitElement m_inputBus; -public: - // Function to request rendered data from a data source - virtual OSStatus Render(AudioUnitRenderActionFlags* actionFlags, - const AudioTimeStamp* pTimeStamp, - UInt32 busNumber, - UInt32 frameCount, - AudioBufferList* pBufList) = 0; - //std::string InputName() { return m_inputName; }; - //void InputName(std::string inputName) { m_inputName = inputName; }; - - //AudioUnitElement InputBus() { return m_inputBus; }; - //void InputBus(AudioUnitElement inputBus) { m_inputBus = m_inputBus; }; -}; diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in index 3815a16bcb..c22c87e874 100644 --- a/xbmc/cores/AudioEngine/Makefile.in +++ b/xbmc/cores/AudioEngine/Makefile.in @@ -20,21 +20,6 @@ CXXFLAGS += -D__STDC_LIMIT_MACROS SRCS = AEFactory.cpp -ifeq ($(findstring osx,@ARCH@),osx) -SRCS += Engines/CoreAudio/CoreAudioAE.cpp -SRCS += Engines/CoreAudio/CoreAudioAEHAL.cpp -SRCS += Engines/CoreAudio/CoreAudioAEHALOSX.cpp -SRCS += Engines/CoreAudio/CoreAudioAESound.cpp -SRCS += Engines/CoreAudio/CoreAudioAEStream.cpp -SRCS += Engines/CoreAudio/CoreAudioChannelLayout.cpp -SRCS += Engines/CoreAudio/CoreAudioDevice.cpp -SRCS += Engines/CoreAudio/CoreAudioGraph.cpp -SRCS += Engines/CoreAudio/CoreAudioHardware.cpp -SRCS += Engines/CoreAudio/CoreAudioMixMap.cpp -SRCS += Engines/CoreAudio/CoreAudioStream.cpp -SRCS += Engines/CoreAudio/CoreAudioUnit.cpp -else - SRCS += AESinkFactory.cpp SRCS += Sinks/AESinkNULL.cpp SRCS += Sinks/AESinkProfiler.cpp @@ -50,6 +35,15 @@ SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp ifeq (@USE_ANDROID@,1) SRCS += Sinks/AESinkAUDIOTRACK.cpp +else ifeq ($(findstring ios,@ARCH@),ios) +SRCS += Sinks/AESinkDARWINIOS.cpp +else ifeq ($(findstring osx,@ARCH@),osx) +SRCS += Sinks/AESinkDARWINOSX.cpp +SRCS += Sinks/osx/CoreAudioChannelCount.cpp +SRCS += Sinks/osx/CoreAudioDevice.cpp +SRCS += Sinks/osx/CoreAudioHardware.cpp +SRCS += Sinks/osx/CoreAudioHelpers.cpp +SRCS += Sinks/osx/CoreAudioStream.cpp else SRCS += Sinks/AESinkALSA.cpp SRCS += Sinks/AESinkOSS.cpp @@ -57,7 +51,6 @@ ifeq (@USE_PULSE@,1) SRCS += Sinks/AESinkPULSE.cpp endif endif -endif SRCS += Utils/AEChannelInfo.cpp SRCS += Utils/AEBuffer.cpp diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINIOS.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINIOS.cpp new file mode 100644 index 0000000000..fa49cba2fb --- /dev/null +++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINIOS.cpp @@ -0,0 +1,780 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program 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, or (at your option) + * any later version. + * + * This Program 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "cores/AudioEngine/Sinks/AESinkDARWINIOS.h" +#include "cores/AudioEngine/Utils/AEUtil.h" +#include "cores/AudioEngine/Utils/AERingBuffer.h" +#include "cores/AudioEngine/Sinks/osx/CoreAudioHelpers.h" +#include "osx/DarwinUtils.h" +#include "utils/log.h" +#include "utils/StringUtils.h" +#include "threads/Condition.h" +#include "windowing/WindowingFactory.h" + +#include <sstream> +#include <AudioToolbox/AudioToolbox.h> + +#define CA_MAX_CHANNELS 8 +static enum AEChannel CAChannelMap[CA_MAX_CHANNELS + 1] = { + AE_CH_FL , AE_CH_FR , AE_CH_BL , AE_CH_BR , AE_CH_FC , AE_CH_LFE , AE_CH_SL , AE_CH_SR , + AE_CH_NULL +}; + +/***************************************************************************************/ +/***************************************************************************************/ +#if DO_440HZ_TONE_TEST +static void SineWaveGeneratorInitWithFrequency(SineWaveGenerator *ctx, double frequency, double samplerate) +{ + // Given: + // frequency in cycles per second + // 2*PI radians per sine wave cycle + // sample rate in samples per second + // + // Then: + // cycles radians seconds radians + // ------ * ------- * ------- = ------- + // second cycle sample sample + ctx->currentPhase = 0.0; + ctx->phaseIncrement = frequency * 2*M_PI / samplerate; +} + +static int16_t SineWaveGeneratorNextSampleInt16(SineWaveGenerator *ctx) +{ + int16_t sample = INT16_MAX * sinf(ctx->currentPhase); + + ctx->currentPhase += ctx->phaseIncrement; + // Keep the value between 0 and 2*M_PI + while (ctx->currentPhase > 2*M_PI) + ctx->currentPhase -= 2*M_PI; + + return sample / 4; +} +static float SineWaveGeneratorNextSampleFloat(SineWaveGenerator *ctx) +{ + float sample = MAXFLOAT * sinf(ctx->currentPhase); + + ctx->currentPhase += ctx->phaseIncrement; + // Keep the value between 0 and 2*M_PI + while (ctx->currentPhase > 2*M_PI) + ctx->currentPhase -= 2*M_PI; + + return sample / 4; +} +#endif + +/***************************************************************************************/ +/***************************************************************************************/ +class CAAudioUnitSink +{ + public: + CAAudioUnitSink(); + ~CAAudioUnitSink(); + + bool open(AudioStreamBasicDescription outputFormat); + bool close(); + bool play(bool mute); + bool mute(bool mute); + bool pause(); + void drain(); + double getDelay(); + double cacheSize(); + unsigned int write(uint8_t *data, unsigned int byte_count); + unsigned int chunkSize() { return m_bufferDuration * m_sampleRate; } + unsigned int getRealisedSampleRate() { return m_outputFormat.mSampleRate; } + static Float64 getCoreAudioRealisedSampleRate(); + + private: + void setCoreAudioBuffersize(); + bool setCoreAudioInputFormat(); + void setCoreAudioPreferredSampleRate(); + bool setupAudio(); + bool checkAudioRoute(); + bool checkSessionProperties(); + bool activateAudioSession(); + void deactivateAudioSession(); + + // callbacks + static void sessionPropertyCallback(void *inClientData, + AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData); + + static void sessionInterruptionCallback(void *inClientData, UInt32 inInterruption); + + static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData); + + bool m_setup; + bool m_initialized; + bool m_activated; + AudioUnit m_audioUnit; + AudioStreamBasicDescription m_outputFormat; + AERingBuffer *m_buffer; + + bool m_mute; + Float32 m_outputVolume; + Float32 m_outputLatency; + Float32 m_bufferDuration; + + unsigned int m_sampleRate; + unsigned int m_frameSize; + unsigned int m_frames; + + bool m_playing; + bool m_playing_saved; + volatile bool m_started; +}; + +CAAudioUnitSink::CAAudioUnitSink() +: m_initialized(false) +, m_activated(false) +, m_buffer(NULL) +, m_playing(false) +, m_playing_saved(false) +, m_started(false) +{ +} + +CAAudioUnitSink::~CAAudioUnitSink() +{ + close(); +} + +bool CAAudioUnitSink::open(AudioStreamBasicDescription outputFormat) +{ + m_mute = false; + m_setup = false; + m_outputFormat = outputFormat; + m_outputLatency = 0.0; + m_bufferDuration= 0.0; + m_outputVolume = 1.0; + m_sampleRate = (unsigned int)outputFormat.mSampleRate; + m_frameSize = outputFormat.mChannelsPerFrame * outputFormat.mBitsPerChannel / 8; + + /* TODO: Reduce the size of this buffer, pre-calculate the size based on how large + the buffers are that CA calls us with in the renderCallback - perhaps call + the checkSessionProperties() before running this? */ + m_buffer = new AERingBuffer(16384); + + return setupAudio(); +} + +bool CAAudioUnitSink::close() +{ + deactivateAudioSession(); + + delete m_buffer; + m_buffer = NULL; + + m_started = false; + return true; +} + +bool CAAudioUnitSink::play(bool mute) +{ + if (!m_playing) + { + if (activateAudioSession()) + { + CAAudioUnitSink::mute(mute); + m_playing = !AudioOutputUnitStart(m_audioUnit); + } + } + + return m_playing; +} + +bool CAAudioUnitSink::mute(bool mute) +{ + m_mute = mute; + + return true; +} + +bool CAAudioUnitSink::pause() +{ + if (m_playing) + m_playing = AudioOutputUnitStop(m_audioUnit); + + return m_playing; +} + +double CAAudioUnitSink::getDelay() +{ + double delay = (double)m_buffer->GetReadSize() / m_frameSize; + delay /= m_sampleRate; + delay += m_bufferDuration + m_outputLatency; + + return delay; +} + +double CAAudioUnitSink::cacheSize() +{ + return (double)m_buffer->GetMaxSize() / (double)(m_frameSize * m_sampleRate); +} + +CCriticalSection mutex; +XbmcThreads::ConditionVariable condVar; + +unsigned int CAAudioUnitSink::write(uint8_t *data, unsigned int frames) +{ + if (m_buffer->GetWriteSize() < frames * m_frameSize) + { // no space to write - wait for a bit + CSingleLock lock(mutex); + if (!m_started) + condVar.wait(lock); + else + condVar.wait(lock, 900 * frames / m_sampleRate); + } + + unsigned int write_frames = std::min(frames, m_buffer->GetWriteSize() / m_frameSize); + if (write_frames) + m_buffer->Write(data, write_frames * m_frameSize); + + return write_frames; +} + +void CAAudioUnitSink::drain() +{ + CCriticalSection mutex; + unsigned int bytes = m_buffer->GetReadSize(); + while (bytes) + { + CSingleLock lock(mutex); + condVar.wait(mutex, 900 * bytes / (m_sampleRate * m_frameSize)); + bytes = m_buffer->GetReadSize(); + } +} + +void CAAudioUnitSink::setCoreAudioBuffersize() +{ +#if !TARGET_IPHONE_SIMULATOR + OSStatus status = noErr; + // set the buffer size, this affects the number of samples + // that get rendered every time the audio callback is fired. + Float32 preferredBufferSize = 512 * m_outputFormat.mChannelsPerFrame / m_outputFormat.mSampleRate; + CLog::Log(LOGNOTICE, "%s setting buffer duration to %f", __PRETTY_FUNCTION__, preferredBufferSize); + status = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, + sizeof(preferredBufferSize), &preferredBufferSize); + if (status != noErr) + CLog::Log(LOGWARNING, "%s preferredBufferSize couldn't be set (error: %d)", __PRETTY_FUNCTION__, (int)status); +#endif +} + +bool CAAudioUnitSink::setCoreAudioInputFormat() +{ + // Set the output stream format + UInt32 ioDataSize = sizeof(AudioStreamBasicDescription); + OSStatus status = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 0, &m_outputFormat, ioDataSize); + if (status != noErr) + { + CLog::Log(LOGERROR, "%s error setting stream format on audioUnit (error: %d)", __PRETTY_FUNCTION__, (int)status); + return false; + } + return true; +} + +void CAAudioUnitSink::setCoreAudioPreferredSampleRate() +{ + Float64 preferredSampleRate = m_outputFormat.mSampleRate; + CLog::Log(LOGNOTICE, "%s requesting hw samplerate %f", __PRETTY_FUNCTION__, preferredSampleRate); + OSStatus status = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareSampleRate, + sizeof(preferredSampleRate), &preferredSampleRate); + if (status != noErr) + CLog::Log(LOGWARNING, "%s preferredSampleRate couldn't be set (error: %d)", __PRETTY_FUNCTION__, (int)status); +} + +Float64 CAAudioUnitSink::getCoreAudioRealisedSampleRate() +{ + Float64 outputSampleRate = 0.0; + UInt32 ioDataSize = sizeof(outputSampleRate); + if (AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, + &ioDataSize, &outputSampleRate) != noErr) + CLog::Log(LOGERROR, "%s: error getting CurrentHardwareSampleRate", __FUNCTION__); + return outputSampleRate; +} + +bool CAAudioUnitSink::setupAudio() +{ + OSStatus status = noErr; + if (m_setup && m_audioUnit) + return true; + + // Audio Session Setup + UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback; + status = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, + sizeof(sessionCategory), &sessionCategory); + if (status != noErr) + { + CLog::Log(LOGERROR, "%s error setting sessioncategory (error: %d)", __PRETTY_FUNCTION__, (int)status); + return false; + } + + AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, + sessionPropertyCallback, this); + + AudioSessionAddPropertyListener(kAudioSessionProperty_CurrentHardwareOutputVolume, + sessionPropertyCallback, this); + + if (AudioSessionSetActive(true) != noErr) + return false; + + // Audio Unit Setup + // Describe a default output unit. + AudioComponentDescription description = {}; + description.componentType = kAudioUnitType_Output; + description.componentSubType = kAudioUnitSubType_RemoteIO; + description.componentManufacturer = kAudioUnitManufacturer_Apple; + + // Get component + AudioComponent component; + component = AudioComponentFindNext(NULL, &description); + status = AudioComponentInstanceNew(component, &m_audioUnit); + if (status != noErr) + { + CLog::Log(LOGERROR, "%s error creating audioUnit (error: %d)", __PRETTY_FUNCTION__, (int)status); + return false; + } + + setCoreAudioPreferredSampleRate(); + + // Get the output samplerate for knowing what was setup in reality + Float64 realisedSampleRate = getCoreAudioRealisedSampleRate(); + if (m_outputFormat.mSampleRate != realisedSampleRate) + { + CLog::Log(LOGNOTICE, "%s couldn't set requested samplerate %d, coreaudio will resample to %d instead", __PRETTY_FUNCTION__, (int)m_outputFormat.mSampleRate, (int)realisedSampleRate); + // if we don't ca to resample - but instead let activeae resample - + // reflect the realised samplerate to the outputformat here + // well maybe it is handy in the future - as of writing this + // ca was about 6 times faster then activeae ;) + //m_outputFormat.mSampleRate = realisedSampleRate; + //m_sampleRate = realisedSampleRate; + } + + setCoreAudioBuffersize(); + if (!setCoreAudioInputFormat()) + return false; + + // Attach a render callback on the unit + AURenderCallbackStruct callbackStruct = {}; + callbackStruct.inputProc = renderCallback; + callbackStruct.inputProcRefCon = this; + status = AudioUnitSetProperty(m_audioUnit, + kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, + 0, &callbackStruct, sizeof(callbackStruct)); + if (status != noErr) + { + CLog::Log(LOGERROR, "%s error setting render callback for audioUnit (error: %d)", __PRETTY_FUNCTION__, (int)status); + return false; + } + + status = AudioUnitInitialize(m_audioUnit); + if (status != noErr) + { + CLog::Log(LOGERROR, "%s error initializing audioUnit (error: %d)", __PRETTY_FUNCTION__, (int)status); + return false; + } + + checkSessionProperties(); + + m_setup = true; + std::string formatString; + CLog::Log(LOGNOTICE, "%s setup audio format: %s", __PRETTY_FUNCTION__, StreamDescriptionToString(m_outputFormat, formatString)); + + return m_setup; +} + +bool CAAudioUnitSink::checkAudioRoute() +{ + // why do we need to know the audio route ? + CFStringRef route; + UInt32 propertySize = sizeof(CFStringRef); + if (AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &route) != noErr) + return false; + + return true; +} + +bool CAAudioUnitSink::checkSessionProperties() +{ + checkAudioRoute(); + + UInt32 ioDataSize; + ioDataSize = sizeof(m_outputVolume); + if (AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputVolume, + &ioDataSize, &m_outputVolume) != noErr) + CLog::Log(LOGERROR, "%s: error getting CurrentHardwareOutputVolume", __FUNCTION__); + + ioDataSize = sizeof(m_outputLatency); + if (AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency, + &ioDataSize, &m_outputLatency) != noErr) + CLog::Log(LOGERROR, "%s: error getting CurrentHardwareOutputLatency", __FUNCTION__); + + ioDataSize = sizeof(m_bufferDuration); + if (AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, + &ioDataSize, &m_bufferDuration) != noErr) + CLog::Log(LOGERROR, "%s: error getting CurrentHardwareIOBufferDuration", __FUNCTION__); + + CLog::Log(LOGDEBUG, "%s: volume = %f, latency = %f, buffer = %f", __FUNCTION__, m_outputVolume, m_outputLatency, m_bufferDuration); + return true; +} + +bool CAAudioUnitSink::activateAudioSession() +{ + if (!m_activated) + { + if (!m_initialized) + { + OSStatus osstat = AudioSessionInitialize(NULL, kCFRunLoopDefaultMode, sessionInterruptionCallback, this); + if (osstat == kAudioSessionNoError || osstat == kAudioSessionAlreadyInitialized) + m_initialized = true; + else + { + CLog::Log(LOGERROR, "%s error initializing audio session (error: %d)", __PRETTY_FUNCTION__, (int)osstat); + return false; + } + } + if (checkAudioRoute() && setupAudio()) + m_activated = true; + } + + return m_activated; +} + +void CAAudioUnitSink::deactivateAudioSession() +{ + if (m_activated) + { + pause(); + AudioUnitUninitialize(m_audioUnit); + AudioComponentInstanceDispose(m_audioUnit), m_audioUnit = NULL; + AudioSessionSetActive(false); + AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_AudioRouteChange, + sessionPropertyCallback, this); + AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_CurrentHardwareOutputVolume, + sessionPropertyCallback, this); + + m_setup = false; + m_activated = false; + } +} + +void CAAudioUnitSink::sessionPropertyCallback(void *inClientData, + AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData) +{ + CAAudioUnitSink *sink = (CAAudioUnitSink*)inClientData; + + if (inID == kAudioSessionProperty_AudioRouteChange) + { + if (sink->checkAudioRoute()) + sink->checkSessionProperties(); + } + else if (inID == kAudioSessionProperty_CurrentHardwareOutputVolume) + { + if (inData && inDataSize == 4) + sink->m_outputVolume = *(float*)inData; + } +} + +void CAAudioUnitSink::sessionInterruptionCallback(void *inClientData, UInt32 inInterruption) +{ + CAAudioUnitSink *sink = (CAAudioUnitSink*)inClientData; + + if (inInterruption == kAudioSessionBeginInterruption) + { + CLog::Log(LOGDEBUG, "Bgn interuption"); + sink->m_playing_saved = sink->m_playing; + sink->pause(); + } + else if (inInterruption == kAudioSessionEndInterruption) + { + CLog::Log(LOGDEBUG, "End interuption"); + if (sink->m_playing_saved) + { + sink->m_playing_saved = false; + sink->play(sink->m_mute); + } + } +} + +OSStatus CAAudioUnitSink::renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +{ + CAAudioUnitSink *sink = (CAAudioUnitSink*)inRefCon; + + sink->m_started = true; + + for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) + { + // buffers come from CA already zero'd, so just copy what is wanted + unsigned int wanted = ioData->mBuffers[i].mDataByteSize; + unsigned int bytes = std::min(sink->m_buffer->GetReadSize(), wanted); + sink->m_buffer->Read((unsigned char*)ioData->mBuffers[i].mData, bytes); + if (bytes != wanted) + CLog::Log(LOGERROR, "%s: %sFLOW (%i vs %i) bytes", __FUNCTION__, bytes > wanted ? "OVER" : "UNDER", bytes, wanted); + } + // tell the sink we're good for more data + condVar.notifyAll(); + + return noErr; +} + +/***************************************************************************************/ +/***************************************************************************************/ +static void EnumerateDevices(AEDeviceInfoList &list) +{ + CAEDeviceInfo device; + + device.m_deviceName = "default"; + device.m_displayName = "Default"; + device.m_displayNameExtra = ""; +#if defined(TARGET_DARWIN_IOS_ATV2) + device.m_deviceType = AE_DEVTYPE_IEC958; + device.m_dataFormats.push_back(AE_FMT_AC3); + device.m_dataFormats.push_back(AE_FMT_DTS); +#else + // TODO screen changing on ios needs to call + // devices changed once this is available in activae + if (g_Windowing.GetCurrentScreen() > 0) + { + device.m_deviceType = AE_DEVTYPE_IEC958; //allow passthrough for tvout + device.m_dataFormats.push_back(AE_FMT_AC3); + device.m_dataFormats.push_back(AE_FMT_DTS); + } + else + device.m_deviceType = AE_DEVTYPE_PCM; +#endif + + // add channel info + CAEChannelInfo channel_info; + for (UInt32 chan = 0; chan < 2; ++chan) + { + if (!device.m_channels.HasChannel(CAChannelMap[chan])) + device.m_channels += CAChannelMap[chan]; + channel_info += CAChannelMap[chan]; + } + + // there are more supported ( one of those 2 gets resampled + // by coreaudio anyway) - but for keeping it save ignore + // the others... + device.m_sampleRates.push_back(44100); + device.m_sampleRates.push_back(48000); + + device.m_dataFormats.push_back(AE_FMT_S16LE); + //device.m_dataFormats.push_back(AE_FMT_S24LE3); + //device.m_dataFormats.push_back(AE_FMT_S32LE); + // AE_FMT_FLOAT is 3% slower on atv2 + // then S16LE - so leave it out for now + //device.m_dataFormats.push_back(AE_FMT_FLOAT); + + CLog::Log(LOGDEBUG, "EnumerateDevices:Device(%s)" , device.m_deviceName.c_str()); + + list.push_back(device); +} + +/***************************************************************************************/ +/***************************************************************************************/ +AEDeviceInfoList CAESinkDARWINIOS::m_devices; + +CAESinkDARWINIOS::CAESinkDARWINIOS() +: m_audioSink(NULL) +{ +} + +CAESinkDARWINIOS::~CAESinkDARWINIOS() +{ +} + +bool CAESinkDARWINIOS::Initialize(AEAudioFormat &format, std::string &device) +{ + bool found = false; + bool forceRaw = false; + + std::string devicelower = device; + StringUtils::ToLower(devicelower); + for (size_t i = 0; i < m_devices.size(); i++) + { + if (devicelower.find(m_devices[i].m_deviceName) != std::string::npos) + { + m_info = m_devices[i]; + found = true; + break; + } + } + + if (!found) + return false; + + AudioStreamBasicDescription audioFormat = {}; + + // AE_FMT_FLOAT is 3% slower on atv2 + // then S16LE - so leave it out for now + // just leave the code commented in here + // as it might come handy at some point maybe ... + //if (format.m_dataFormat == AE_FMT_FLOAT) + // audioFormat.mFormatFlags |= kLinearPCMFormatFlagIsFloat; + //else// this will be selected when AE wants AC3 or DTS or anything other then float + { + audioFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; + if (AE_IS_RAW(format.m_dataFormat)) + forceRaw = true; + format.m_dataFormat = AE_FMT_S16LE; + } + + format.m_channelLayout = m_info.m_channels; + format.m_frameSize = format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); + + + audioFormat.mFormatID = kAudioFormatLinearPCM; + switch(format.m_sampleRate) + { + case 11025: + case 22050: + case 44100: + case 88200: + case 176400: + audioFormat.mSampleRate = 44100; + break; + default: + case 8000: + case 12000: + case 16000: + case 24000: + case 32000: + case 48000: + case 96000: + case 192000: + case 384000: + audioFormat.mSampleRate = 48000; + break; + } + + if (forceRaw)//make sure input and output samplerate match for preventing resampling + audioFormat.mSampleRate = CAAudioUnitSink::getCoreAudioRealisedSampleRate(); + + audioFormat.mFramesPerPacket = 1; + audioFormat.mChannelsPerFrame= 2;// ios only supports 2 channels + audioFormat.mBitsPerChannel = CAEUtil::DataFormatToBits(format.m_dataFormat); + audioFormat.mBytesPerFrame = format.m_frameSize; + audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket; + audioFormat.mFormatFlags |= kLinearPCMFormatFlagIsPacked; + +#if DO_440HZ_TONE_TEST + SineWaveGeneratorInitWithFrequency(&m_SineWaveGenerator, 440.0, audioFormat.mSampleRate); +#endif + + m_audioSink = new CAAudioUnitSink; + m_audioSink->open(audioFormat); + + format.m_frames = m_audioSink->chunkSize(); + format.m_frameSamples = format.m_frames * audioFormat.mChannelsPerFrame; + // reset to the realised samplerate + format.m_sampleRate = m_audioSink->getRealisedSampleRate(); + m_format = format; + + m_volume_changed = false; + m_audioSink->play(false); + + return true; +} + +void CAESinkDARWINIOS::Deinitialize() +{ + delete m_audioSink; + m_audioSink = NULL; +} + +bool CAESinkDARWINIOS::IsCompatible(const AEAudioFormat &format, const std::string &device) +{ + return ((m_format.m_sampleRate == format.m_sampleRate) && + (m_format.m_dataFormat == format.m_dataFormat) && + (m_format.m_channelLayout == format.m_channelLayout)); +} + +double CAESinkDARWINIOS::GetDelay() +{ + if (m_audioSink) + return m_audioSink->getDelay(); + return 0.0; +} + +double CAESinkDARWINIOS::GetCacheTotal() +{ + if (m_audioSink) + return m_audioSink->cacheSize(); + return 0.0; +} + +unsigned int CAESinkDARWINIOS::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) +{ + +#if DO_440HZ_TONE_TEST + if (m_format.m_dataFormat == AE_FMT_FLOAT) + { + float *samples = (float*)data; + for (unsigned int j = 0; j < frames ; j++) + { + float sample = SineWaveGeneratorNextSampleFloat(&m_SineWaveGenerator); + *samples++ = sample; + *samples++ = sample; + } + + } + else + { + int16_t *samples = (int16_t*)data; + for (unsigned int j = 0; j < frames ; j++) + { + int16_t sample = SineWaveGeneratorNextSampleInt16(&m_SineWaveGenerator); + *samples++ = sample; + *samples++ = sample; + } + } +#endif + if (m_audioSink) + return m_audioSink->write(data, frames); + return 0; +} + +void CAESinkDARWINIOS::Drain() +{ + if (m_audioSink) + m_audioSink->drain(); +} + +bool CAESinkDARWINIOS::HasVolume() +{ + return false; +} + +void CAESinkDARWINIOS::SetVolume(float scale) +{ + // CoreAudio uses fixed steps, reverse scale back to percent + float gain = CAEUtil::ScaleToGain(scale); + m_volume = CAEUtil::GainToPercent(gain); + m_volume_changed = true; +} + +void CAESinkDARWINIOS::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) +{ + m_devices.clear(); + EnumerateDevices(m_devices); + list = m_devices; +} diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINIOS.h b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINIOS.h new file mode 100644 index 0000000000..f1fec67e25 --- /dev/null +++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINIOS.h @@ -0,0 +1,68 @@ +#pragma once +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program 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, or (at your option) + * any later version. + * + * This Program 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "cores/AudioEngine/Interfaces/AESink.h" +#include "cores/AudioEngine/Utils/AEDeviceInfo.h" + +#define DO_440HZ_TONE_TEST 0 + +#if DO_440HZ_TONE_TEST +typedef struct { + float currentPhase; + float phaseIncrement; +} SineWaveGenerator; +#endif + +class AERingBuffer; +class CAAudioUnitSink; + +class CAESinkDARWINIOS : public IAESink +{ +public: + virtual const char *GetName() { return "DARWINIOS"; } + + CAESinkDARWINIOS(); + virtual ~CAESinkDARWINIOS(); + + virtual bool Initialize(AEAudioFormat &format, std::string &device); + virtual void Deinitialize(); + virtual bool IsCompatible(const AEAudioFormat &format, const std::string &device); + + virtual double GetDelay (); + virtual double GetCacheTotal (); + virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual void Drain (); + virtual bool HasVolume (); + virtual void SetVolume (float scale); + static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false); + +private: + static AEDeviceInfoList m_devices; + CAEDeviceInfo m_info; + AEAudioFormat m_format; + double m_volume; + bool m_volume_changed; + + CAAudioUnitSink *m_audioSink; +#if DO_440HZ_TONE_TEST + SineWaveGenerator m_SineWaveGenerator; +#endif +};
\ No newline at end of file diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp new file mode 100644 index 0000000000..f19acba58c --- /dev/null +++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp @@ -0,0 +1,636 @@ +/* + * Copyright (C) 2005-2014 Team XBMC + * http://xbmc.org + * + * This Program 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, or (at your option) + * any later version. + * + * This Program 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "cores/AudioEngine/AEFactory.h" +#include "cores/AudioEngine/Sinks/AESinkDARWINOSX.h" +#include "cores/AudioEngine/Utils/AEUtil.h" +#include "cores/AudioEngine/Utils/AERingBuffer.h" +#include "cores/AudioEngine/Sinks/osx/CoreAudioHelpers.h" +#include "cores/AudioEngine/Sinks/osx/CoreAudioHardware.h" +#include "osx/DarwinUtils.h" +#include "utils/log.h" +#include "utils/StringUtils.h" +#include "threads/Condition.h" +#include "threads/CriticalSection.h" + +#include <sstream> + +#define CA_MAX_CHANNELS 8 +static enum AEChannel CAChannelMap[CA_MAX_CHANNELS + 1] = { + AE_CH_FL , AE_CH_FR , AE_CH_BL , AE_CH_BR , AE_CH_FC , AE_CH_LFE , AE_CH_SL , AE_CH_SR , + AE_CH_NULL +}; + +static bool HasSampleRate(const AESampleRateList &list, const unsigned int samplerate) +{ + for (size_t i = 0; i < list.size(); ++i) + { + if (list[i] == samplerate) + return true; + } + return false; +} + +static bool HasDataFormat(const AEDataFormatList &list, const enum AEDataFormat format) +{ + for (size_t i = 0; i < list.size(); ++i) + { + if (list[i] == format) + return true; + } + return false; +} + +typedef std::vector< std::pair<AudioDeviceID, CAEDeviceInfo> > CADeviceList; + +static void EnumerateDevices(CADeviceList &list) +{ + CAEDeviceInfo device; + + std::string defaultDeviceName; + CCoreAudioHardware::GetOutputDeviceName(defaultDeviceName); + + CoreAudioDeviceList deviceIDList; + CCoreAudioHardware::GetOutputDevices(&deviceIDList); + while (!deviceIDList.empty()) + { + AudioDeviceID deviceID = deviceIDList.front(); + CCoreAudioDevice caDevice(deviceID); + + device.m_channels.Reset(); + device.m_dataFormats.clear(); + device.m_sampleRates.clear(); + + device.m_deviceType = AE_DEVTYPE_PCM; + device.m_deviceName = caDevice.GetName(); + device.m_displayName = device.m_deviceName; + device.m_displayNameExtra = ""; + + if (device.m_deviceName.find("HDMI") != std::string::npos) + device.m_deviceType = AE_DEVTYPE_HDMI; + + CLog::Log(LOGDEBUG, "EnumerateDevices:Device(%s)" , device.m_deviceName.c_str()); + AudioStreamIdList streams; + if (caDevice.GetStreams(&streams)) + { + for (AudioStreamIdList::iterator j = streams.begin(); j != streams.end(); ++j) + { + StreamFormatList streams; + if (CCoreAudioStream::GetAvailablePhysicalFormats(*j, &streams)) + { + for (StreamFormatList::iterator i = streams.begin(); i != streams.end(); ++i) + { + AudioStreamBasicDescription desc = i->mFormat; + std::string formatString; + CLog::Log(LOGDEBUG, "EnumerateDevices:Format(%s)" , + StreamDescriptionToString(desc, formatString)); + // add stream format info + switch (desc.mFormatID) + { + case kAudioFormatAC3: + case kAudioFormat60958AC3: + if (!HasDataFormat(device.m_dataFormats, AE_FMT_AC3)) + device.m_dataFormats.push_back(AE_FMT_AC3); + if (!HasDataFormat(device.m_dataFormats, AE_FMT_DTS)) + device.m_dataFormats.push_back(AE_FMT_DTS); + // if we are not hdmi, this is an S/PDIF device + if (device.m_deviceType != AE_DEVTYPE_HDMI) + device.m_deviceType = AE_DEVTYPE_IEC958; + break; + default: + AEDataFormat format = AE_FMT_INVALID; + switch(desc.mBitsPerChannel) + { + case 16: + if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian) + format = AE_FMT_S16BE; + else + { + /* Passthrough is possible with a 2ch digital output */ + if (desc.mChannelsPerFrame == 2 && CCoreAudioStream::IsDigitalOuptut(*j)) + { + if (desc.mSampleRate == 48000) + { + if (!HasDataFormat(device.m_dataFormats, AE_FMT_AC3)) + device.m_dataFormats.push_back(AE_FMT_AC3); + if (!HasDataFormat(device.m_dataFormats, AE_FMT_DTS)) + device.m_dataFormats.push_back(AE_FMT_DTS); + } + else if (desc.mSampleRate == 192000) + { + if (!HasDataFormat(device.m_dataFormats, AE_FMT_EAC3)) + device.m_dataFormats.push_back(AE_FMT_EAC3); + } + } + format = AE_FMT_S16LE; + } + break; + case 24: + if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian) + format = AE_FMT_S24BE3; + else + format = AE_FMT_S24LE3; + break; + case 32: + if (desc.mFormatFlags & kAudioFormatFlagIsFloat) + format = AE_FMT_FLOAT; + else + { + if (desc.mFormatFlags & kAudioFormatFlagIsBigEndian) + format = AE_FMT_S32BE; + else + format = AE_FMT_S32LE; + } + break; + } + if (format != AE_FMT_INVALID && !HasDataFormat(device.m_dataFormats, format)) + device.m_dataFormats.push_back(format); + break; + } + + // add channel info + CAEChannelInfo channel_info; + for (UInt32 chan = 0; chan < CA_MAX_CHANNELS && chan < desc.mChannelsPerFrame; ++chan) + { + if (!device.m_channels.HasChannel(CAChannelMap[chan])) + device.m_channels += CAChannelMap[chan]; + channel_info += CAChannelMap[chan]; + } + + // add sample rate info + if (!HasSampleRate(device.m_sampleRates, desc.mSampleRate)) + device.m_sampleRates.push_back(desc.mSampleRate); + } + } + } + } + + list.push_back(std::make_pair(deviceID, device)); + //in the first place of the list add the default device + //with name "default" - if this is selected + //we will output to whatever osx claims to be default + //(allows transition from headphones to speaker and stuff + //like that + if(defaultDeviceName == device.m_deviceName) + { + device.m_deviceName = "default"; + device.m_displayName = "Default"; + list.insert(list.begin(), std::make_pair(deviceID, device)); + } + + deviceIDList.pop_front(); + } +} + +/* static, threadsafe access to the device list */ +static CADeviceList s_devices; +static CCriticalSection s_devicesLock; + +static void EnumerateDevices() +{ + CADeviceList devices; + EnumerateDevices(devices); + { + CSingleLock lock(s_devicesLock); + s_devices = devices; + } +} + +static CADeviceList GetDevices() +{ + CADeviceList list; + { + CSingleLock lock(s_devicesLock); + list = s_devices; + } + return list; +} + +OSStatus deviceChangedCB(AudioObjectID inObjectID, + UInt32 inNumberAddresses, + const AudioObjectPropertyAddress inAddresses[], + void* inClientData) +{ + CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - reenumerating"); + CAEFactory::DeviceChange(); + CLog::Log(LOGDEBUG, "CoreAudio: audiodevicelist changed - done"); + return noErr; +} + +void RegisterDeviceChangedCB(bool bRegister, void *ref) +{ + OSStatus ret = noErr; + const AudioObjectPropertyAddress inAdr = + { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + if (bRegister) + ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref); + else + ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &inAdr, deviceChangedCB, ref); + + if (ret != noErr) + CLog::Log(LOGERROR, "CCoreAudioAE::Deinitialize - error %s a listener callback for device changes!", bRegister?"attaching":"removing"); +} + + +//////////////////////////////////////////////////////////////////////////////////////////// +CAESinkDARWINOSX::CAESinkDARWINOSX() +: m_latentFrames(0), m_outputBufferIndex(0), m_outputBitstream(false), m_outputBuffer(NULL), m_buffer(NULL) +{ + // By default, kAudioHardwarePropertyRunLoop points at the process's main thread on SnowLeopard, + // If your process lacks such a run loop, you can set kAudioHardwarePropertyRunLoop to NULL which + // tells the HAL to run it's own thread for notifications (which was the default prior to SnowLeopard). + // So tell the HAL to use its own thread for similar behavior under all supported versions of OSX. + CFRunLoopRef theRunLoop = NULL; + AudioObjectPropertyAddress theAddress = { + kAudioHardwarePropertyRunLoop, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + OSStatus theError = AudioObjectSetPropertyData(kAudioObjectSystemObject, + &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); + if (theError != noErr) + { + CLog::Log(LOGERROR, "CCoreAudioAE::constructor: kAudioHardwarePropertyRunLoop error."); + } + RegisterDeviceChangedCB(true, this); + m_started = false; +} + +CAESinkDARWINOSX::~CAESinkDARWINOSX() +{ + RegisterDeviceChangedCB(false, this); +} + +float ScoreStream(const AudioStreamBasicDescription &desc, const AEAudioFormat &format) +{ + float score = 0; + if (format.m_dataFormat == AE_FMT_AC3 || + format.m_dataFormat == AE_FMT_DTS) + { + if (desc.mFormatID == kAudioFormat60958AC3 || + desc.mFormatID == 'IAC3' || + desc.mFormatID == kAudioFormatAC3) + { + if (desc.mSampleRate == format.m_sampleRate && + desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat) && + desc.mChannelsPerFrame == format.m_channelLayout.Count()) + { + // perfect match + score = FLT_MAX; + } + } + } + if (format.m_dataFormat == AE_FMT_AC3 || + format.m_dataFormat == AE_FMT_DTS || + format.m_dataFormat == AE_FMT_EAC3) + { // we should be able to bistreaming in PCM if the samplerate, bitdepth and channels match + if (desc.mSampleRate == format.m_sampleRate && + desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat) && + desc.mChannelsPerFrame == format.m_channelLayout.Count() && + desc.mFormatID == kAudioFormatLinearPCM) + { + score = FLT_MAX / 2; + } + } + else + { // non-passthrough, whatever works is fine + if (desc.mFormatID == kAudioFormatLinearPCM) + { + if (desc.mSampleRate == format.m_sampleRate) + score += 10; + else if (desc.mSampleRate > format.m_sampleRate) + score += 1; + if (desc.mChannelsPerFrame == format.m_channelLayout.Count()) + score += 5; + else if (desc.mChannelsPerFrame > format.m_channelLayout.Count()) + score += 1; + if (format.m_dataFormat == AE_FMT_FLOAT) + { // for float, prefer the highest bitdepth we have + if (desc.mBitsPerChannel >= 16) + score += (desc.mBitsPerChannel / 8); + } + else + { + if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat)) + score += 5; + else if (desc.mBitsPerChannel == CAEUtil::DataFormatToBits(format.m_dataFormat)) + score += 1; + } + } + } + return score; +} + +bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device) +{ + AudioDeviceID deviceID = 0; + CADeviceList devices = GetDevices(); + if (StringUtils::EqualsNoCase(device, "default")) + { + CCoreAudioHardware::GetOutputDeviceName(device); + CLog::Log(LOGNOTICE, "%s: Opening default device %s", __PRETTY_FUNCTION__, device.c_str()); + } + + for (size_t i = 0; i < devices.size(); i++) + { + if (device.find(devices[i].second.m_deviceName) != std::string::npos) + { + m_info = devices[i].second; + deviceID = devices[i].first; + break; + } + } + if (!deviceID) + { + CLog::Log(LOGERROR, "%s: Unable to find device %s", __FUNCTION__, device.c_str()); + return false; + } + + m_device.Open(deviceID); + + // Fetch a list of the streams defined by the output device + AudioStreamIdList streams; + m_device.GetStreams(&streams); + + CLog::Log(LOGDEBUG, "%s: Finding stream for format %s", __FUNCTION__, CAEUtil::DataFormatToStr(format.m_dataFormat)); + + bool passthrough = false; + UInt32 outputIndex = 0; + float outputScore = 0; + AudioStreamBasicDescription outputFormat = {0}; + AudioStreamID outputStream = 0; + + /* The theory is to score based on + 1. Matching passthrough characteristics (i.e. passthrough flag) + 2. Matching sample rate. + 3. Matching bits per channel (or higher). + 4. Matching number of channels (or higher). + */ + UInt32 index = 0; + for (AudioStreamIdList::const_iterator i = streams.begin(); i != streams.end(); ++i) + { + // Probe physical formats + StreamFormatList formats; + CCoreAudioStream::GetAvailablePhysicalFormats(*i, &formats); + for (StreamFormatList::const_iterator j = formats.begin(); j != formats.end(); ++j) + { + const AudioStreamBasicDescription &desc = j->mFormat; + + float score = ScoreStream(desc, format); + + std::string formatString; + CLog::Log(LOGDEBUG, "%s: Physical Format: %s rated %f", __FUNCTION__, StreamDescriptionToString(desc, formatString), score); + + if (score > outputScore) + { + passthrough = score > 1000; + outputScore = score; + outputFormat = desc; + outputStream = *i; + outputIndex = index; + } + } + index++; + } + + if (!outputFormat.mFormatID) + { + CLog::Log(LOGERROR, "%s, Unable to find suitable stream", __FUNCTION__); + return false; + } + + /* Update our AE format */ + format.m_sampleRate = outputFormat.mSampleRate; + if (outputFormat.mChannelsPerFrame != format.m_channelLayout.Count()) + { /* update the channel count. We assume that they're layed out as given in CAChannelMap. + if they're not, this is plain wrong */ + format.m_channelLayout.Reset(); + for (unsigned int i = 0; i < outputFormat.mChannelsPerFrame; i++) + format.m_channelLayout += CAChannelMap[i]; + } + + m_outputBufferIndex = outputIndex; + m_outputBitstream = passthrough && outputFormat.mFormatID == kAudioFormatLinearPCM; + + std::string formatString; + CLog::Log(LOGDEBUG, "%s: Selected stream[%u] - id: 0x%04X, Physical Format: %s %s", __FUNCTION__, m_outputBufferIndex, outputStream, StreamDescriptionToString(outputFormat, formatString), m_outputBitstream ? "bitstreamed passthrough" : ""); + + SetHogMode(passthrough); + + // Configure the output stream object + m_outputStream.Open(outputStream); + + AudioStreamBasicDescription virtualFormat, previousPhysicalFormat; + m_outputStream.GetVirtualFormat(&virtualFormat); + m_outputStream.GetPhysicalFormat(&previousPhysicalFormat); + CLog::Log(LOGDEBUG, "%s: Previous Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString)); + CLog::Log(LOGDEBUG, "%s: Previous Physical Format: %s", __FUNCTION__, StreamDescriptionToString(previousPhysicalFormat, formatString)); + + m_outputStream.SetPhysicalFormat(&outputFormat); // Set the active format (the old one will be reverted when we close) + m_outputStream.GetVirtualFormat(&virtualFormat); + CLog::Log(LOGDEBUG, "%s: New Virtual Format: %s", __FUNCTION__, StreamDescriptionToString(virtualFormat, formatString)); + CLog::Log(LOGDEBUG, "%s: New Physical Format: %s", __FUNCTION__, StreamDescriptionToString(outputFormat, formatString)); + + m_latentFrames = m_device.GetNumLatencyFrames(); + m_latentFrames += m_outputStream.GetNumLatencyFrames(); + + /* TODO: Should we use the virtual format to determine our data format? */ + format.m_frameSize = format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); + format.m_frames = m_device.GetBufferSize(); + format.m_frameSamples = format.m_frames * format.m_channelLayout.Count(); + + if (m_outputBitstream) + { + m_outputBuffer = new int16_t[format.m_frameSamples]; + /* TODO: Do we need this? */ + m_device.SetNominalSampleRate(format.m_sampleRate); + } + + unsigned int num_buffers = 4; + m_buffer = new AERingBuffer(num_buffers * format.m_frames * format.m_frameSize); + CLog::Log(LOGDEBUG, "%s: using buffer size: %u (%f ms)", __FUNCTION__, m_buffer->GetMaxSize(), (float)m_buffer->GetMaxSize() / (format.m_sampleRate * format.m_frameSize)); + + m_format = format; + if (passthrough) + format.m_dataFormat = AE_FMT_S16NE; + else + format.m_dataFormat = AE_FMT_FLOAT; + + // Register for data request callbacks from the driver and start + m_device.AddIOProc(renderCallback, this); + m_device.Start(); + return true; +} + +void CAESinkDARWINOSX::SetHogMode(bool on) +{ + // TODO: Auto hogging sets this for us. Figure out how/when to turn it off or use it + // It appears that leaving this set will aslo restore the previous stream format when the + // Application exits. If auto hogging is set and we try to set hog mode, we will deadlock + // From the SDK docs: "If the AudioDevice is in a non-mixable mode, the HAL will automatically take hog mode on behalf of the first process to start an IOProc." + + // Lock down the device. This MUST be done PRIOR to switching to a non-mixable format, if it is done at all + // If it is attempted after the format change, there is a high likelihood of a deadlock + // We may need to do this sooner to enable mix-disable (i.e. before setting the stream format) + if (on) + { + // Auto-Hog does not always un-hog the device when changing back to a mixable mode. + // Handle this on our own until it is fixed. + CCoreAudioHardware::SetAutoHogMode(false); + bool autoHog = CCoreAudioHardware::GetAutoHogMode(); + CLog::Log(LOGDEBUG, " CoreAudioRenderer::InitializeEncoded: " + "Auto 'hog' mode is set to '%s'.", autoHog ? "On" : "Off"); + if (autoHog) + return; + } + m_device.SetHogStatus(on); + m_device.SetMixingSupport(!on); +} + +void CAESinkDARWINOSX::Deinitialize() +{ + m_device.Stop(); + m_device.RemoveIOProc(); + + m_outputStream.Close(); + m_device.Close(); + if (m_buffer) + { + delete m_buffer; + m_buffer = NULL; + } + m_outputBufferIndex = 0; + m_outputBitstream = false; + + delete[] m_outputBuffer; + m_outputBuffer = NULL; + + m_started = false; +} + +bool CAESinkDARWINOSX::IsCompatible(const AEAudioFormat &format, const std::string &device) +{ + return ((m_format.m_sampleRate == format.m_sampleRate) && + (m_format.m_dataFormat == format.m_dataFormat) && + (m_format.m_channelLayout == format.m_channelLayout)); +} + +double CAESinkDARWINOSX::GetDelay() +{ + if (m_buffer) + { + // Calculate the duration of the data in the cache + double delay = (double)m_buffer->GetReadSize() / (double)m_format.m_frameSize; + delay += (double)m_latentFrames; + delay /= (double)m_format.m_sampleRate; + return delay; + } + return 0.0; +} + +double CAESinkDARWINOSX::GetCacheTotal() +{ + return (double)m_buffer->GetMaxSize() / (double)(m_format.m_frameSize * m_format.m_sampleRate); +} + +CCriticalSection mutex; +XbmcThreads::ConditionVariable condVar; + +unsigned int CAESinkDARWINOSX::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) +{ + if (m_buffer->GetWriteSize() < frames * m_format.m_frameSize) + { // no space to write - wait for a bit + CSingleLock lock(mutex); + if (!m_started) + condVar.wait(lock); + else + condVar.wait(lock, 900 * frames / m_format.m_sampleRate); + } + + unsigned int write_frames = std::min(frames, m_buffer->GetWriteSize() / m_format.m_frameSize); + if (write_frames) + m_buffer->Write(data, write_frames * m_format.m_frameSize); + + return write_frames; +} + +void CAESinkDARWINOSX::Drain() +{ + CCriticalSection mutex; + int bytes = m_buffer->GetReadSize(); + while (bytes) + { + CSingleLock lock(mutex); + condVar.wait(mutex, 900 * bytes / (m_format.m_sampleRate * m_format.m_frameSize)); + bytes = m_buffer->GetReadSize(); + } +} + +void CAESinkDARWINOSX::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) +{ + EnumerateDevices(); + list.clear(); + for (CADeviceList::const_iterator i = s_devices.begin(); i != s_devices.end(); ++i) + list.push_back(i->second); +} + +OSStatus CAESinkDARWINOSX::renderCallback(AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData) +{ + CAESinkDARWINOSX *sink = (CAESinkDARWINOSX*)inClientData; + + sink->m_started = true; + if (sink->m_outputBufferIndex < outOutputData->mNumberBuffers) + { + if (sink->m_outputBitstream) + { + /* HACK for bitstreaming AC3/DTS via PCM. + We reverse the float->S16LE conversion done in the stream or device */ + static const float mul = 1.0f / (INT16_MAX + 1); + + unsigned int wanted = std::min(outOutputData->mBuffers[sink->m_outputBufferIndex].mDataByteSize / sizeof(float), (size_t)sink->m_format.m_frameSamples) * sizeof(int16_t); + if (wanted <= sink->m_buffer->GetReadSize()) + { + sink->m_buffer->Read((unsigned char *)sink->m_outputBuffer, wanted); + int16_t *src = sink->m_outputBuffer; + float *dest = (float*)outOutputData->mBuffers[sink->m_outputBufferIndex].mData; + for (unsigned int i = 0; i < wanted / 2; i++) + *dest++ = *src++ * mul; + } + } + else + { + /* buffers appear to come from CA already zero'd, so just copy what is wanted */ + unsigned int wanted = outOutputData->mBuffers[sink->m_outputBufferIndex].mDataByteSize; + unsigned int bytes = std::min(sink->m_buffer->GetReadSize(), wanted); + sink->m_buffer->Read((unsigned char*)outOutputData->mBuffers[sink->m_outputBufferIndex].mData, bytes); + if (bytes != wanted) + CLog::Log(LOGERROR, "%s: %sFLOW (%i vs %i) bytes", __FUNCTION__, bytes > wanted ? "OVER" : "UNDER", bytes, wanted); + } + + // tell the sink we're good for more data + condVar.notifyAll(); + } + return noErr; +} diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h new file mode 100644 index 0000000000..6df15c4db5 --- /dev/null +++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.h @@ -0,0 +1,66 @@ +#pragma once +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * This Program 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, or (at your option) + * any later version. + * + * This Program 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "cores/AudioEngine/Interfaces/AESink.h" +#include "cores/AudioEngine/Utils/AEDeviceInfo.h" +#include "cores/AudioEngine/Sinks/osx/CoreAudioDevice.h" +#include "cores/AudioEngine/Sinks/osx/CoreAudioStream.h" + +class AERingBuffer; + +class CAESinkDARWINOSX : public IAESink +{ +public: + virtual const char *GetName() { return "DARWINOSX"; } + + CAESinkDARWINOSX(); + virtual ~CAESinkDARWINOSX(); + + virtual bool Initialize(AEAudioFormat &format, std::string &device); + virtual void Deinitialize(); + virtual bool IsCompatible(const AEAudioFormat &format, const std::string &device); + + virtual double GetDelay (); + virtual double GetCacheTotal (); + virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual void Drain (); + static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false); + +private: + static OSStatus renderCallback(AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData); + void SetHogMode(bool on); + + CAEDeviceInfo m_info; + AEAudioFormat m_format; + + volatile bool m_draining; + + CCoreAudioDevice m_device; + CCoreAudioStream m_outputStream; + unsigned int m_latentFrames; + unsigned int m_outputBufferIndex; + + bool m_outputBitstream; ///< true if we're bistreaming into a LinearPCM stream rather than AC3 stream. + int16_t *m_outputBuffer; ///< buffer for bitstreaming + + AERingBuffer *m_buffer; + volatile bool m_started; // set once we get a callback from CoreAudio, which can take a little while. +}; diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioChannelLayout.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioChannelLayout.cpp index 8abecfaa9e..8abecfaa9e 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioChannelLayout.cpp +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioChannelLayout.cpp diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioChannelLayout.h b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioChannelLayout.h index cf95c83666..cf95c83666 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioChannelLayout.h +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioChannelLayout.h diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioDevice.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp index a03673f1a5..937e561b42 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioDevice.cpp +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.cpp @@ -19,7 +19,7 @@ */ #include "CoreAudioDevice.h" -#include "CoreAudioAEHAL.h" +#include "CoreAudioHelpers.h" #include "CoreAudioChannelLayout.h" #include "CoreAudioHardware.h" #include "utils/log.h" @@ -29,7 +29,6 @@ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CCoreAudioDevice::CCoreAudioDevice() : m_Started (false ), - m_pSource (NULL ), m_DeviceId (0 ), m_MixerRestore (-1 ), m_IoProc (NULL ), @@ -44,7 +43,6 @@ CCoreAudioDevice::CCoreAudioDevice() : CCoreAudioDevice::CCoreAudioDevice(AudioDeviceID deviceId) : m_Started (false ), - m_pSource (NULL ), m_DeviceId (deviceId ), m_MixerRestore (-1 ), m_IoProc (NULL ), @@ -78,8 +76,7 @@ void CCoreAudioDevice::Close() Stop(); // Unregister the IOProc if we have one - if (m_IoProc) - SetInputSource(NULL, 0, 0); + RemoveIOProc(); SetHogStatus(false); CCoreAudioHardware::SetAutoHogMode(false); @@ -98,7 +95,6 @@ void CCoreAudioDevice::Close() } m_IoProc = NULL; - m_pSource = NULL; m_DeviceId = 0; m_ObjectListenerProc = NULL; } @@ -170,26 +166,13 @@ bool CCoreAudioDevice::SetObjectListenerProc(AudioObjectPropertyListenerProc cal m_ObjectListenerProc = callback; return true; } - -bool CCoreAudioDevice::SetInputSource(ICoreAudioSource* pSource, unsigned int frameSize, unsigned int outputBufferIndex) -{ - m_pSource = pSource; - m_frameSize = frameSize; - m_OutputBufferIndex = outputBufferIndex; - - if (pSource) - return AddIOProc(); - else - return RemoveIOProc(); -} - -bool CCoreAudioDevice::AddIOProc() +bool CCoreAudioDevice::AddIOProc(AudioDeviceIOProc ioProc, void* pCallbackData) { // Allow only one IOProc at a time if (!m_DeviceId || m_IoProc) return false; - OSStatus ret = AudioDeviceCreateIOProcID(m_DeviceId, DirectRenderCallback, this, &m_IoProc); + OSStatus ret = AudioDeviceCreateIOProcID(m_DeviceId, ioProc, pCallbackData, &m_IoProc); if (ret) { CLog::Log(LOGERROR, "CCoreAudioDevice::AddIOProc: " @@ -216,7 +199,6 @@ bool CCoreAudioDevice::RemoveIOProc() "Unable to remove IOProc. Error = %s", GetError(ret).c_str()); m_IoProc = NULL; // Clear the reference no matter what - m_pSource = NULL; Sleep(100); @@ -226,7 +208,7 @@ bool CCoreAudioDevice::RemoveIOProc() std::string CCoreAudioDevice::GetName() { if (!m_DeviceId) - return NULL; + return ""; AudioObjectPropertyAddress propertyAddress; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; @@ -236,9 +218,9 @@ std::string CCoreAudioDevice::GetName() UInt32 propertySize; OSStatus ret = AudioObjectGetPropertyDataSize(m_DeviceId, &propertyAddress, 0, NULL, &propertySize); if (ret != noErr) - return NULL; + return ""; - std::string name = ""; + std::string name; char *buff = new char[propertySize + 1]; buff[propertySize] = 0x00; ret = AudioObjectGetPropertyData(m_DeviceId, &propertyAddress, 0, NULL, &propertySize, buff); @@ -250,10 +232,10 @@ std::string CCoreAudioDevice::GetName() else { name = buff; + name.erase(name.find_last_not_of(" ") + 1); } delete[] buff; - return name; } @@ -478,7 +460,7 @@ bool CCoreAudioDevice::GetMixingSupport() mix = 0; } } - CLog::Log(LOGERROR, "CCoreAudioDevice::SupportsMixing: " + CLog::Log(LOGDEBUG, "CCoreAudioDevice::SupportsMixing: " "Device mixing support : %s.", mix ? "'Yes'" : "'No'"); return (mix > 0); @@ -685,27 +667,3 @@ bool CCoreAudioDevice::SetBufferSize(UInt32 size) return (ret == noErr); } - -OSStatus CCoreAudioDevice::DirectRenderCallback(AudioDeviceID inDevice, - const AudioTimeStamp *inNow, - const AudioBufferList *inInputData, - const AudioTimeStamp *inInputTime, - AudioBufferList *outOutputData, - const AudioTimeStamp *inOutputTime, - void *inClientData) -{ - OSStatus ret = noErr; - CCoreAudioDevice *audioDevice = (CCoreAudioDevice*)inClientData; - - if (audioDevice->m_pSource && audioDevice->m_frameSize) - { - UInt32 frames = outOutputData->mBuffers[audioDevice->m_OutputBufferIndex].mDataByteSize / audioDevice->m_frameSize; - ret = audioDevice->m_pSource->Render(NULL, inInputTime, 0, frames, outOutputData); - } - else - { - outOutputData->mBuffers[audioDevice->m_OutputBufferIndex].mDataByteSize = 0; - } - - return ret; -} diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioDevice.h b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h index b94a256c0e..dcd5bf6cbb 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioDevice.h +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioDevice.h @@ -25,8 +25,7 @@ #include <string> -#include "ICoreAudioSource.h" -#include "CoreAudioStream.h" +#include "cores/AudioEngine/Sinks/osx/CoreAudioStream.h" #include <CoreAudio/CoreAudio.h> @@ -68,17 +67,11 @@ public: UInt32 GetBufferSize(); bool SetBufferSize(UInt32 size); - virtual bool SetInputSource(ICoreAudioSource *pSource, unsigned int frameSize, unsigned int outputBufferIndex); -protected: - bool AddIOProc(); + bool AddIOProc(AudioDeviceIOProc ioProc, void* pCallbackData); bool RemoveIOProc(); - - static OSStatus DirectRenderCallback(AudioDeviceID inDevice, - const AudioTimeStamp *inNow, const AudioBufferList *inInputData, const AudioTimeStamp *inInputTime, - AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *inClientData); +protected: bool m_Started; - ICoreAudioSource *m_pSource; AudioDeviceID m_DeviceId; int m_MixerRestore; AudioDeviceIOProc m_IoProc; diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioHardware.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioHardware.cpp index 51984441ce..51cba80e0d 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioHardware.cpp +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioHardware.cpp @@ -20,7 +20,7 @@ #include "CoreAudioHardware.h" -#include "CoreAudioAEHAL.h" +#include "CoreAudioHelpers.h" #include "utils/log.h" #include "osx/DarwinUtils.h" diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioHardware.h b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioHardware.h index 95d33f6862..7762eb1177 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioHardware.h +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioHardware.h @@ -23,7 +23,7 @@ #if defined(TARGET_DARWIN_OSX) -#include "CoreAudioDevice.h" +#include "cores/AudioEngine/Sinks/osx/CoreAudioDevice.h" // There is only one AudioSystemObject instance system-side. // Therefore, all CCoreAudioHardware methods are static diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHAL.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioHelpers.cpp index 50bd3d5503..e8355d7854 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHAL.cpp +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioHelpers.cpp @@ -18,9 +18,7 @@ * */ -#include "CoreAudioAEHAL.h" -#include "CoreAudioAE.h" -#include "utils/log.h" +#include "CoreAudioHelpers.h" #include <sstream> diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHAL.h b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioHelpers.h index df2dd5737f..5233565a35 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHAL.h +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioHelpers.h @@ -20,7 +20,6 @@ */ #include <string> -#include <AudioUnit/AudioUnit.h> #include <AudioToolbox/AudioToolbox.h> // Helper Functions diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioStream.cpp b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp index 0e2598779a..4b7a5795e0 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioStream.cpp +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.cpp @@ -20,7 +20,7 @@ #include "CoreAudioStream.h" -#include "CoreAudioAEHAL.h" +#include "CoreAudioHelpers.h" #include "utils/log.h" #include "utils/StdString.h" @@ -127,9 +127,17 @@ UInt32 CCoreAudioStream::GetDirection() return val; } -UInt32 CCoreAudioStream::GetTerminalType() +bool CCoreAudioStream::IsDigitalOuptut(AudioStreamID id) { - if (!m_StreamId) + UInt32 type = GetTerminalType(id); + return (type == kAudioStreamTerminalTypeDigitalAudioInterface || + type == kAudioStreamTerminalTypeDisplayPort || + type == kAudioStreamTerminalTypeHDMI); +} + +UInt32 CCoreAudioStream::GetTerminalType(AudioStreamID id) +{ + if (!id) return 0; UInt32 val = 0; @@ -140,7 +148,7 @@ UInt32 CCoreAudioStream::GetTerminalType() propertyAddress.mElement = kAudioObjectPropertyElementMaster; propertyAddress.mSelector = kAudioStreamPropertyTerminalType; - OSStatus ret = AudioObjectGetPropertyData(m_StreamId, &propertyAddress, 0, NULL, &size, &val); + OSStatus ret = AudioObjectGetPropertyData(id, &propertyAddress, 0, NULL, &size, &val); if (ret) return 0; return val; @@ -335,7 +343,12 @@ bool CCoreAudioStream::SetPhysicalFormat(AudioStreamBasicDescription* pDesc) bool CCoreAudioStream::GetAvailableVirtualFormats(StreamFormatList* pList) { - if (!pList || !m_StreamId) + return GetAvailableVirtualFormats(m_StreamId, pList); +} + +bool CCoreAudioStream::GetAvailableVirtualFormats(AudioStreamID id, StreamFormatList* pList) +{ + if (!pList || !id) return false; AudioObjectPropertyAddress propertyAddress; @@ -344,13 +357,13 @@ bool CCoreAudioStream::GetAvailableVirtualFormats(StreamFormatList* pList) propertyAddress.mSelector = kAudioStreamPropertyAvailableVirtualFormats; UInt32 propertySize = 0; - OSStatus ret = AudioObjectGetPropertyDataSize(m_StreamId, &propertyAddress, 0, NULL, &propertySize); + OSStatus ret = AudioObjectGetPropertyDataSize(id, &propertyAddress, 0, NULL, &propertySize); if (ret) return false; UInt32 formatCount = propertySize / sizeof(AudioStreamRangedDescription); AudioStreamRangedDescription *pFormatList = new AudioStreamRangedDescription[formatCount]; - ret = AudioObjectGetPropertyData(m_StreamId, &propertyAddress, 0, NULL, &propertySize, pFormatList); + ret = AudioObjectGetPropertyData(id, &propertyAddress, 0, NULL, &propertySize, pFormatList); if (!ret) { for (UInt32 format = 0; format < formatCount; format++) @@ -362,7 +375,12 @@ bool CCoreAudioStream::GetAvailableVirtualFormats(StreamFormatList* pList) bool CCoreAudioStream::GetAvailablePhysicalFormats(StreamFormatList* pList) { - if (!pList || !m_StreamId) + return GetAvailablePhysicalFormats(m_StreamId, pList); +} + +bool CCoreAudioStream::GetAvailablePhysicalFormats(AudioStreamID id, StreamFormatList* pList) +{ + if (!pList || !id) return false; AudioObjectPropertyAddress propertyAddress; @@ -371,13 +389,13 @@ bool CCoreAudioStream::GetAvailablePhysicalFormats(StreamFormatList* pList) propertyAddress.mSelector = kAudioStreamPropertyAvailablePhysicalFormats; UInt32 propertySize = 0; - OSStatus ret = AudioObjectGetPropertyDataSize(m_StreamId, &propertyAddress, 0, NULL, &propertySize); + OSStatus ret = AudioObjectGetPropertyDataSize(id, &propertyAddress, 0, NULL, &propertySize); if (ret) return false; UInt32 formatCount = propertySize / sizeof(AudioStreamRangedDescription); AudioStreamRangedDescription *pFormatList = new AudioStreamRangedDescription[formatCount]; - ret = AudioObjectGetPropertyData(m_StreamId, &propertyAddress, 0, NULL, &propertySize, pFormatList); + ret = AudioObjectGetPropertyData(id, &propertyAddress, 0, NULL, &propertySize, pFormatList); if (!ret) { for (UInt32 format = 0; format < formatCount; format++) diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioStream.h b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h index 008800e56d..3f3d1d0f79 100644 --- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioStream.h +++ b/xbmc/cores/AudioEngine/Sinks/osx/CoreAudioStream.h @@ -23,7 +23,7 @@ #if defined(TARGET_DARWIN_OSX) -#include "threads/Thread.h" +#include "threads/Event.h" #include <CoreAudio/CoreAudio.h> #include <list> @@ -39,10 +39,10 @@ public: bool Open(AudioStreamID streamId); void Close(bool restore = true); - + AudioStreamID GetId() {return m_StreamId;} UInt32 GetDirection(); - UInt32 GetTerminalType(); + static UInt32 GetTerminalType(AudioStreamID id); UInt32 GetNumLatencyFrames(); bool GetVirtualFormat(AudioStreamBasicDescription *pDesc); bool GetPhysicalFormat(AudioStreamBasicDescription *pDesc); @@ -50,7 +50,10 @@ public: bool SetPhysicalFormat(AudioStreamBasicDescription *pDesc); bool GetAvailableVirtualFormats(StreamFormatList *pList); bool GetAvailablePhysicalFormats(StreamFormatList *pList); - + static bool GetAvailableVirtualFormats(AudioStreamID id, StreamFormatList *pList); + static bool GetAvailablePhysicalFormats(AudioStreamID id, StreamFormatList *pList); + static bool IsDigitalOuptut(AudioStreamID id); + protected: static OSStatus HardwareStreamListener(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* inClientData); @@ -58,10 +61,9 @@ protected: CEvent m_virtual_format_event; CEvent m_physical_format_event; - AudioStreamID m_StreamId; AudioStreamBasicDescription m_OriginalVirtualFormat; - AudioStreamBasicDescription m_OriginalPhysicalFormat; + AudioStreamBasicDescription m_OriginalPhysicalFormat; }; #endif diff --git a/xbmc/osx/IOSScreenManager.mm b/xbmc/osx/IOSScreenManager.mm index 1fe7f7a90b..ad2a7cb611 100644 --- a/xbmc/osx/IOSScreenManager.mm +++ b/xbmc/osx/IOSScreenManager.mm @@ -29,6 +29,7 @@ #include "Application.h" #include "WindowingFactory.h" #include "settings/DisplaySettings.h" +#include "cores/AudioEngine/AEFactory.h" #undef BOOL #import <Foundation/Foundation.h> @@ -205,6 +206,10 @@ static CEvent screenChangeEvent; { [self changeScreenSelector:dict]; } + + // re-enumerate audio devices in that case too + // as we might gain passthrough capabilities via HDMI + CAEFactory::DeviceChange(); return true; } //-------------------------------------------------------------- diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp index d30aa30d4c..892a1392c8 100644 --- a/xbmc/settings/Settings.cpp +++ b/xbmc/settings/Settings.cpp @@ -55,7 +55,6 @@ #include "network/WakeOnAccess.h" #if defined(TARGET_DARWIN_OSX) #include "osx/XBMCHelper.h" -#include "cores/AudioEngine/Engines/CoreAudio/CoreAudioHardware.h" #endif // defined(TARGET_DARWIN_OSX) #if defined(TARGET_DARWIN) #include "osx/DarwinUtils.h" @@ -798,14 +797,7 @@ void CSettings::InitializeDefaults() #endif #endif -#if defined(TARGET_DARWIN) - #if !defined(TARGET_DARWIN_IOS) - CStdString defaultAudioDeviceName; - CCoreAudioHardware::GetOutputDeviceName(defaultAudioDeviceName); - ((CSettingString*)m_settingsManager->GetSetting("audiooutput.audiodevice"))->SetDefault(defaultAudioDeviceName); - ((CSettingString*)m_settingsManager->GetSetting("audiooutput.passthroughdevice"))->SetDefault(defaultAudioDeviceName); - #endif -#elif !defined(TARGET_WINDOWS) +#if !defined(TARGET_WINDOWS) ((CSettingString*)m_settingsManager->GetSetting("audiooutput.audiodevice"))->SetDefault(CAEFactory::GetDefaultDevice(false)); ((CSettingString*)m_settingsManager->GetSetting("audiooutput.passthroughdevice"))->SetDefault(CAEFactory::GetDefaultDevice(true)); #endif |