From 010c235e4623ae33ba0c14ef771ca36756934f03 Mon Sep 17 00:00:00 2001 From: "Morgan J." Date: Sun, 15 Mar 2026 06:02:56 +0900 Subject: [PATCH] Initial commit --- .editorconfig | 15 + .gitignore | 39 + LICENSE | 339 +++++ LICENSE-Apple-Sample-Code | 56 + Makefile | 151 ++ app/Info.plist | 24 + app/PublicUtility/CAAtomic.h | 318 ++++ app/PublicUtility/CAAutoDisposer.h | 508 +++++++ app/PublicUtility/CABitOperations.h | 206 +++ app/PublicUtility/CACFArray.cpp | 821 +++++++++++ app/PublicUtility/CACFArray.h | 195 +++ app/PublicUtility/CACFDictionary.cpp | 581 ++++++++ app/PublicUtility/CACFDictionary.h | 176 +++ app/PublicUtility/CACFNumber.cpp | 83 ++ app/PublicUtility/CACFNumber.h | 151 ++ app/PublicUtility/CACFString.cpp | 110 ++ app/PublicUtility/CACFString.h | 196 +++ app/PublicUtility/CADebugMacros.cpp | 134 ++ app/PublicUtility/CADebugMacros.h | 612 ++++++++ app/PublicUtility/CADebugPrintf.cpp | 114 ++ app/PublicUtility/CADebugPrintf.h | 113 ++ app/PublicUtility/CADebugger.cpp | 103 ++ app/PublicUtility/CADebugger.h | 78 + app/PublicUtility/CAException.h | 83 ++ app/PublicUtility/CAHALAudioDevice.cpp | 1156 +++++++++++++++ app/PublicUtility/CAHALAudioDevice.h | 238 +++ app/PublicUtility/CAHALAudioObject.cpp | 373 +++++ app/PublicUtility/CAHALAudioObject.h | 155 ++ app/PublicUtility/CAHALAudioStream.cpp | 182 +++ app/PublicUtility/CAHALAudioStream.h | 94 ++ app/PublicUtility/CAHALAudioSystemObject.cpp | 181 +++ app/PublicUtility/CAHALAudioSystemObject.h | 90 ++ app/PublicUtility/CAHostTimeBase.cpp | 99 ++ app/PublicUtility/CAHostTimeBase.h | 234 +++ app/PublicUtility/CAMutex.cpp | 345 +++++ app/PublicUtility/CAMutex.h | 192 +++ app/PublicUtility/CAPThread.cpp | 450 ++++++ app/PublicUtility/CAPThread.h | 191 +++ app/PublicUtility/CAPropertyAddress.h | 292 ++++ app/PublicUtility/CARingBuffer.cpp | 319 ++++ app/PublicUtility/CARingBuffer.h | 126 ++ app/PublicUtility/VCDebugLogging.c | 50 + app/PublicUtility/VCDebugLogging.h | 63 + app/PublicUtility/VCThreadSafetyAnalysis.h | 104 ++ app/VCAudioDevice.cpp | 387 +++++ app/VCAudioDevice.h | 121 ++ app/VCAudioDeviceManager.h | 55 + app/VCAudioDeviceManager.mm | 465 ++++++ app/VCPlayThrough.cpp | 1250 ++++++++++++++++ app/VCPlayThrough.h | 238 +++ app/VCPlayThroughRTLogger.cpp | 521 +++++++ app/VCPlayThroughRTLogger.h | 227 +++ app/VCTermination.h | 33 + app/VCTermination.mm | 69 + app/VCVirtualDevice.cpp | 119 ++ app/VCVirtualDevice.h | 85 ++ app/main.mm | 169 +++ driver/DeviceIcon.icns | Bin 0 -> 128046 bytes driver/Info.plist | 40 + driver/PublicUtility/CAAtomic.h | 317 ++++ driver/PublicUtility/CAAtomicStack.h | 242 ++++ driver/PublicUtility/CAAutoDisposer.h | 508 +++++++ driver/PublicUtility/CABitOperations.h | 206 +++ driver/PublicUtility/CACFArray.cpp | 821 +++++++++++ driver/PublicUtility/CACFArray.h | 195 +++ driver/PublicUtility/CACFDictionary.cpp | 581 ++++++++ driver/PublicUtility/CACFDictionary.h | 176 +++ driver/PublicUtility/CACFNumber.cpp | 83 ++ driver/PublicUtility/CACFNumber.h | 151 ++ driver/PublicUtility/CACFString.cpp | 110 ++ driver/PublicUtility/CACFString.h | 180 +++ driver/PublicUtility/CADebugMacros.cpp | 116 ++ driver/PublicUtility/CADebugMacros.h | 583 ++++++++ driver/PublicUtility/CADebugPrintf.cpp | 89 ++ driver/PublicUtility/CADebugPrintf.h | 115 ++ driver/PublicUtility/CADebugger.cpp | 103 ++ driver/PublicUtility/CADebugger.h | 69 + driver/PublicUtility/CADispatchQueue.cpp | 438 ++++++ driver/PublicUtility/CADispatchQueue.h | 235 +++ driver/PublicUtility/CAException.h | 83 ++ driver/PublicUtility/CAHostTimeBase.cpp | 99 ++ driver/PublicUtility/CAHostTimeBase.h | 234 +++ driver/PublicUtility/CAMutex.cpp | 345 +++++ driver/PublicUtility/CAMutex.h | 164 +++ driver/PublicUtility/CAPThread.cpp | 450 ++++++ driver/PublicUtility/CAPThread.h | 191 +++ driver/PublicUtility/CAPropertyAddress.h | 321 +++++ driver/PublicUtility/CARingBuffer.cpp | 319 ++++ driver/PublicUtility/CARingBuffer.h | 126 ++ driver/PublicUtility/CAVolumeCurve.cpp | 482 +++++++ driver/PublicUtility/CAVolumeCurve.h | 178 +++ driver/VC_AbstractDevice.cpp | 410 ++++++ driver/VC_AbstractDevice.h | 111 ++ driver/VC_Control.cpp | 182 +++ driver/VC_Control.h | 87 ++ driver/VC_Device.cpp | 1363 ++++++++++++++++++ driver/VC_Device.h | 240 +++ driver/VC_MuteControl.cpp | 225 +++ driver/VC_MuteControl.h | 98 ++ driver/VC_Object.cpp | 184 +++ driver/VC_Object.h | 162 +++ driver/VC_PlugIn.cpp | 232 +++ driver/VC_PlugIn.h | 90 ++ driver/VC_PlugInInterface.cpp | 946 ++++++++++++ driver/VC_Stream.cpp | 488 +++++++ driver/VC_Stream.h | 112 ++ driver/VC_TaskQueue.cpp | 405 ++++++ driver/VC_TaskQueue.h | 180 +++ driver/VC_VolumeControl.cpp | 462 ++++++ driver/VC_VolumeControl.h | 168 +++ shared/VC_Types.h | 106 ++ shared/VC_Utils.cpp | 235 +++ shared/VC_Utils.h | 228 +++ 113 files changed, 28943 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 LICENSE-Apple-Sample-Code create mode 100644 Makefile create mode 100644 app/Info.plist create mode 100644 app/PublicUtility/CAAtomic.h create mode 100644 app/PublicUtility/CAAutoDisposer.h create mode 100644 app/PublicUtility/CABitOperations.h create mode 100644 app/PublicUtility/CACFArray.cpp create mode 100644 app/PublicUtility/CACFArray.h create mode 100644 app/PublicUtility/CACFDictionary.cpp create mode 100644 app/PublicUtility/CACFDictionary.h create mode 100644 app/PublicUtility/CACFNumber.cpp create mode 100644 app/PublicUtility/CACFNumber.h create mode 100644 app/PublicUtility/CACFString.cpp create mode 100644 app/PublicUtility/CACFString.h create mode 100644 app/PublicUtility/CADebugMacros.cpp create mode 100644 app/PublicUtility/CADebugMacros.h create mode 100644 app/PublicUtility/CADebugPrintf.cpp create mode 100644 app/PublicUtility/CADebugPrintf.h create mode 100644 app/PublicUtility/CADebugger.cpp create mode 100644 app/PublicUtility/CADebugger.h create mode 100644 app/PublicUtility/CAException.h create mode 100644 app/PublicUtility/CAHALAudioDevice.cpp create mode 100644 app/PublicUtility/CAHALAudioDevice.h create mode 100644 app/PublicUtility/CAHALAudioObject.cpp create mode 100644 app/PublicUtility/CAHALAudioObject.h create mode 100644 app/PublicUtility/CAHALAudioStream.cpp create mode 100644 app/PublicUtility/CAHALAudioStream.h create mode 100644 app/PublicUtility/CAHALAudioSystemObject.cpp create mode 100644 app/PublicUtility/CAHALAudioSystemObject.h create mode 100644 app/PublicUtility/CAHostTimeBase.cpp create mode 100644 app/PublicUtility/CAHostTimeBase.h create mode 100644 app/PublicUtility/CAMutex.cpp create mode 100644 app/PublicUtility/CAMutex.h create mode 100644 app/PublicUtility/CAPThread.cpp create mode 100644 app/PublicUtility/CAPThread.h create mode 100644 app/PublicUtility/CAPropertyAddress.h create mode 100644 app/PublicUtility/CARingBuffer.cpp create mode 100644 app/PublicUtility/CARingBuffer.h create mode 100644 app/PublicUtility/VCDebugLogging.c create mode 100644 app/PublicUtility/VCDebugLogging.h create mode 100644 app/PublicUtility/VCThreadSafetyAnalysis.h create mode 100644 app/VCAudioDevice.cpp create mode 100644 app/VCAudioDevice.h create mode 100644 app/VCAudioDeviceManager.h create mode 100644 app/VCAudioDeviceManager.mm create mode 100644 app/VCPlayThrough.cpp create mode 100644 app/VCPlayThrough.h create mode 100644 app/VCPlayThroughRTLogger.cpp create mode 100644 app/VCPlayThroughRTLogger.h create mode 100644 app/VCTermination.h create mode 100644 app/VCTermination.mm create mode 100644 app/VCVirtualDevice.cpp create mode 100644 app/VCVirtualDevice.h create mode 100644 app/main.mm create mode 100644 driver/DeviceIcon.icns create mode 100644 driver/Info.plist create mode 100644 driver/PublicUtility/CAAtomic.h create mode 100644 driver/PublicUtility/CAAtomicStack.h create mode 100644 driver/PublicUtility/CAAutoDisposer.h create mode 100644 driver/PublicUtility/CABitOperations.h create mode 100644 driver/PublicUtility/CACFArray.cpp create mode 100644 driver/PublicUtility/CACFArray.h create mode 100644 driver/PublicUtility/CACFDictionary.cpp create mode 100644 driver/PublicUtility/CACFDictionary.h create mode 100644 driver/PublicUtility/CACFNumber.cpp create mode 100644 driver/PublicUtility/CACFNumber.h create mode 100644 driver/PublicUtility/CACFString.cpp create mode 100644 driver/PublicUtility/CACFString.h create mode 100644 driver/PublicUtility/CADebugMacros.cpp create mode 100644 driver/PublicUtility/CADebugMacros.h create mode 100644 driver/PublicUtility/CADebugPrintf.cpp create mode 100644 driver/PublicUtility/CADebugPrintf.h create mode 100644 driver/PublicUtility/CADebugger.cpp create mode 100644 driver/PublicUtility/CADebugger.h create mode 100644 driver/PublicUtility/CADispatchQueue.cpp create mode 100644 driver/PublicUtility/CADispatchQueue.h create mode 100644 driver/PublicUtility/CAException.h create mode 100644 driver/PublicUtility/CAHostTimeBase.cpp create mode 100644 driver/PublicUtility/CAHostTimeBase.h create mode 100644 driver/PublicUtility/CAMutex.cpp create mode 100644 driver/PublicUtility/CAMutex.h create mode 100644 driver/PublicUtility/CAPThread.cpp create mode 100644 driver/PublicUtility/CAPThread.h create mode 100644 driver/PublicUtility/CAPropertyAddress.h create mode 100644 driver/PublicUtility/CARingBuffer.cpp create mode 100644 driver/PublicUtility/CARingBuffer.h create mode 100644 driver/PublicUtility/CAVolumeCurve.cpp create mode 100644 driver/PublicUtility/CAVolumeCurve.h create mode 100644 driver/VC_AbstractDevice.cpp create mode 100644 driver/VC_AbstractDevice.h create mode 100644 driver/VC_Control.cpp create mode 100644 driver/VC_Control.h create mode 100644 driver/VC_Device.cpp create mode 100644 driver/VC_Device.h create mode 100644 driver/VC_MuteControl.cpp create mode 100644 driver/VC_MuteControl.h create mode 100644 driver/VC_Object.cpp create mode 100644 driver/VC_Object.h create mode 100644 driver/VC_PlugIn.cpp create mode 100644 driver/VC_PlugIn.h create mode 100644 driver/VC_PlugInInterface.cpp create mode 100644 driver/VC_Stream.cpp create mode 100644 driver/VC_Stream.h create mode 100644 driver/VC_TaskQueue.cpp create mode 100644 driver/VC_TaskQueue.h create mode 100644 driver/VC_VolumeControl.cpp create mode 100644 driver/VC_VolumeControl.h create mode 100644 shared/VC_Types.h create mode 100644 shared/VC_Utils.cpp create mode 100644 shared/VC_Utils.h diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1e50794 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +# This file was added to get GitHub to display our source code correctly when +# it has mixed tabs and spaces. (I didn't realise the sample code BGMDriver is +# based on used tabs and it's too late to fix it now.) +# +# See http://editorconfig.org. + +# This is the top-most .editorconfig file. +root = true + +# Set tabs to the width of 4 spaces in C, C++, Objective-C and Objective-C++ +# source files. +[*.{h,c,cpp,m,mm}] +tab_width = 4 + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c57aec9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +.DS_Store +.*.swp +/BGMDriver/BGMDriver/quick_install.conf +/build_and_install.log +.idea/ +tags +cmake-build-debug/ +/Background-Music-*/ +BGM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +Images/*.aux +Images/*.log +/archives/ + +# Everything below is from https://github.com/github/gitignore/blob/master/Objective-C.gitignore + +## Build generated +build/ +DerivedData + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata + +## Other +*.xccheckout +*.moved-aside +*.xcuserstate +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 of the License, 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 this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/LICENSE-Apple-Sample-Code b/LICENSE-Apple-Sample-Code new file mode 100644 index 0000000..49f25c4 --- /dev/null +++ b/LICENSE-Apple-Sample-Code @@ -0,0 +1,56 @@ +Background Music includes code from Core Audio User-Space Driver +Examples, see +, +which was provided with the following copyright notice and the license +below. + +Copyright (C) 2013 Apple Inc. All Rights Reserved. + +Background Music includes code from Core Audio Utility Classes, see +, +which was provided with the following copyright notice and the license +below. + +Copyright (C) 2014 Apple Inc. All Rights Reserved. + +------------------------------------------------------------------------ + +Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple +Inc. ("Apple") in consideration of your agreement to the following +terms, and your use, installation, modification or redistribution of +this Apple software constitutes acceptance of these terms. If you do +not agree with these terms, please do not use, install, modify or +redistribute this Apple software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, Apple grants you a personal, non-exclusive +license, under Apple's copyrights in this original Apple software (the +"Apple Software"), to use, reproduce, modify and redistribute the Apple +Software, with or without modifications, in source and/or binary forms; +provided that if you redistribute the Apple Software in its entirety and +without modifications, you must retain this notice and the following +text and disclaimers in all such redistributions of the Apple Software. +Neither the name, trademarks, service marks or logos of Apple Inc. may +be used to endorse or promote products derived from the Apple Software +without specific prior written permission from Apple. Except as +expressly stated in this notice, no other rights or licenses, express or +implied, are granted by Apple herein, including but not limited to any +patent rights that may be infringed by your derivative works or by other +works in which the Apple Software may be incorporated. + +The Apple Software is provided by Apple on an "AS IS" basis. APPLE +MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION +THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND +OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + +IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, +MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED +AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), +STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9ef98c0 --- /dev/null +++ b/Makefile @@ -0,0 +1,151 @@ +# VolumeControl Makefile + +CXX = clang++ +CC = clang +CXXFLAGS = -std=c++11 -stdlib=libc++ -fPIC -O2 +OBJCFLAGS = -fobjc-arc +CFLAGS = + +BUILD_DIR = build + +DRIVER_INSTALL_PATH = /Library/Audio/Plug-Ins/HAL +APP_INSTALL_PATH = /Applications +LAUNCHAGENT_DIR = $(HOME)/Library/LaunchAgents +LAUNCHAGENT_PLIST = com.volumecontrol.App.plist + +# --- Driver --- + +DRIVER_NAME = VolumeControl +DRIVER_BUNDLE = $(BUILD_DIR)/$(DRIVER_NAME).driver +DRIVER_CONTENTS = $(DRIVER_BUNDLE)/Contents +DRIVER_MACOS = $(DRIVER_CONTENTS)/MacOS +DRIVER_BINARY = $(DRIVER_MACOS)/$(DRIVER_NAME) + +DRIVER_SRC = driver +DRIVER_UTIL = driver/PublicUtility +SHARED = shared + +DRIVER_INCLUDES = -I$(DRIVER_SRC) -I$(DRIVER_UTIL) -I$(SHARED) +DRIVER_FRAMEWORKS = -framework CoreAudio -framework CoreFoundation -framework IOKit -framework Accelerate + +DRIVER_CPP_SRCS = $(wildcard $(DRIVER_SRC)/*.cpp) $(wildcard $(DRIVER_UTIL)/*.cpp) $(wildcard $(SHARED)/*.cpp) +DRIVER_CPP_OBJS = $(patsubst %.cpp,$(BUILD_DIR)/driver_obj/%.o,$(DRIVER_CPP_SRCS)) + +# --- Daemon --- + +APP_NAME = VolumeControl +APP_BUNDLE = $(BUILD_DIR)/$(APP_NAME).app +APP_CONTENTS = $(APP_BUNDLE)/Contents +APP_MACOS = $(APP_CONTENTS)/MacOS +APP_BINARY = $(APP_MACOS)/$(APP_NAME) + +APP_SRC = app +APP_UTIL = app/PublicUtility + +APP_INCLUDES = -I$(APP_SRC) -I$(APP_UTIL) -I$(SHARED) +APP_FRAMEWORKS = -framework Cocoa -framework CoreAudio -framework AudioToolbox -framework Accelerate -framework AVFoundation + +APP_CPP_SRCS = $(wildcard $(APP_SRC)/*.cpp) $(wildcard $(APP_UTIL)/*.cpp) $(wildcard $(SHARED)/*.cpp) +APP_MM_SRCS = $(wildcard $(APP_SRC)/*.mm) +APP_C_SRCS = $(wildcard $(APP_UTIL)/*.c) + +APP_CPP_OBJS = $(patsubst %.cpp,$(BUILD_DIR)/app_obj/%.o,$(APP_CPP_SRCS)) +APP_MM_OBJS = $(patsubst %.mm,$(BUILD_DIR)/app_obj/%.o,$(APP_MM_SRCS)) +APP_C_OBJS = $(patsubst %.c,$(BUILD_DIR)/app_obj/%.o,$(APP_C_SRCS)) + +APP_ALL_OBJS = $(APP_CPP_OBJS) $(APP_MM_OBJS) $(APP_C_OBJS) + +# --- Targets --- + +.PHONY: all driver daemon install uninstall clean + +all: driver daemon + +driver: $(DRIVER_BINARY) $(DRIVER_CONTENTS)/Info.plist + +$(DRIVER_BINARY): $(DRIVER_CPP_OBJS) + @mkdir -p $(DRIVER_MACOS) + $(CXX) $(CXXFLAGS) $(DRIVER_FRAMEWORKS) -bundle -o $@ $^ + +$(DRIVER_CONTENTS)/Info.plist: $(DRIVER_SRC)/Info.plist + @mkdir -p $(DRIVER_CONTENTS) + cp $< $@ + +$(BUILD_DIR)/driver_obj/%.o: %.cpp + @mkdir -p $(dir $@) + $(CXX) $(CXXFLAGS) $(DRIVER_INCLUDES) -c -o $@ $< + +daemon: $(APP_BINARY) $(APP_CONTENTS)/Info.plist + +$(APP_BINARY): $(APP_ALL_OBJS) + @mkdir -p $(APP_MACOS) + $(CXX) $(CXXFLAGS) $(OBJCFLAGS) $(APP_FRAMEWORKS) -o $@ $^ + +$(APP_CONTENTS)/Info.plist: $(APP_SRC)/Info.plist + @mkdir -p $(APP_CONTENTS) + cp $< $@ + +$(BUILD_DIR)/app_obj/%.o: %.cpp + @mkdir -p $(dir $@) + $(CXX) $(CXXFLAGS) $(APP_INCLUDES) -c -o $@ $< + +$(BUILD_DIR)/app_obj/%.o: %.mm + @mkdir -p $(dir $@) + $(CXX) $(CXXFLAGS) $(OBJCFLAGS) $(APP_INCLUDES) -c -o $@ $< + +$(BUILD_DIR)/app_obj/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(APP_INCLUDES) -c -o $@ $< + +install-app: daemon + @echo "Installing VolumeControl app only (no driver change)..." + @launchctl unload "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" 2>/dev/null; true + @killall VolumeControl 2>/dev/null; sleep 1; true + sudo rm -rf "$(APP_INSTALL_PATH)/$(APP_NAME).app" + sudo cp -R "$(APP_BUNDLE)" "$(APP_INSTALL_PATH)/" + sudo xattr -cr "$(APP_INSTALL_PATH)/$(APP_NAME).app" + launchctl load "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" 2>/dev/null; true + @echo "Done." + +install: all + @echo "Installing VolumeControl..." + @# Stop any running instance before touching the driver. + @launchctl unload "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" 2>/dev/null; true + @killall VolumeControl 2>/dev/null; sleep 1; true + sudo mkdir -p "$(DRIVER_INSTALL_PATH)" + sudo rm -rf "$(DRIVER_INSTALL_PATH)/$(DRIVER_NAME).driver" + sudo cp -R "$(DRIVER_BUNDLE)" "$(DRIVER_INSTALL_PATH)/" + sudo xattr -cr "$(DRIVER_INSTALL_PATH)/$(DRIVER_NAME).driver" + sudo killall -9 coreaudiod + @echo "Waiting for coreaudiod..." + @sleep 5 + sudo mkdir -p "$(APP_INSTALL_PATH)" + sudo rm -rf "$(APP_INSTALL_PATH)/$(APP_NAME).app" + sudo cp -R "$(APP_BUNDLE)" "$(APP_INSTALL_PATH)/" + sudo xattr -cr "$(APP_INSTALL_PATH)/$(APP_NAME).app" + @# Install LaunchAgent to start on login + @mkdir -p "$(LAUNCHAGENT_DIR)" + @echo '' > "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" + @echo '' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" + @echo '' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" + @echo ' Labelcom.volumecontrol.App' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" + @echo ' ProgramArguments/Applications/VolumeControl.app/Contents/MacOS/VolumeControl' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" + @echo ' RunAtLoad' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" + @echo ' KeepAlive' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" + @echo '' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" + launchctl load "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" 2>/dev/null; true + @echo "Done. VolumeControl daemon is running and will start on login." + +uninstall: + @echo "Uninstalling VolumeControl..." + @launchctl unload "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" 2>/dev/null; true + @rm -f "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)" + @killall VolumeControl 2>/dev/null; sleep 1; true + sudo rm -rf "$(DRIVER_INSTALL_PATH)/$(DRIVER_NAME).driver" + sudo rm -rf "$(APP_INSTALL_PATH)/$(APP_NAME).app" + sudo killall -9 coreaudiod + @defaults delete com.volumecontrol.App 2>/dev/null; true + @echo "Done." + +clean: + rm -rf $(BUILD_DIR) diff --git a/app/Info.plist b/app/Info.plist new file mode 100644 index 0000000..406a545 --- /dev/null +++ b/app/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleExecutable + VolumeControl + CFBundleIdentifier + com.volumecontrol.App + CFBundleName + VolumeControl + CFBundlePackageType + APPL + CFBundleVersion + 1.0.0 + CFBundleShortVersionString + 1.0.0 + LSUIElement + + LSMinimumSystemVersion + 10.14 + NSMicrophoneUsageDescription + VolumeControl reads system audio through a virtual input device to provide software volume control for HDMI and other outputs. + + diff --git a/app/PublicUtility/CAAtomic.h b/app/PublicUtility/CAAtomic.h new file mode 100644 index 0000000..9eabc06 --- /dev/null +++ b/app/PublicUtility/CAAtomic.h @@ -0,0 +1,318 @@ +/* + File: CAAtomic.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +/* + This file implements all Atomic operations using Interlocked functions specified in + Winbase.h +NOTE: According to Microsoft documentation, all Interlocked functions generates a +full barrier. + On Windows: + As the Interlocked functions returns the Old value, Extra checks and operations + are made after the atomic operation to return value consistent with OSX counterparts. +*/ +#ifndef __CAAtomic_h__ +#define __CAAtomic_h__ + +#if TARGET_OS_WIN32 + #include + #include + #pragma intrinsic(_InterlockedOr) + #pragma intrinsic(_InterlockedAnd) +#else + #include + #include +#endif + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +inline void CAMemoryBarrier() +{ +#if TARGET_OS_WIN32 + MemoryBarrier(); +#else + OSMemoryBarrier(); +#endif +} + +inline SInt32 CAAtomicAdd32Barrier(SInt32 theAmt, volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + long lRetVal = InterlockedExchangeAdd((volatile long*)theValue, theAmt); + // InterlockedExchangeAdd returns the original value which differs from OSX version. + // At this point the addition would have occured and hence returning the new value + // to keep it sync with OSX. + return lRetVal + theAmt; +#else + return OSAtomicAdd32Barrier(theAmt, (volatile int32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicOr32Barrier(UInt32 theMask, volatile UInt32* theValue) +{ +#if TARGET_OS_WIN32 + // InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic + // function instead. + long j = _InterlockedOr((volatile long*)theValue, theMask); + // _InterlockedOr returns the original value which differs from OSX version. + // Returning the new value similar to OSX + return (SInt32)(j | theMask); +#else + return OSAtomicOr32Barrier(theMask, (volatile uint32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicAnd32Barrier(UInt32 theMask, volatile UInt32* theValue) +{ +#if TARGET_OS_WIN32 +// InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic +// function instead. + long j = _InterlockedAnd((volatile long*)theValue, theMask); + // _InterlockedAnd returns the original value which differs from OSX version. + // Returning the new value similar to OSX + return (SInt32)(j & theMask); +#else + return OSAtomicAnd32Barrier(theMask, (volatile uint32_t *)theValue); +#endif +} + +inline bool CAAtomicCompareAndSwap32Barrier(SInt32 oldValue, SInt32 newValue, volatile SInt32 *theValue) +{ +#if TARGET_OS_WIN32 + // InterlockedCompareExchange returns the old value. But we need to return bool value. + long lRetVal = InterlockedCompareExchange((volatile long*)theValue, newValue, oldValue); +// Hence we check if the new value is set and if it is we return true else false. +// If theValue is equal to oldValue then the swap happens. Otherwise swap doesn't happen. + return (oldValue == lRetVal); +#else + return OSAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile int32_t *)theValue); +#endif +} + + +inline SInt32 CAAtomicIncrement32(volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + return (SInt32)InterlockedIncrement((volatile long*)theValue); +#else + return OSAtomicIncrement32((volatile int32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicDecrement32(volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + return (SInt32)InterlockedDecrement((volatile long*)theValue); +#else + return OSAtomicDecrement32((volatile int32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicIncrement32Barrier(volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + return CAAtomicIncrement32(theValue); +#else + return OSAtomicIncrement32Barrier((volatile int32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicDecrement32Barrier(volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + return CAAtomicDecrement32(theValue); +#else + return OSAtomicDecrement32Barrier((volatile int32_t *)theValue); +#endif +} + +inline bool CAAtomicTestAndClearBarrier(int bitToClear, void* theAddress) +{ +#if TARGET_OS_WIN32 + BOOL bOldVal = InterlockedBitTestAndReset((long*)theAddress, bitToClear); + return (bOldVal ? true : false); +#else + return OSAtomicTestAndClearBarrier(bitToClear, (volatile void *)theAddress); +#endif +} + +inline bool CAAtomicTestAndClear(int bitToClear, void* theAddress) +{ +#if TARGET_OS_WIN32 + BOOL bOldVal = CAAtomicTestAndClearBarrier(bitToClear, (long*)theAddress); + return (bOldVal ? true : false); +#else + return OSAtomicTestAndClear(bitToClear, (volatile void *)theAddress); +#endif +} + +inline bool CAAtomicTestAndSetBarrier(int bitToSet, void* theAddress) +{ +#if TARGET_OS_WIN32 + BOOL bOldVal = InterlockedBitTestAndSet((long*)theAddress, bitToSet); + return (bOldVal ? true : false); +#else + return OSAtomicTestAndSetBarrier(bitToSet, (volatile void *)theAddress); +#endif +} + +#pragma clang diagnostic pop + +// int32_t flavors -- for C++ only since we can't overload in C +// CFBase.h defines SInt32 as signed int which is similar to int32_t. If CFBase.h is included, then +// this will generate redefinition error. But on Mac, CFBase.h, still includes MacTypes.h where +// SInt32 is defined as signed long so this would work there. +// So in order to fix the redefinition errors, we define these functions only if MacTypes.h is included. +#if defined(__cplusplus) && defined(__MACTYPES__) && !__LP64__ +inline int32_t CAAtomicAdd32Barrier(int32_t theAmt, volatile int32_t* theValue) +{ + return CAAtomicAdd32Barrier(theAmt, (volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicOr32Barrier(uint32_t theMask, volatile uint32_t* theValue) +{ + return CAAtomicOr32Barrier(theMask, (volatile UInt32 *)theValue); +} + +inline int32_t CAAtomicAnd32Barrier(uint32_t theMask, volatile uint32_t* theValue) +{ + return CAAtomicAnd32Barrier(theMask, (volatile UInt32 *)theValue); +} + +inline bool CAAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue) +{ + return CAAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicIncrement32(volatile int32_t* theValue) +{ + return CAAtomicIncrement32((volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicDecrement32(volatile int32_t* theValue) +{ + return CAAtomicDecrement32((volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicIncrement32Barrier(volatile int32_t* theValue) +{ + return CAAtomicIncrement32Barrier((volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicDecrement32Barrier(volatile int32_t* theValue) +{ + return CAAtomicDecrement32Barrier((volatile SInt32 *)theValue); +} +#endif // __cplusplus && !__LP64__ + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" + +#if __LP64__ +inline bool CAAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue ) +{ + return OSAtomicCompareAndSwap64Barrier(__oldValue, __newValue, __theValue); +} +#endif + +inline bool CAAtomicCompareAndSwapPtrBarrier(void *__oldValue, void *__newValue, volatile void ** __theValue) +{ +#if __LP64__ + return CAAtomicCompareAndSwap64Barrier((int64_t)__oldValue, (int64_t)__newValue, (int64_t *)__theValue); +#else + return CAAtomicCompareAndSwap32Barrier((int32_t)__oldValue, (int32_t)__newValue, (int32_t *)__theValue); +#endif +} + +#pragma clang diagnostic pop + +/* Spinlocks. These use memory barriers as required to synchronize access to shared + * memory protected by the lock. The lock operation spins, but employs various strategies + * to back off if the lock is held, making it immune to most priority-inversion livelocks. + * The try operation immediately returns false if the lock was held, true if it took the + * lock. The convention is that unlocked is zero, locked is nonzero. + */ +#define CA_SPINLOCK_INIT 0 + +typedef int32_t CASpinLock; + +bool CASpinLockTry( volatile CASpinLock *__lock ); +void CASpinLockLock( volatile CASpinLock *__lock ); +void CASpinLockUnlock( volatile CASpinLock *__lock ); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" + +inline void CASpinLockLock( volatile CASpinLock *__lock ) +{ +#if TARGET_OS_MAC + OSSpinLockLock(__lock); +#else + while (CAAtomicTestAndSetBarrier(0, (void*)__lock)) + usleep(1000); // ??? +#endif +} + +inline void CASpinLockUnlock( volatile CASpinLock *__lock ) +{ +#if TARGET_OS_MAC + OSSpinLockUnlock(__lock); +#else + CAAtomicTestAndClearBarrier(0, (void*)__lock); +#endif +} + +inline bool CASpinLockTry( volatile CASpinLock *__lock ) +{ +#if TARGET_OS_MAC + return OSSpinLockTry(__lock); +#else + return (CAAtomicTestAndSetBarrier(0, (void*)__lock) == 0); +#endif +} + +#pragma clang diagnostic pop + +#endif // __CAAtomic_h__ diff --git a/app/PublicUtility/CAAutoDisposer.h b/app/PublicUtility/CAAutoDisposer.h new file mode 100644 index 0000000..2da2415 --- /dev/null +++ b/app/PublicUtility/CAAutoDisposer.h @@ -0,0 +1,508 @@ +/* + File: CAAutoDisposer.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAPtr_h__) +#define __CAPtr_h__ + +#include // for malloc +#include // for bad_alloc +#include // for memset + +inline void* CA_malloc(size_t size) +{ + void* p = malloc(size); + if (!p && size) throw std::bad_alloc(); + return p; +} + +inline void* CA_realloc(void* old, size_t size) +{ +#if TARGET_OS_WIN32 + void* p = realloc(old, size); +#else + void* p = reallocf(old, size); // reallocf ensures the old pointer is freed if memory is full (p is NULL). +#endif + if (!p && size) throw std::bad_alloc(); + return p; +} + +#ifndef UINTPTR_MAX +#if __LP64__ +#define UINTPTR_MAX 18446744073709551615ULL +#else +#define UINTPTR_MAX 4294967295U +#endif +#endif + +inline void* CA_calloc(size_t n, size_t size) +{ + // ensure that multiplication will not overflow + if (n && UINTPTR_MAX / n < size) throw std::bad_alloc(); + + size_t nsize = n*size; + void* p = malloc(nsize); + if (!p && nsize) throw std::bad_alloc(); + + memset(p, 0, nsize); + return p; +} + + +// helper class for automatic conversions +template +struct CAPtrRef +{ + T* ptr_; + + explicit CAPtrRef(T* ptr) : ptr_(ptr) {} +}; + +template +class CAAutoFree +{ +private: + T* ptr_; + +public: + + CAAutoFree() : ptr_(0) {} + + explicit CAAutoFree(T* ptr) : ptr_(ptr) {} + + template + CAAutoFree(CAAutoFree& that) : ptr_(that.release()) {} // take ownership + + // C++ std says: a template constructor is never a copy constructor + CAAutoFree(CAAutoFree& that) : ptr_(that.release()) {} // take ownership + + CAAutoFree(size_t n, bool clear = false) + // this becomes an ambiguous call if n == 0 + : ptr_(0) + { + size_t maxItems = ~size_t(0) / sizeof(T); + if (n > maxItems) + throw std::bad_alloc(); + + ptr_ = static_cast(clear ? CA_calloc(n, sizeof(T)) : CA_malloc(n * sizeof(T))); + } + + ~CAAutoFree() { free(); } + + void alloc(size_t numItems, bool clear = false) + { + size_t maxItems = ~size_t(0) / sizeof(T); + if (numItems > maxItems) throw std::bad_alloc(); + + free(); + ptr_ = static_cast(clear ? CA_calloc(numItems, sizeof(T)) : CA_malloc(numItems * sizeof(T))); + } + + void allocBytes(size_t numBytes, bool clear = false) + { + free(); + ptr_ = static_cast(clear ? CA_calloc(1, numBytes) : CA_malloc(numBytes)); + } + + void reallocBytes(size_t numBytes) + { + ptr_ = static_cast(CA_realloc(ptr_, numBytes)); + } + + void reallocItems(size_t numItems) + { + size_t maxItems = ~size_t(0) / sizeof(T); + if (numItems > maxItems) throw std::bad_alloc(); + + ptr_ = static_cast(CA_realloc(ptr_, numItems * sizeof(T))); + } + + template + CAAutoFree& operator=(CAAutoFree& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoFree& operator=(CAAutoFree& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoFree& operator=(T* ptr) + { + set(ptr); + return *this; + } + + template + CAAutoFree& operator=(U* ptr) + { + set(ptr); + return *this; + } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + + T* operator()() const { return ptr_; } + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + + bool operator==(CAAutoFree const& that) const { return ptr_ == that.ptr_; } + bool operator!=(CAAutoFree const& that) const { return ptr_ != that.ptr_; } + bool operator==(T* ptr) const { return ptr_ == ptr; } + bool operator!=(T* ptr) const { return ptr_ != ptr; } + + T* release() + { + // release ownership + T* result = ptr_; + ptr_ = 0; + return result; + } + + void set(T* ptr) + { + if (ptr != ptr_) + { + ::free(ptr_); + ptr_ = ptr; + } + } + + void free() + { + set(0); + } + + + // automatic conversions to allow assignment from results of functions. + // hard to explain. see auto_ptr implementation and/or Josuttis' STL book. + CAAutoFree(CAPtrRef ref) : ptr_(ref.ptr_) { } + + CAAutoFree& operator=(CAPtrRef ref) + { + set(ref.ptr_); + return *this; + } + + template + operator CAPtrRef() + { return CAPtrRef(release()); } + + template + operator CAAutoFree() + { return CAAutoFree(release()); } + +}; + + +template +class CAAutoDelete +{ +private: + T* ptr_; + +public: + CAAutoDelete() : ptr_(0) {} + + explicit CAAutoDelete(T* ptr) : ptr_(ptr) {} + + template + CAAutoDelete(CAAutoDelete& that) : ptr_(that.release()) {} // take ownership + + // C++ std says: a template constructor is never a copy constructor + CAAutoDelete(CAAutoDelete& that) : ptr_(that.release()) {} // take ownership + + ~CAAutoDelete() { free(); } + + template + CAAutoDelete& operator=(CAAutoDelete& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoDelete& operator=(CAAutoDelete& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoDelete& operator=(T* ptr) + { + set(ptr); + return *this; + } + + template + CAAutoDelete& operator=(U* ptr) + { + set(ptr); + return *this; + } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + + T* operator()() const { return ptr_; } + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + + bool operator==(CAAutoDelete const& that) const { return ptr_ == that.ptr_; } + bool operator!=(CAAutoDelete const& that) const { return ptr_ != that.ptr_; } + bool operator==(T* ptr) const { return ptr_ == ptr; } + bool operator!=(T* ptr) const { return ptr_ != ptr; } + + T* release() + { + // release ownership + T* result = ptr_; + ptr_ = 0; + return result; + } + + void set(T* ptr) + { + if (ptr != ptr_) + { + delete ptr_; + ptr_ = ptr; + } + } + + void free() + { + set(0); + } + + + // automatic conversions to allow assignment from results of functions. + // hard to explain. see auto_ptr implementation and/or Josuttis' STL book. + CAAutoDelete(CAPtrRef ref) : ptr_(ref.ptr_) { } + + CAAutoDelete& operator=(CAPtrRef ref) + { + set(ref.ptr_); + return *this; + } + + template + operator CAPtrRef() + { return CAPtrRef(release()); } + + template + operator CAAutoFree() + { return CAAutoFree(release()); } + +}; + + +template +class CAAutoArrayDelete +{ +private: + T* ptr_; + +public: + CAAutoArrayDelete() : ptr_(0) {} + + explicit CAAutoArrayDelete(T* ptr) : ptr_(ptr) {} + + template + CAAutoArrayDelete(CAAutoArrayDelete& that) : ptr_(that.release()) {} // take ownership + + // C++ std says: a template constructor is never a copy constructor + CAAutoArrayDelete(CAAutoArrayDelete& that) : ptr_(that.release()) {} // take ownership + + // this becomes an ambiguous call if n == 0 + CAAutoArrayDelete(size_t n) : ptr_(new T[n]) {} + + ~CAAutoArrayDelete() { free(); } + + void alloc(size_t numItems) + { + free(); + ptr_ = new T [numItems]; + } + + template + CAAutoArrayDelete& operator=(CAAutoArrayDelete& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoArrayDelete& operator=(CAAutoArrayDelete& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoArrayDelete& operator=(T* ptr) + { + set(ptr); + return *this; + } + + template + CAAutoArrayDelete& operator=(U* ptr) + { + set(ptr); + return *this; + } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + + T* operator()() const { return ptr_; } + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + + bool operator==(CAAutoArrayDelete const& that) const { return ptr_ == that.ptr_; } + bool operator!=(CAAutoArrayDelete const& that) const { return ptr_ != that.ptr_; } + bool operator==(T* ptr) const { return ptr_ == ptr; } + bool operator!=(T* ptr) const { return ptr_ != ptr; } + + T* release() + { + // release ownership + T* result = ptr_; + ptr_ = 0; + return result; + } + + void set(T* ptr) + { + if (ptr != ptr_) + { + delete [] ptr_; + ptr_ = ptr; + } + } + + void free() + { + set(0); + } + + + // automatic conversions to allow assignment from results of functions. + // hard to explain. see auto_ptr implementation and/or Josuttis' STL book. + CAAutoArrayDelete(CAPtrRef ref) : ptr_(ref.ptr_) { } + + CAAutoArrayDelete& operator=(CAPtrRef ref) + { + set(ref.ptr_); + return *this; + } + + template + operator CAPtrRef() + { return CAPtrRef(release()); } + + template + operator CAAutoArrayDelete() + { return CAAutoFree(release()); } + +}; + + + + + +// convenience function +template +void free(CAAutoFree& p) +{ + p.free(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if 0 +// example program showing ownership transfer + +CAAutoFree source() +{ + // source allocates and returns ownership to the caller. + const char* str = "this is a test"; + size_t size = strlen(str) + 1; + CAAutoFree captr(size, false); + strlcpy(captr(), str, size); + printf("source %08X %08X '%s'\n", &captr, captr(), captr()); + return captr; +} + +void user(CAAutoFree const& captr) +{ + // passed by const reference. user can access the pointer but does not take ownership. + printf("user: %08X %08X '%s'\n", &captr, captr(), captr()); +} + +void sink(CAAutoFree captr) +{ + // passed by value. sink takes ownership and frees the pointer on return. + printf("sink: %08X %08X '%s'\n", &captr, captr(), captr()); +} + + +int main (int argc, char * const argv[]) +{ + + CAAutoFree captr(source()); + printf("main captr A %08X %08X\n", &captr, captr()); + user(captr); + sink(captr); + printf("main captr B %08X %08X\n", &captr, captr()); + return 0; +} +#endif + +#endif diff --git a/app/PublicUtility/CABitOperations.h b/app/PublicUtility/CABitOperations.h new file mode 100644 index 0000000..21cb516 --- /dev/null +++ b/app/PublicUtility/CABitOperations.h @@ -0,0 +1,206 @@ +/* + File: CABitOperations.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef _CABitOperations_h_ +#define _CABitOperations_h_ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + //#include + #include +#else +// #include + #include "CFBase.h" +#endif +#include + +// return whether a number is a power of two +inline UInt32 IsPowerOfTwo(UInt32 x) +{ + return (x & (x-1)) == 0; +} + +// count the leading zeros in a word +// Metrowerks Codewarrior. powerpc native count leading zeros instruction: +// I think it's safe to remove this ... +//#define CountLeadingZeroes(x) ((int)__cntlzw((unsigned int)x)) + +inline UInt32 CountLeadingZeroes(UInt32 arg) +{ +// GNUC / LLVM have a builtin +#if defined(__GNUC__) || defined(__llvm___) +#if (TARGET_CPU_X86 || TARGET_CPU_X86_64) + if (arg == 0) return 32; +#endif // TARGET_CPU_X86 || TARGET_CPU_X86_64 + return __builtin_clz(arg); +#elif TARGET_OS_WIN32 + UInt32 tmp; + __asm{ + bsr eax, arg + mov ecx, 63 + cmovz eax, ecx + xor eax, 31 + mov tmp, eax // this moves the result in tmp to return. + } + return tmp; +#else +#error "Unsupported architecture" +#endif // defined(__GNUC__) +} +// Alias (with different spelling) +#define CountLeadingZeros CountLeadingZeroes + +inline UInt32 CountLeadingZeroesLong(UInt64 arg) +{ +// GNUC / LLVM have a builtin +#if defined(__GNUC__) || defined(__llvm___) +#if (TARGET_CPU_X86 || TARGET_CPU_X86_64) + if (arg == 0) return 64; +#endif // TARGET_CPU_X86 || TARGET_CPU_X86_64 + return __builtin_clzll(arg); +#elif TARGET_OS_WIN32 + UInt32 x = CountLeadingZeroes((UInt32)(arg >> 32)); + if(x < 32) + return x; + else + return 32+CountLeadingZeroes((UInt32)arg); +#else +#error "Unsupported architecture" +#endif // defined(__GNUC__) +} +#define CountLeadingZerosLong CountLeadingZeroesLong + +// count trailing zeroes +inline UInt32 CountTrailingZeroes(UInt32 x) +{ + return 32 - CountLeadingZeroes(~x & (x-1)); +} + +// count leading ones +inline UInt32 CountLeadingOnes(UInt32 x) +{ + return CountLeadingZeroes(~x); +} + +// count trailing ones +inline UInt32 CountTrailingOnes(UInt32 x) +{ + return 32 - CountLeadingZeroes(x & (~x-1)); +} + +// number of bits required to represent x. +inline UInt32 NumBits(UInt32 x) +{ + return 32 - CountLeadingZeroes(x); +} + +// base 2 log of next power of two greater or equal to x +inline UInt32 Log2Ceil(UInt32 x) +{ + return 32 - CountLeadingZeroes(x - 1); +} + +// base 2 log of next power of two less or equal to x +inline UInt32 Log2Floor(UInt32 x) +{ + return 32 - CountLeadingZeroes(x) - 1; +} + +// next power of two greater or equal to x +inline UInt32 NextPowerOfTwo(UInt32 x) +{ + return 1 << Log2Ceil(x); +} + +// counting the one bits in a word +inline UInt32 CountOnes(UInt32 x) +{ + // secret magic algorithm for counting bits in a word. + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; +} + +// counting the zero bits in a word +inline UInt32 CountZeroes(UInt32 x) +{ + return CountOnes(~x); +} + +// return the bit position (0..31) of the least significant bit +inline UInt32 LSBitPos(UInt32 x) +{ + return CountTrailingZeroes(x & -(SInt32)x); +} + +// isolate the least significant bit +inline UInt32 LSBit(UInt32 x) +{ + return x & -(SInt32)x; +} + +// return the bit position (0..31) of the most significant bit +inline UInt32 MSBitPos(UInt32 x) +{ + return 31 - CountLeadingZeroes(x); +} + +// isolate the most significant bit +inline UInt32 MSBit(UInt32 x) +{ + return 1 << MSBitPos(x); +} + +// Division optimized for power of 2 denominators +inline UInt32 DivInt(UInt32 numerator, UInt32 denominator) +{ + if(IsPowerOfTwo(denominator)) + return numerator >> (31 - CountLeadingZeroes(denominator)); + else + return numerator/denominator; +} + +#endif + diff --git a/app/PublicUtility/CACFArray.cpp b/app/PublicUtility/CACFArray.cpp new file mode 100644 index 0000000..e7c057d --- /dev/null +++ b/app/PublicUtility/CACFArray.cpp @@ -0,0 +1,821 @@ +/* + File: CACFArray.cpp + Abstract: CACFArray.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CACFArray.h" + +// PublicUtility Includes +#include "CACFDictionary.h" +#include "CACFNumber.h" +#include "CACFString.h" + +//============================================================================= +// CACFArray +//============================================================================= + +bool CACFArray::HasItem(const void* inItem) const +{ + bool theAnswer = false; + if(mCFArray != NULL) + { + CFRange theRange = { 0, CFArrayGetCount(mCFArray)}; + theAnswer = CFArrayContainsValue(mCFArray, theRange, inItem); + } + return theAnswer; +} + +bool CACFArray::GetIndexOfItem(const void* inItem, UInt32& outIndex) const +{ + bool theAnswer = false; + outIndex = 0; + if(mCFArray != NULL) + { + CFRange theRange = { 0, CFArrayGetCount(mCFArray)}; + CFIndex theIndex = CFArrayGetFirstIndexOfValue(mCFArray, theRange, inItem); + if(theIndex != -1) + { + theAnswer = true; + outIndex = ToUInt32(theIndex); + } + } + return theAnswer; +} + +bool CACFArray::GetBool(UInt32 inIndex, bool& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inIndex, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFBooleanGetTypeID())) + { + outValue = CFBooleanGetValue(static_cast(theValue)); + theAnswer = true; + } + else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + SInt32 theNumericValue = 0; + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &theNumericValue); + outValue = theNumericValue != 0; + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetSInt32(UInt32 inIndex, SInt32& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberSInt32Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetUInt32(UInt32 inIndex, UInt32& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberSInt32Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetSInt64(UInt32 inIndex, SInt64& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberSInt64Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetUInt64(UInt32 inIndex, UInt64& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberSInt64Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetFloat32(UInt32 inIndex, Float32& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberFloat32Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetFloat64(UInt32 inIndex, Float64& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberFloat64Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::Get4CC(UInt32 inIndex, UInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inIndex, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + else if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + CFStringRef theString = static_cast(theValue); + if(CFStringGetLength(theString) == 4) + { + char theCString[5]; + CFStringGetCString(theString, theCString, 5, kCFStringEncodingASCII); + outValue = CFSwapInt32BigToHost(*reinterpret_cast(theCString)); + } + } + } + + return theAnswer; +} + +bool CACFArray::GetString(UInt32 inIndex, CFStringRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFStringGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetArray(UInt32 inIndex, CFArrayRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFArrayGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetDictionary(UInt32 inIndex, CFDictionaryRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFDictionaryGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetData(UInt32 inIndex, CFDataRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFDataGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetUUID(UInt32 inIndex, CFUUIDRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFUUIDGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetCFType(UInt32 inIndex, CFTypeRef& outItem) const +{ + bool theAnswer = false; + + if((mCFArray != NULL) && (inIndex < GetNumberItems())) + { + outItem = CFArrayGetValueAtIndex(mCFArray, static_cast(inIndex)); + theAnswer = outItem != NULL; + } + + return theAnswer; +} + +void CACFArray::GetCACFString(UInt32 inIndex, CACFString& outItem) const +{ + outItem = static_cast(NULL); + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFStringGetTypeID())) + { + outItem = static_cast(theItem); + } + } +} + +void CACFArray::GetCACFArray(UInt32 inIndex, CACFArray& outItem) const +{ + outItem = static_cast(NULL); + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFArrayGetTypeID())) + { + outItem = static_cast(theItem); + } + } +} + +void CACFArray::GetCACFDictionary(UInt32 inIndex, CACFDictionary& outItem) const +{ + outItem = static_cast(NULL); + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFDictionaryGetTypeID())) + { + outItem = static_cast(theItem); + } + } +} + +bool CACFArray::AppendBool(bool inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFBoolean theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFBoolean()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendSInt32(SInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendUInt32(UInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendSInt64(SInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendUInt64(UInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendFloat32(Float32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendFloat64(Float64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendString(const CFStringRef inItem) +{ + return AppendCFType(inItem); +} + +bool CACFArray::AppendArray(const CFArrayRef inItem) +{ + return AppendCFType(inItem); +} + +bool CACFArray::AppendDictionary(const CFDictionaryRef inItem) +{ + return AppendCFType(inItem); +} + +bool CACFArray::AppendData(const CFDataRef inItem) +{ + return AppendCFType(inItem); +} + +bool CACFArray::AppendCFType(const CFTypeRef inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CFArrayAppendValue(mCFArray, inItem); + theAnswer = true; + } + + return theAnswer; +} + +bool CACFArray::InsertBool(UInt32 inIndex, bool inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFBoolean theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFBoolean()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertSInt32(UInt32 inIndex, SInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertUInt32(UInt32 inIndex, UInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertSInt64(UInt32 inIndex, SInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertUInt64(UInt32 inIndex, UInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertFloat32(UInt32 inIndex, Float32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertFloat64(UInt32 inIndex, Float64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertString(UInt32 inIndex, const CFStringRef inItem) +{ + return InsertCFType(inIndex, inItem); +} + +bool CACFArray::InsertArray(UInt32 inIndex, const CFArrayRef inItem) +{ + return InsertCFType(inIndex, inItem); +} + +bool CACFArray::InsertDictionary(UInt32 inIndex, const CFDictionaryRef inItem) +{ + return InsertCFType(inIndex, inItem); +} + +bool CACFArray::InsertData(UInt32 inIndex, const CFDataRef inItem) +{ + return InsertCFType(inIndex, inItem); +} + +bool CACFArray::InsertCFType(UInt32 inIndex, const CFTypeRef inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + if(inIndex < GetNumberItems()) + { + CFArrayInsertValueAtIndex(mCFArray, static_cast(inIndex), inItem); + } + else + { + CFArrayAppendValue(mCFArray, inItem); + } + theAnswer = true; + } + + return theAnswer; +} + +bool CACFArray::SetBool(UInt32 inIndex, bool inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFBoolean theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFBoolean()); + } + } + + return theAnswer; +} + +bool CACFArray::SetSInt32(UInt32 inIndex, SInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetUInt32(UInt32 inIndex, UInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetSInt64(UInt32 inIndex, SInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetUInt64(UInt32 inIndex, UInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetFloat32(UInt32 inIndex, Float32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetFloat64(UInt32 inIndex, Float64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetString(UInt32 inIndex, const CFStringRef inItem) +{ + return SetCFType(inIndex, inItem); +} + +bool CACFArray::SetArray(UInt32 inIndex, const CFArrayRef inItem) +{ + return SetCFType(inIndex, inItem); +} + +bool CACFArray::SetDictionary(UInt32 inIndex, const CFDictionaryRef inItem) +{ + return SetCFType(inIndex, inItem); +} + +bool CACFArray::SetData(UInt32 inIndex, const CFDataRef inItem) +{ + return SetCFType(inIndex, inItem); +} + +bool CACFArray::SetCFType(UInt32 inIndex, const CFTypeRef inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CFArraySetValueAtIndex(mCFArray, static_cast(inIndex), inItem); + theAnswer = true; + } + + return theAnswer; +} diff --git a/app/PublicUtility/CACFArray.h b/app/PublicUtility/CACFArray.h new file mode 100644 index 0000000..89c8c55 --- /dev/null +++ b/app/PublicUtility/CACFArray.h @@ -0,0 +1,195 @@ +/* + File: CACFArray.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CACFArray_h__) +#define __CACFArray_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +#include "CADebugMacros.h" + +//============================================================================= +// Types +//============================================================================= + +class CACFDictionary; +class CACFString; + +//============================================================================= +// CACFArray +//============================================================================= + +class CACFArray +{ + +// Construction/Destruction +public: + CACFArray() : mCFArray(CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)), mRelease(true), mMutable(true) {} + explicit CACFArray(bool inRelease) : mCFArray(CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)), mRelease(inRelease), mMutable(true) {} + CACFArray(UInt32 inMaxNumberItems, bool inRelease) : mCFArray(CFArrayCreateMutable(NULL, static_cast(inMaxNumberItems), &kCFTypeArrayCallBacks)), mRelease(inRelease), mMutable(true) {} + CACFArray(CFArrayRef inCFArray, bool inRelease) : mCFArray(const_cast(inCFArray)), mRelease(inRelease), mMutable(false) {} + CACFArray(CFMutableArrayRef inCFArray, bool inRelease) : mCFArray(inCFArray), mRelease(inRelease), mMutable(true) {} + CACFArray(const CACFArray& inArray) : mCFArray(inArray.mCFArray), mRelease(inArray.mRelease), mMutable(inArray.mMutable) { Retain(); } + CACFArray& operator=(const CACFArray& inArray) { Release(); mCFArray = inArray.mCFArray; mRelease = inArray.mRelease; mMutable = inArray.mMutable; Retain(); return *this; } + CACFArray& operator=(CFArrayRef inCFArray) { Release(); mCFArray = const_cast(inCFArray); mMutable = false; Retain(); return *this; } + CACFArray& operator=(CFMutableArrayRef inCFArray) { Release(); mCFArray = inCFArray; mMutable = true; Retain(); return *this; } + ~CACFArray() { Release(); } + +private: + void Retain() { if(mRelease && (mCFArray != NULL)) { CFRetain(mCFArray); } } + void Release() { if(mRelease && (mCFArray != NULL)) { CFRelease(mCFArray); } } + +// Attributes +public: + bool IsValid() const { return mCFArray != NULL; } + bool IsMutable() const { return mMutable; } + bool CanModify() const { return mMutable && (mCFArray != NULL); } + + bool WillRelease() const { return mRelease; } + void ShouldRelease(bool inRelease) { mRelease = inRelease; } + + CFTypeID GetTypeID() const { return CFGetTypeID(mCFArray); } + + CFArrayRef GetCFArray() const { return mCFArray; } + CFArrayRef CopyCFArray() const { if(mCFArray != NULL) { CFRetain(mCFArray); } return mCFArray; } + + CFMutableArrayRef GetCFMutableArray() const { return mCFArray; } + CFMutableArrayRef CopyCFMutableArray() const { if(mCFArray != NULL) { CFRetain(mCFArray); } return mCFArray; } + CFPropertyListRef AsPropertyList() const { return mCFArray; } + + void SetCFMutableArrayFromCopy(CFArrayRef inArray, bool inRelease = true) { Release(); mCFArray = CFArrayCreateMutableCopy(NULL, 0, inArray); mMutable = true; mRelease = inRelease; } + +// Item Operations +public: + UInt32 GetNumberItems() const { UInt32 theAnswer = 0; if(mCFArray != NULL) { theAnswer = ToUInt32(CFArrayGetCount(mCFArray)); } return theAnswer; } + bool HasItem(const void* inItem) const; + void RemoveItem(const void* inItem) { UInt32 theIndex; if(CanModify() && GetIndexOfItem(inItem, theIndex)) { RemoveItemAtIndex(theIndex); } } + bool GetIndexOfItem(const void* inItem, UInt32& outIndex) const; + void RemoveItemAtIndex(UInt32 inIndex) { if(CanModify()) { CFArrayRemoveValueAtIndex(mCFArray, static_cast(inIndex)); } } + void Clear() { if(CanModify()) { CFArrayRemoveAllValues(mCFArray); } } + void Sort(CFComparatorFunction inCompareFunction) { if(CanModify()) { CFRange theRange = { 0, CFArrayGetCount(mCFArray) }; CFArraySortValues(mCFArray, theRange, inCompareFunction, NULL); } } + void SortNumbers() { Sort((CFComparatorFunction)CFNumberCompare); } + void SortStrings() { Sort((CFComparatorFunction)CFStringCompare); } + + bool GetBool(UInt32 inIndex, bool& outValue) const; + bool GetSInt32(UInt32 inIndex, SInt32& outItem) const; + bool GetUInt32(UInt32 inIndex, UInt32& outItem) const; + bool GetSInt64(UInt32 inIndex, SInt64& outItem) const; + bool GetUInt64(UInt32 inIndex, UInt64& outItem) const; + bool GetFloat32(UInt32 inIndex, Float32& outItem) const; + bool GetFloat64(UInt32 inIndex, Float64& outItem) const; + bool Get4CC(UInt32 inIndex, UInt32& outValue) const; + bool GetString(UInt32 inIndex, CFStringRef& outItem) const; + bool GetArray(UInt32 inIndex, CFArrayRef& outItem) const; + bool GetDictionary(UInt32 inIndex, CFDictionaryRef& outItem) const; + bool GetData(UInt32 inIndex, CFDataRef& outItem) const; + bool GetUUID(UInt32 inIndex, CFUUIDRef& outItem) const; + bool GetCFType(UInt32 inIndex, CFTypeRef& outItem) const; + + void GetCACFString(UInt32 inIndex, CACFString& outItem) const; + void GetCACFArray(UInt32 inIndex, CACFArray& outItem) const; + void GetCACFDictionary(UInt32 inIndex, CACFDictionary& outItem) const; + + bool AppendBool(bool inItem); + bool AppendSInt32(SInt32 inItem); + bool AppendUInt32(UInt32 inItem); + bool AppendSInt64(SInt64 inItem); + bool AppendUInt64(UInt64 inItem); + bool AppendFloat32(Float32 inItem); + bool AppendFloat64(Float64 inItem); + bool AppendString(const CFStringRef inItem); + bool AppendArray(const CFArrayRef inItem); + bool AppendDictionary(const CFDictionaryRef inItem); + bool AppendData(const CFDataRef inItem); + bool AppendCFType(const CFTypeRef inItem); + + bool InsertBool(UInt32 inIndex, bool inItem); + bool InsertSInt32(UInt32 inIndex, SInt32 inItem); + bool InsertUInt32(UInt32 inIndex, UInt32 inItem); + bool InsertSInt64(UInt32 inIndex, SInt64 inItem); + bool InsertUInt64(UInt32 inIndex, UInt64 inItem); + bool InsertFloat32(UInt32 inIndex, Float32 inItem); + bool InsertFloat64(UInt32 inIndex, Float64 inItem); + bool InsertString(UInt32 inIndex, const CFStringRef inItem); + bool InsertArray(UInt32 inIndex, const CFArrayRef inItem); + bool InsertDictionary(UInt32 inIndex, const CFDictionaryRef inItem); + bool InsertData(UInt32 inIndex, const CFDataRef inItem); + bool InsertCFType(UInt32 inIndex, const CFTypeRef inItem); + + bool SetBool(UInt32 inIndex, bool inItem); + bool SetSInt32(UInt32 inIndex, SInt32 inItem); + bool SetUInt32(UInt32 inIndex, UInt32 inItem); + bool SetSInt64(UInt32 inIndex, SInt64 inItem); + bool SetUInt64(UInt32 inIndex, UInt64 inItem); + bool SetFloat32(UInt32 inIndex, Float32 inItem); + bool SetFloat64(UInt32 inIndex, Float64 inItem); + bool SetString(UInt32 inIndex, const CFStringRef inItem); + bool SetArray(UInt32 inIndex, const CFArrayRef inItem); + bool SetDictionary(UInt32 inIndex, const CFDictionaryRef inItem); + bool SetData(UInt32 inIndex, const CFDataRef inItem); + bool SetCFType(UInt32 inIndex, const CFTypeRef inItem); + +// Implementation +private: + CFMutableArrayRef mCFArray; + bool mRelease; + bool mMutable; + + CACFArray(const void*); // prevent accidental instantiation with a pointer via bool constructor +}; + +#endif diff --git a/app/PublicUtility/CACFDictionary.cpp b/app/PublicUtility/CACFDictionary.cpp new file mode 100644 index 0000000..fbac774 --- /dev/null +++ b/app/PublicUtility/CACFDictionary.cpp @@ -0,0 +1,581 @@ +/* + File: CACFDictionary.cpp + Abstract: CACFDictionary.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CACFDictionary.h" + +// PublicUtility Includes +#include "CACFArray.h" +#include "CACFNumber.h" +#include "CACFString.h" + +//============================================================================= +// CACFDictionary +//============================================================================= + +bool CACFDictionary::HasKey(const CFStringRef inKey) const +{ + return CFDictionaryContainsKey(mCFDictionary, inKey) != 0; +} + +UInt32 CACFDictionary::Size () const +{ + return mCFDictionary ? ToUInt32(CFDictionaryGetCount(mCFDictionary)) : 0; +} + +void CACFDictionary::GetKeys (const void **keys) const +{ + CFDictionaryGetKeysAndValues(mCFDictionary, keys, NULL); +} + +void CACFDictionary::GetKeysAndValues (const void **keys, const void **values) const +{ + CFDictionaryGetKeysAndValues(mCFDictionary, keys, values); +} + +bool CACFDictionary::GetBool(const CFStringRef inKey, bool& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFBooleanGetTypeID())) + { + outValue = CFBooleanGetValue(static_cast(theValue)); + theAnswer = true; + } + else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + SInt32 theNumericValue = 0; + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &theNumericValue); + outValue = theNumericValue != 0; + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetSInt32(const CFStringRef inKey, SInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetUInt32(const CFStringRef inKey, UInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetSInt64(const CFStringRef inKey, SInt64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetUInt64(const CFStringRef inKey, UInt64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFloat32FromString(const CFStringRef inKey, Float32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + outValue = static_cast(CFStringGetDoubleValue(static_cast(theValue))); + } + } + + return theAnswer; +} + +bool CACFDictionary::GetUInt32FromString(const CFStringRef inKey, UInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + outValue = CFStringGetIntValue(static_cast(theValue)); + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFloat32(const CFStringRef inKey, Float32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberFloat32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFloat64(const CFStringRef inKey, Float64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberFloat64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFixed32(const CFStringRef inKey, Float32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + SInt32 theFixed32 = 0; + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &theFixed32); + + // this is a 16.16 value so convert it to a float + Float32 theSign = theFixed32 < 0 ? -1.0f : 1.0f; + theFixed32 *= (SInt32)theSign; + Float32 theWholePart = (theFixed32 & 0x7FFF0000) >> 16; + Float32 theFractPart = theFixed32 & 0x0000FFFF; + theFractPart /= 65536.0f; + outValue = theSign * (theWholePart + theFractPart); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFixed64(const CFStringRef inKey, Float64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + SInt64 theFixed64 = 0; + CFNumberGetValue(static_cast(theValue), kCFNumberSInt64Type, &theFixed64); + outValue = static_cast(theFixed64 >> 32); + outValue += static_cast(theFixed64 & 0x00000000FFFFFFFFLL) / static_cast(0x0000000100000000LL); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::Get4CC(const CFStringRef inKey, UInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + else if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + CFStringRef theString = static_cast(theValue); + if(CFStringGetLength(theString) == 4) + { + char theCString[5]; + CFStringGetCString(theString, theCString, 5, kCFStringEncodingASCII); + outValue = CFSwapInt32BigToHost(*reinterpret_cast(theCString)); + } + } + } + + return theAnswer; +} + +bool CACFDictionary::GetString(const CFStringRef inKey, CFStringRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetArray(const CFStringRef inKey, CFArrayRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFArrayGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetDictionary(const CFStringRef inKey, CFDictionaryRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDictionaryGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetData(const CFStringRef inKey, CFDataRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDataGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetCFType(const CFStringRef inKey, CFTypeRef& outValue) const +{ + bool theAnswer = false; + + if(mCFDictionary != NULL) + { + outValue = CFDictionaryGetValue(mCFDictionary, inKey); + theAnswer = (outValue != NULL); + } + + return theAnswer; +} + +bool CACFDictionary::GetURL(const CFStringRef inKey, CFURLRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFURLGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetCFTypeWithCStringKey(const char* inKey, CFTypeRef& outValue) const +{ + bool theAnswer = false; + + if(mCFDictionary != NULL) + { + CACFString theKey(inKey); + if(theKey.IsValid()) + { + theAnswer = GetCFType(theKey.GetCFString(), outValue); + } + } + + return theAnswer; +} + +void CACFDictionary::GetCACFString(const CFStringRef inKey, CACFString& outValue) const +{ + outValue = static_cast(NULL); + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + outValue = static_cast(theValue); + } + } +} + +void CACFDictionary::GetCACFArray(const CFStringRef inKey, CACFArray& outValue) const +{ + outValue = static_cast(NULL); + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFArrayGetTypeID())) + { + outValue = static_cast(theValue); + } + } +} + +void CACFDictionary::GetCACFDictionary(const CFStringRef inKey, CACFDictionary& outValue) const +{ + outValue = static_cast(NULL); + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDictionaryGetTypeID())) + { + outValue = static_cast(theValue); + } + } +} + +bool CACFDictionary::AddBool(const CFStringRef inKey, bool inValue) +{ + CACFBoolean theValue(inValue); + return AddCFType(inKey, theValue.GetCFBoolean()); +} + +bool CACFDictionary::AddSInt32(const CFStringRef inKey, SInt32 inValue) +{ + CACFNumber theValue(inValue); + return AddCFType(inKey, theValue.GetCFNumber()); +} + +bool CACFDictionary::AddUInt32(const CFStringRef inKey, UInt32 inValue) +{ + CACFNumber theValue(inValue); + return AddCFType(inKey, theValue.GetCFNumber()); +} + +bool CACFDictionary::AddSInt64(const CFStringRef inKey, SInt64 inValue) +{ + CACFNumber theValue(inValue); + return AddCFType(inKey, theValue.GetCFNumber()); +} + +bool CACFDictionary::AddUInt64(const CFStringRef inKey, UInt64 inValue) +{ + CACFNumber theValue(inValue); + return AddCFType(inKey, theValue.GetCFNumber()); +} + +bool CACFDictionary::AddFloat32(const CFStringRef inKey, Float32 inValue) +{ + CACFNumber theValue(inValue); + return AddCFType(inKey, theValue.GetCFNumber()); +} + +bool CACFDictionary::AddFloat64(const CFStringRef inKey, Float64 inValue) +{ + CACFNumber theValue(inValue); + return AddCFType(inKey, theValue.GetCFNumber()); +} + +bool CACFDictionary::AddNumber(const CFStringRef inKey, const CFNumberRef inValue) +{ + return AddCFType(inKey, inValue); +} + +bool CACFDictionary::AddString(const CFStringRef inKey, const CFStringRef inValue) +{ + return AddCFType(inKey, inValue); +} + +bool CACFDictionary::AddArray(const CFStringRef inKey, const CFArrayRef inValue) +{ + return AddCFType(inKey, inValue); +} + +bool CACFDictionary::AddDictionary(const CFStringRef inKey, const CFDictionaryRef inValue) +{ + return AddCFType(inKey, inValue); +} + +bool CACFDictionary::AddData(const CFStringRef inKey, const CFDataRef inValue) +{ + return AddCFType(inKey, inValue); +} + +bool CACFDictionary::AddURL(const CFStringRef inKey, const CFURLRef inValue) +{ + return AddCFType (inKey, inValue); +} + +bool CACFDictionary::AddCFTypeWithCStringKey(const char* inKey, const CFTypeRef inValue) +{ + bool theAnswer = false; + + if (inKey) + { + CACFString theKey(inKey); + if(theKey.IsValid()) + { + theAnswer = AddCFType(theKey.GetCFString(), inValue); + } + } + + return theAnswer; +} + +bool CACFDictionary::AddCString(const CFStringRef inKey, const char* inValue) +{ + bool theAnswer = false; + + if (inValue) + { + CACFString theValue(inValue); + if(theValue.IsValid()) + { + theAnswer = AddCFType(inKey, theValue.GetCFString()); + } + } + return theAnswer; +} + +bool CACFDictionary::AddCFType(const CFStringRef inKey, const CFTypeRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL) && inValue) + { + CFDictionarySetValue(mCFDictionary, inKey, inValue); + theAnswer = true; + } + + return theAnswer; +} diff --git a/app/PublicUtility/CACFDictionary.h b/app/PublicUtility/CACFDictionary.h new file mode 100644 index 0000000..c389e50 --- /dev/null +++ b/app/PublicUtility/CACFDictionary.h @@ -0,0 +1,176 @@ +/* + File: CACFDictionary.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CACFDictionary_h__) +#define __CACFDictionary_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +//============================================================================= +// Types +//============================================================================= + +class CACFArray; +class CACFString; + +//============================================================================= +// CACFDictionary +//============================================================================= + +class CACFDictionary +{ + +// Construction/Destruction +public: + CACFDictionary() : mCFDictionary(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)), mRelease(true), mMutable(true) {} + explicit CACFDictionary(bool inRelease) : mCFDictionary(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)), mRelease(inRelease), mMutable(true) {} + CACFDictionary(CFDictionaryRef inCFDictionary, bool inRelease) : mCFDictionary(const_cast(inCFDictionary)), mRelease(inRelease), mMutable(false) {} + CACFDictionary(CFMutableDictionaryRef inCFDictionary, bool inRelease) : mCFDictionary(inCFDictionary), mRelease(inRelease), mMutable(true) {} + CACFDictionary(const CACFDictionary& inDictionary) : mCFDictionary(inDictionary.mCFDictionary), mRelease(inDictionary.mRelease), mMutable(inDictionary.mMutable) { Retain(); } + CACFDictionary& operator=(const CACFDictionary& inDictionary) { Release(); mCFDictionary = inDictionary.mCFDictionary; mRelease = inDictionary.mRelease; mMutable = inDictionary.mMutable; Retain(); return *this; } + CACFDictionary& operator=(CFDictionaryRef inDictionary) { Release(); mCFDictionary = const_cast(inDictionary); mMutable = false; Retain(); return *this; } + CACFDictionary& operator=(CFMutableDictionaryRef inDictionary) { Release(); mCFDictionary = inDictionary; mMutable = true; Retain(); return *this; } + ~CACFDictionary() { Release(); } + +private: + void Retain() { if(mRelease && (mCFDictionary != NULL)) { CFRetain(mCFDictionary); } } + void Release() { if(mRelease && (mCFDictionary != NULL)) { CFRelease(mCFDictionary); } } + +// Attributes +public: + bool IsValid() const { return mCFDictionary != NULL; } + bool IsMutable() const { return mMutable;} + bool CanModify() const { return mMutable && (mCFDictionary != NULL); } + + bool WillRelease() const { return mRelease; } + void ShouldRelease(bool inRelease) { mRelease = inRelease; } + + CFDictionaryRef GetDict() const { return mCFDictionary; } + CFDictionaryRef GetCFDictionary() const { return mCFDictionary; } + CFDictionaryRef CopyCFDictionary() const { if(mCFDictionary != NULL) { CFRetain(mCFDictionary); } return mCFDictionary; } + + CFMutableDictionaryRef GetMutableDict() { return mCFDictionary; } + CFMutableDictionaryRef GetCFMutableDictionary() const { return mCFDictionary; } + CFMutableDictionaryRef CopyCFMutableDictionary() const { if(mCFDictionary != NULL) { CFRetain(mCFDictionary); } return mCFDictionary; } + void SetCFMutableDictionaryFromCopy(CFDictionaryRef inDictionary, bool inRelease = true) { Release(); mCFDictionary = CFDictionaryCreateMutableCopy(NULL, 0, inDictionary); mMutable = true; mRelease = inRelease; } + void SetCFMutableDictionaryToEmpty(bool inRelease = true) { Release(); mCFDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); mMutable = true; mRelease = inRelease; } + + CFPropertyListRef AsPropertyList() const { return mCFDictionary; } + OSStatus GetDictIfMutable(CFMutableDictionaryRef& outDict) const { OSStatus theAnswer = -1; if(mMutable) { outDict = mCFDictionary; theAnswer = 0; } return theAnswer; } + +// Item Operations +public: + bool HasKey(const CFStringRef inKey) const; + UInt32 Size() const; + void GetKeys(const void** keys) const; + void GetKeysAndValues (const void **keys, const void **values) const; + + bool GetBool(const CFStringRef inKey, bool& outValue) const; + bool GetSInt32(const CFStringRef inKey, SInt32& outValue) const; + bool GetUInt32(const CFStringRef inKey, UInt32& outValue) const; + bool GetUInt32FromString(const CFStringRef inKey, UInt32& outValue) const; + bool GetSInt64(const CFStringRef inKey, SInt64& outValue) const; + bool GetUInt64(const CFStringRef inKey, UInt64& outValue) const; + bool GetFloat32(const CFStringRef inKey, Float32& outValue) const; + bool GetFloat32FromString(const CFStringRef inKey, Float32& outValue) const; + bool GetFloat64(const CFStringRef inKey, Float64& outValue) const; + bool GetFixed32(const CFStringRef inKey, Float32& outValue) const; + bool GetFixed64(const CFStringRef inKey, Float64& outValue) const; + bool Get4CC(const CFStringRef inKey, UInt32& outValue) const; + bool GetString(const CFStringRef inKey, CFStringRef& outValue) const; + bool GetArray(const CFStringRef inKey, CFArrayRef& outValue) const; + bool GetDictionary(const CFStringRef inKey, CFDictionaryRef& outValue) const; + bool GetData(const CFStringRef inKey, CFDataRef& outValue) const; + bool GetCFType(const CFStringRef inKey, CFTypeRef& outValue) const; + bool GetURL(const CFStringRef inKey, CFURLRef& outValue) const; + bool GetCFTypeWithCStringKey(const char* inKey, CFTypeRef& outValue) const; + + void GetCACFString(const CFStringRef inKey, CACFString& outItem) const; + void GetCACFArray(const CFStringRef inKey, CACFArray& outItem) const; + void GetCACFDictionary(const CFStringRef inKey, CACFDictionary& outItem) const; + + bool AddBool(const CFStringRef inKey, bool inValue); + bool AddSInt32(const CFStringRef inKey, SInt32 inValue); + bool AddUInt32(const CFStringRef inKey, UInt32 inValue); + bool AddSInt64(const CFStringRef inKey, SInt64 inValue); + bool AddUInt64(const CFStringRef inKey, UInt64 inValue); + bool AddFloat32(const CFStringRef inKey, Float32 inValue); + bool AddFloat64(const CFStringRef inKey, Float64 inValue); + bool AddNumber(const CFStringRef inKey, const CFNumberRef inValue); + bool AddString(const CFStringRef inKey, const CFStringRef inValue); + bool AddArray(const CFStringRef inKey, const CFArrayRef inValue); + bool AddDictionary(const CFStringRef inKey, const CFDictionaryRef inValue); + bool AddData(const CFStringRef inKey, const CFDataRef inValue); + bool AddCFType(const CFStringRef inKey, const CFTypeRef inValue); + bool AddURL(const CFStringRef inKey, const CFURLRef inValue); + + bool AddCFTypeWithCStringKey(const char* inKey, const CFTypeRef inValue); + bool AddCString(const CFStringRef inKey, const char* inValue); + + void RemoveKey(const CFStringRef inKey) { if(CanModify()) { CFDictionaryRemoveValue(mCFDictionary, inKey); } } + void Clear() { if(CanModify()) { CFDictionaryRemoveAllValues(mCFDictionary); } } + + void Show() { CFShow(mCFDictionary); } + +// Implementation +private: + CFMutableDictionaryRef mCFDictionary; + bool mRelease; + bool mMutable; + + CACFDictionary(const void*); // prevent accidental instantiation with a pointer via bool constructor +}; + +#endif //__CACFDictionary_h__ diff --git a/app/PublicUtility/CACFNumber.cpp b/app/PublicUtility/CACFNumber.cpp new file mode 100644 index 0000000..36d1c2e --- /dev/null +++ b/app/PublicUtility/CACFNumber.cpp @@ -0,0 +1,83 @@ +/* + File: CACFNumber.cpp + Abstract: CACFNumber.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CACFNumber.h" + +//============================================================================= +// CACFNumber +//============================================================================= + +Float32 CACFNumber::GetFixed32() const +{ + SInt32 theFixedValue = GetSInt32(); + + // this is a 16.16 value so convert it to a float + Float32 theSign = theFixedValue < 0 ? -1.0f : 1.0f; + theFixedValue *= (SInt32)theSign; + Float32 theWholePart = (theFixedValue & 0x7FFF0000) >> 16; + Float32 theFractPart = theFixedValue & 0x0000FFFF; + theFractPart /= 65536.0f; + + return theSign * (theWholePart + theFractPart); +} + +Float64 CACFNumber::GetFixed64() const +{ + SInt64 theFixedValue = GetSInt64(); + + // this is a 32.32 value so convert it to a double + Float64 theSign = theFixedValue < 0 ? -1.0 : 1.0; + theFixedValue *= (SInt64)theSign; + Float64 theWholePart = (theFixedValue & 0x7FFFFFFF00000000LL) >> 32; + Float64 theFractPart = theFixedValue & 0x00000000FFFFFFFFLL; + theFractPart /= 4294967296.0; + + return theSign * (theWholePart + theFractPart); +} diff --git a/app/PublicUtility/CACFNumber.h b/app/PublicUtility/CACFNumber.h new file mode 100644 index 0000000..25887f6 --- /dev/null +++ b/app/PublicUtility/CACFNumber.h @@ -0,0 +1,151 @@ +/* + File: CACFNumber.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CACFNumber_h__) +#define __CACFNumber_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +//============================================================================= +// CACFBoolean +//============================================================================= + +class CACFBoolean +{ +// Construction/Destruction +public: + explicit CACFBoolean(CFBooleanRef inCFBoolean) : mCFBoolean(inCFBoolean), mWillRelease(true) {} + CACFBoolean(CFBooleanRef inCFBoolean, bool inWillRelease) : mCFBoolean(inCFBoolean), mWillRelease(inWillRelease) {} + explicit CACFBoolean(bool inValue) : mCFBoolean(inValue ? kCFBooleanTrue : kCFBooleanFalse), mWillRelease(true) { Retain(); } + ~CACFBoolean() { Release(); } + CACFBoolean(const CACFBoolean& inBoolean) : mCFBoolean(inBoolean.mCFBoolean), mWillRelease(inBoolean.mWillRelease) { Retain(); } + CACFBoolean& operator=(const CACFBoolean& inBoolean) { Release(); mCFBoolean = inBoolean.mCFBoolean; mWillRelease = inBoolean.mWillRelease; Retain(); return *this; } + CACFBoolean& operator=(CFBooleanRef inCFBoolean) { Release(); mCFBoolean = inCFBoolean; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFBoolean != NULL)) { CFRetain(mCFBoolean); } } + void Release() { if(mWillRelease && (mCFBoolean != NULL)) { CFRelease(mCFBoolean); } } + + CFBooleanRef mCFBoolean; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFBoolean != NULL; } + +// Value Access +public: + CFBooleanRef GetCFBoolean() const { return mCFBoolean; } + CFBooleanRef CopyCFBoolean() const { if(mCFBoolean != NULL) { CFRetain(mCFBoolean); } return mCFBoolean; } + + bool GetBoolean() const { bool theAnswer = false; if(mCFBoolean != NULL) { theAnswer = CFEqual(mCFBoolean, kCFBooleanTrue); } return theAnswer; } + + CACFBoolean(const void*); // prevent accidental instantiation with a pointer via bool constructor +}; + +//============================================================================= +// CACFNumber +//============================================================================= + +class CACFNumber +{ +// Construction/Destruction +public: + explicit CACFNumber(CFNumberRef inCFNumber) : mCFNumber(inCFNumber), mWillRelease(true) {} + CACFNumber(CFNumberRef inCFNumber, bool inWillRelease) : mCFNumber(inCFNumber), mWillRelease(inWillRelease) {} + CACFNumber(SInt32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt32Type, &inValue)), mWillRelease(true) {} + CACFNumber(UInt32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt32Type, &inValue)), mWillRelease(true) {} + CACFNumber(SInt64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt64Type, &inValue)), mWillRelease(true) {} + CACFNumber(UInt64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt64Type, &inValue)), mWillRelease(true) {} + CACFNumber(Float32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberFloat32Type, &inValue)), mWillRelease(true) {} + CACFNumber(Float64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberFloat64Type, &inValue)), mWillRelease(true) {} + ~CACFNumber() { Release(); } + CACFNumber(const CACFNumber& inNumber) : mCFNumber(inNumber.mCFNumber), mWillRelease(inNumber.mWillRelease) { Retain(); } + CACFNumber& operator=(const CACFNumber& inNumber) { Release(); mCFNumber = inNumber.mCFNumber; mWillRelease = inNumber.mWillRelease; Retain(); return *this; } + CACFNumber& operator=(CFNumberRef inCFNumber) { Release(); mCFNumber = inCFNumber; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFNumber != NULL)) { CFRetain(mCFNumber); } } + void Release() { if(mWillRelease && (mCFNumber != NULL)) { CFRelease(mCFNumber); } } + + CFNumberRef mCFNumber; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() const { return mCFNumber != NULL; } + +// Value Access +public: + CFNumberRef GetCFNumber() const { return mCFNumber; } + CFNumberRef CopyCFNumber() const { if(mCFNumber != NULL) { CFRetain(mCFNumber); } return mCFNumber; } + + SInt8 GetSInt8() const { SInt8 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt8Type, &theAnswer); } return theAnswer; } + SInt32 GetSInt32() const { SInt32 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt32Type, &theAnswer); } return theAnswer; } + UInt32 GetUInt32() const { UInt32 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt32Type, &theAnswer); } return theAnswer; } + Float32 GetFloat32() const { Float32 theAnswer = 0.0f; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberFloat32Type, &theAnswer); } return theAnswer; } + Float32 GetFixed32() const; + Float64 GetFixed64() const; + SInt64 GetSInt64() const { SInt64 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt64Type, &theAnswer); } return theAnswer; } + + CACFNumber(const void*); // prevent accidental instantiation with a pointer via bool constructor +}; + +#endif diff --git a/app/PublicUtility/CACFString.cpp b/app/PublicUtility/CACFString.cpp new file mode 100644 index 0000000..3ce81a5 --- /dev/null +++ b/app/PublicUtility/CACFString.cpp @@ -0,0 +1,110 @@ +/* + File: CACFString.cpp + Abstract: CACFString.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CACFString.h" + +//============================================================================= +// CACFString +//============================================================================= + +UInt32 CACFString::GetStringByteLength(CFStringRef inCFString, CFStringEncoding inEncoding) +{ + CFIndex theAnswer = 0; + + if(inCFString != NULL) + { + CFRange theRange = { 0, CFStringGetLength(inCFString) }; + CFStringGetBytes(inCFString, theRange, inEncoding, 0, false, NULL, 0x7FFFFFFF, &theAnswer); + } + + return UInt32(theAnswer); +} + +void CACFString::GetCString(CFStringRef inCFString, char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding) +{ + if(ioStringSize > 0) + { + if(inCFString != NULL) + { + CFIndex theLength = 0; + CFRange theRange = { 0, CFStringGetLength(inCFString) }; + CFStringGetBytes(inCFString, theRange, inEncoding, 0, false, (UInt8*)outString, static_cast(ioStringSize - 1), &theLength); + outString[theLength] = 0; + ioStringSize = ToUInt32(theLength) + 1; + } + else + { + outString[0] = 0; + ioStringSize = 1; + } + } +} + +void CACFString::GetUnicodeString(CFStringRef inCFString, UInt16* outString, UInt32& ioStringSize) +{ + if(ioStringSize > 0) + { + if(inCFString != NULL) + { + CFRange theStringRange = { 0, CFStringGetLength(inCFString) }; + if(static_cast(theStringRange.length) > ioStringSize) + { + theStringRange.length = static_cast(ioStringSize); + } + CFStringGetCharacters(inCFString, theStringRange, outString); + ioStringSize = ToUInt32(theStringRange.length); + } + else + { + outString[0] = 0; + ioStringSize = 0; + } + } +} diff --git a/app/PublicUtility/CACFString.h b/app/PublicUtility/CACFString.h new file mode 100644 index 0000000..3abce51 --- /dev/null +++ b/app/PublicUtility/CACFString.h @@ -0,0 +1,196 @@ +/* + File: CACFString.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CACFString_h__) +#define __CACFString_h__ + +//============================================================================= +// Includes +//============================================================================= + +#include "CADebugMacros.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +//============================================================================= +// CACFString +// +// Notes +// - Using the AssignWithoutRetain() method will fool the static analyzer into thinking that the +// CFString being assigned will be leaked. This is because the static analyzer is not smart +// enough to understand that the destructor will release the object. +//============================================================================= + +class CACFString +{ +// Construction/Destruction +public: + CACFString() : mCFString(NULL), mWillRelease(true) {} + explicit CACFString(CFStringRef inCFString) : mCFString(inCFString), mWillRelease(true) {} + CACFString(const char* inCString) : mCFString(CFStringCreateWithCString(NULL, inCString, kCFStringEncodingASCII)), mWillRelease(true) {} + CACFString(CFStringRef inCFString, bool inWillRelease) : mCFString(inCFString), mWillRelease(inWillRelease) {} + CACFString(const char* inCString, bool inWillRelease) : mCFString(CFStringCreateWithCString(NULL, inCString, kCFStringEncodingASCII)), mWillRelease(inWillRelease) {} + CACFString(const char* inCString, CFStringEncoding inCStringEncoding, bool inWillRelease = true) : mCFString(CFStringCreateWithCString(NULL, inCString, inCStringEncoding)), mWillRelease(inWillRelease) {} + ~CACFString() { Release(); } + CACFString(const CACFString& inString) : mCFString(inString.mCFString), mWillRelease(inString.mWillRelease) { Retain(); } + CACFString& operator=(const CACFString& inString) { if (inString.mCFString != mCFString) { Release(); mCFString = inString.mCFString; mWillRelease = inString.mWillRelease; Retain(); } return *this; } + CACFString& operator=(CFStringRef inCFString) { if (inCFString != mCFString) { Release(); mCFString = inCFString; } mWillRelease = true; Retain(); return *this; } + void AssignWithoutRetain(CFStringRef inCFString) { if (inCFString != mCFString) { Release(); mCFString = inCFString; } mWillRelease = true; } + +private: + void Retain() { if(mWillRelease && (mCFString != NULL)) { CFRetain(mCFString); } } + void Release() { if(mWillRelease && (mCFString != NULL)) { CFRelease(mCFString); } } + + CFStringRef mCFString; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() const { return mCFString != NULL; } + bool IsEqualTo(CFStringRef inString) const { bool theAnswer = false; if(mCFString != NULL) { theAnswer = CFStringCompare(inString, mCFString, 0) == kCFCompareEqualTo; } return theAnswer; } + bool StartsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFString != NULL) { theAnswer = CFStringHasPrefix(mCFString, inString); } return theAnswer; } + bool EndsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFString != NULL) { theAnswer = CFStringHasSuffix(mCFString, inString); } return theAnswer; } + +// Value Access +public: + CFStringRef GetCFString() const { return mCFString; } + CFStringRef CopyCFString() const { if(mCFString != NULL) { CFRetain(mCFString); } return mCFString; } + const CFStringRef* GetPointerToStorage() const { return &mCFString; } + CFStringRef& GetStorage() { Release(); mWillRelease = true; return mCFString; } + UInt32 GetLength() const { UInt32 theAnswer = 0; if(mCFString != NULL) { theAnswer = ToUInt32(CFStringGetLength(mCFString)); } return theAnswer; } + UInt32 GetByteLength(CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { UInt32 theAnswer = 0; if(mCFString != NULL) { theAnswer = GetStringByteLength(mCFString, inEncoding); } return theAnswer; } + void GetCString(char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { GetCString(mCFString, outString, ioStringSize, inEncoding); } + void GetUnicodeString(UInt16* outString, UInt32& ioStringSize) const { GetUnicodeString(mCFString, outString, ioStringSize); } + SInt32 GetAsInteger() { return GetAsInteger(mCFString); } + Float64 GetAsFloat64() { return GetAsFloat64(mCFString); } + + static UInt32 GetStringLength(CFStringRef inCFString) { UInt32 theAnswer = 0; if(inCFString != NULL) { theAnswer = ToUInt32(CFStringGetLength(inCFString)); } return theAnswer; } + static UInt32 GetStringByteLength(CFStringRef inCFString, CFStringEncoding inEncoding = kCFStringEncodingUTF8); + static void GetCString(CFStringRef inCFString, char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8); + static void GetUnicodeString(CFStringRef inCFString, UInt16* outString, UInt32& ioStringSize); + static SInt32 GetAsInteger(CFStringRef inCFString) { SInt32 theAnswer = 0; if(inCFString != NULL){ theAnswer = CFStringGetIntValue(inCFString); } return theAnswer; } + static Float64 GetAsFloat64(CFStringRef inCFString) { Float64 theAnswer = 0; if(inCFString != NULL){ theAnswer = CFStringGetDoubleValue(inCFString); } return theAnswer; } + +}; + +inline bool operator<(const CACFString& x, const CACFString& y) { return CFStringCompare(x.GetCFString(), y.GetCFString(), 0) == kCFCompareLessThan; } +inline bool operator==(const CACFString& x, const CACFString& y) { return CFStringCompare(x.GetCFString(), y.GetCFString(), 0) == kCFCompareEqualTo; } +inline bool operator!=(const CACFString& x, const CACFString& y) { return !(x == y); } +inline bool operator<=(const CACFString& x, const CACFString& y) { return (x < y) || (x == y); } +inline bool operator>=(const CACFString& x, const CACFString& y) { return !(x < y); } +inline bool operator>(const CACFString& x, const CACFString& y) { return !((x < y) || (x == y)); } + +inline bool operator<(const CACFString& x, CFStringRef y) { return CFStringCompare(x.GetCFString(), y, 0) == kCFCompareLessThan; } +inline bool operator==(const CACFString& x, CFStringRef y) { return CFStringCompare(x.GetCFString(), y, 0) == kCFCompareEqualTo; } +inline bool operator!=(const CACFString& x, CFStringRef y) { return !(x == y); } +inline bool operator<=(const CACFString& x, CFStringRef y) { return (x < y) || (x == y); } +inline bool operator>=(const CACFString& x, CFStringRef y) { return !(x < y); } +inline bool operator>(const CACFString& x, CFStringRef y) { return !((x < y) || (x == y)); } + +inline bool operator<(CFStringRef x, const CACFString& y) { return CFStringCompare(x, y.GetCFString(), 0) == kCFCompareLessThan; } +inline bool operator==(CFStringRef x, const CACFString& y) { return CFStringCompare(x, y.GetCFString(), 0) == kCFCompareEqualTo; } +inline bool operator!=(CFStringRef x, const CACFString& y) { return !(x == y); } +inline bool operator<=(CFStringRef x, const CACFString& y) { return (x < y) || (x == y); } +inline bool operator>=(CFStringRef x, const CACFString& y) { return !(x < y); } +inline bool operator>(CFStringRef x, const CACFString& y) { return !((x < y) || (x == y)); } + +//============================================================================= +// CACFMutableString +//============================================================================= + +class CACFMutableString +{ +// Construction/Destruction +public: + CACFMutableString() : mCFMutableString(NULL), mWillRelease(true) {} + CACFMutableString(CFMutableStringRef inCFMutableString, bool inWillRelease = true) : mCFMutableString(inCFMutableString), mWillRelease(inWillRelease) {} + CACFMutableString(CFStringRef inStringToCopy, bool /*inMakeCopy*/, bool inWillRelease = true) : mCFMutableString(CFStringCreateMutableCopy(NULL, 0, inStringToCopy)), mWillRelease(inWillRelease) {} + CACFMutableString(const char* inCString, bool inWillRelease = true) : mCFMutableString(NULL), mWillRelease(inWillRelease) { CACFString theString(inCString); mCFMutableString = CFStringCreateMutableCopy(NULL, 0, theString.GetCFString()); } + CACFMutableString(const char* inCString, CFStringEncoding inCStringEncoding, bool inWillRelease = true) : mCFMutableString(NULL), mWillRelease(inWillRelease) { CACFString theString(inCString, inCStringEncoding); mCFMutableString = CFStringCreateMutableCopy(NULL, 0, theString.GetCFString()); } + ~CACFMutableString() { Release(); } + CACFMutableString(const CACFMutableString& inString) : mCFMutableString(inString.mCFMutableString), mWillRelease(inString.mWillRelease) { Retain(); } + CACFMutableString& operator=(const CACFMutableString& inString) { Release(); mCFMutableString = inString.mCFMutableString; mWillRelease = inString.mWillRelease; Retain(); return *this; } + CACFMutableString& operator=(CFMutableStringRef inCFMutableString) { Release(); mCFMutableString = inCFMutableString; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFMutableString != NULL)) { CFRetain(mCFMutableString); } } + void Release() { if(mWillRelease && (mCFMutableString != NULL)) { CFRelease(mCFMutableString); } } + + CFMutableStringRef mCFMutableString; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFMutableString != NULL; } + bool IsEqualTo(CFStringRef inString) const { bool theAnswer = false; if(mCFMutableString != NULL) { theAnswer = CFStringCompare(inString, mCFMutableString, 0) == kCFCompareEqualTo; } return theAnswer; } + bool StartsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFMutableString != NULL) { theAnswer = CFStringHasPrefix(mCFMutableString, inString); } return theAnswer; } + bool EndsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFMutableString != NULL) { theAnswer = CFStringHasSuffix(mCFMutableString, inString); } return theAnswer; } + void Append(CFStringRef inString) { if(mCFMutableString != NULL) { CFStringAppend(mCFMutableString, inString); } } + +// Value Access +public: + CFMutableStringRef GetCFMutableString() const { return mCFMutableString; } + CFMutableStringRef CopyCFMutableString() const { if(mCFMutableString != NULL) { CFRetain(mCFMutableString); } return mCFMutableString; } + UInt32 GetLength() const { UInt32 theAnswer = 0; if(mCFMutableString != NULL) { theAnswer = ToUInt32(CFStringGetLength(mCFMutableString)); } return theAnswer; } + UInt32 GetByteLength(CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { UInt32 theAnswer = 0; if(mCFMutableString != NULL) { theAnswer = CACFString::GetStringByteLength(mCFMutableString, inEncoding); } return theAnswer; } + void GetCString(char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { CACFString::GetCString(mCFMutableString, outString, ioStringSize, inEncoding); } + void GetUnicodeString(UInt16* outString, UInt32& ioStringSize) const { CACFString::GetUnicodeString(mCFMutableString, outString, ioStringSize); } + SInt32 GetAsInteger() { return CACFString::GetAsInteger(mCFMutableString); } + Float64 GetAsFloat64() { return CACFString::GetAsFloat64(mCFMutableString); } + +}; + +#endif diff --git a/app/PublicUtility/CADebugMacros.cpp b/app/PublicUtility/CADebugMacros.cpp new file mode 100644 index 0000000..815348a --- /dev/null +++ b/app/PublicUtility/CADebugMacros.cpp @@ -0,0 +1,134 @@ +// This file is part of Background Music. +// +// Background Music is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 2 of the +// License, or (at your option) any later version. +// +// Background Music is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Background Music. If not, see . + +// +// CADebugMacros.cpp +// PublicUtility +// +// Copyright (C) 2014 Apple Inc. All Rights Reserved. +// Copyright © 2016, 2017, 2020 Kyle Neideck +// +// Original license header follows. +// + +/* + File: CADebugMacros.cpp + Abstract: CADebugMacros.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "CADebugMacros.h" +#include +#if TARGET_API_MAC_OSX + #include +#endif + +#if DEBUG +#include + +void DebugPrint(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} +#endif // DEBUG + +void LogError(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vLogError(fmt, args); + va_end(args); +} + +void vLogError(const char *fmt, va_list args) +{ +#if (DEBUG || !TARGET_API_MAC_OSX) && !CoreAudio_UseSysLog + printf("[ERROR] "); + vprintf(fmt, args); + printf("\n"); +#else + vsyslog(LOG_ERR, fmt, args); +#endif + +#if DEBUG + CADebuggerStop(); +#endif +} + +void LogWarning(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vLogWarning(fmt, args); + va_end(args); +} + +void vLogWarning(const char *fmt, va_list args) +{ +#if (DEBUG || !TARGET_API_MAC_OSX) && !CoreAudio_UseSysLog + printf("[WARNING] "); + vprintf(fmt, args); + printf("\n"); +#else + vsyslog(LOG_WARNING, fmt, args); +#endif + +#if DEBUG + //CADebuggerStop(); // TODO: Add a toggle for this to the project file (under "Preprocessor Macros"). Default to off. +#endif +} diff --git a/app/PublicUtility/CADebugMacros.h b/app/PublicUtility/CADebugMacros.h new file mode 100644 index 0000000..a434e45 --- /dev/null +++ b/app/PublicUtility/CADebugMacros.h @@ -0,0 +1,612 @@ +// This file is part of Background Music. +// +// Background Music is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 2 of the +// License, or (at your option) any later version. +// +// Background Music is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Background Music. If not, see . + +// +// CADebugMacros.h +// PublicUtility +// +// Copyright (C) 2014 Apple Inc. All Rights Reserved. +// Copyright © 2016, 2020 Kyle Neideck +// +// Original license header follows. +// + +/* + File: CADebugMacros.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CADebugMacros_h__) +#define __CADebugMacros_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "CoreAudioTypes.h" +#endif + +#include "CADebugPrintf.h" + +#include + +//============================================================================= +// CADebugMacros +//============================================================================= + +//#define CoreAudio_StopOnFailure 1 +//#define CoreAudio_TimeStampMessages 1 +//#define CoreAudio_ThreadStampMessages 1 +//#define CoreAudio_FlushDebugMessages 1 + +#if TARGET_RT_BIG_ENDIAN + #define CA4CCToCString(the4CC) { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 } + #define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[0]; theCString[1] = ((char*)&the4CC)[1]; theCString[2] = ((char*)&the4CC)[2]; theCString[3] = ((char*)&the4CC)[3]; theCString[4] = 0; } +#else + #define CA4CCToCString(the4CC) { ((char*)&the4CC)[3], ((char*)&the4CC)[2], ((char*)&the4CC)[1], ((char*)&the4CC)[0], 0 } + #define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[3]; theCString[1] = ((char*)&the4CC)[2]; theCString[2] = ((char*)&the4CC)[1]; theCString[3] = ((char*)&the4CC)[0]; theCString[4] = 0; } +#endif + +// This is a macro that does a sizeof and casts the result to a UInt32. This is useful for all the +// places where -wshorten64-32 catches assigning a sizeof expression to a UInt32. +// For want of a better place to park this, we'll park it here. +#define SizeOf32(X) ((UInt32)sizeof(X)) + +// This is a macro that does a offsetof and casts the result to a UInt32. This is useful for all the +// places where -wshorten64-32 catches assigning an offsetof expression to a UInt32. +// For want of a better place to park this, we'll park it here. +#define OffsetOf32(X, Y) ((UInt32)offsetof(X, Y)) + +// This macro casts the expression to a UInt32. It is called out specially to allow us to track casts +// that have been added purely to avert -wshorten64-32 warnings on 64 bit platforms. +// For want of a better place to park this, we'll park it here. +#define ToUInt32(X) ((UInt32)(X)) +#define ToSInt32(X) ((SInt32)(X)) + +#pragma mark Basic Definitions + +// basic debugging print routines +#if TARGET_OS_MAC && !TARGET_API_MAC_CARBON + extern void DebugStr(const unsigned char* debuggerMsg); + #define DebugMessage(msg) DebugStr("\p"msg) + #define DebugMessageN1(msg, N1) + #define DebugMessageN2(msg, N1, N2) + #define DebugMessageN3(msg, N1, N2, N3) +#else + #if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile) + #define FlushRtn ,fflush(DebugPrintfFile) + #else + #define FlushRtn + #endif + + #if CoreAudio_ThreadStampMessages + #include + #include "CAHostTimeBase.h" + #if TARGET_RT_64_BIT + #define DebugPrintfThreadIDFormat "%16p" + #else + #define DebugPrintfThreadIDFormat "%8p" + #endif + #define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " DebugPrintfThreadIDFormat " " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), ## __VA_ARGS__) FlushRtn + #elif CoreAudio_TimeStampMessages + #include "CAHostTimeBase.h" + #define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), ## __VA_ARGS__) FlushRtn + #else + #define DebugMsg(inFormat, ...) DebugPrintf(inFormat, ## __VA_ARGS__) FlushRtn + #endif +#endif + +#if DEBUG || CoreAudio_Debug + // can be used to break into debugger immediately, also see CADebugger + #define BusError() { long* p=NULL; *p=0; } + + void DebugPrint(const char *fmt, ...); // can be used like printf + #ifndef DEBUGPRINT + #define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h) + #endif + #if VERBOSE + #define vprint(msg) DEBUGPRINT(msg) + #else + #define vprint(msg) + #endif + + // Original macro keeps its function of turning on and off use of CADebuggerStop() for both asserts and throws. + // For backwards compat, it overrides any setting of the two sub-macros. + #if CoreAudio_StopOnFailure + #include "CADebugger.h" + #undef CoreAudio_StopOnAssert + #define CoreAudio_StopOnAssert 1 + #undef CoreAudio_StopOnThrow + #define CoreAudio_StopOnThrow 1 + #define STOP CADebuggerStop() + #else + #define STOP + #endif + + #if CoreAudio_StopOnAssert + #if !CoreAudio_StopOnFailure + #include "CADebugger.h" + #define STOP + #endif + #define __ASSERT_STOP CADebuggerStop() + #else + #define __ASSERT_STOP + #endif + + #if CoreAudio_StopOnThrow + #if !CoreAudio_StopOnFailure + #include "CADebugger.h" + #define STOP + #endif + #define __THROW_STOP CADebuggerStop() + #else + #define __THROW_STOP + #endif + +#else + + #ifndef DEBUGPRINT + #define DEBUGPRINT(msg) + #endif + #define vprint(msg) + #define STOP + #define __ASSERT_STOP + #define __THROW_STOP +#endif + +// Old-style numbered DebugMessage calls are implemented in terms of DebugMsg() now +#define DebugMessage(msg) DebugMsg(msg) +#define DebugMessageN1(msg, N1) DebugMsg(msg, N1) +#define DebugMessageN2(msg, N1, N2) DebugMsg(msg, N1, N2) +#define DebugMessageN3(msg, N1, N2, N3) DebugMsg(msg, N1, N2, N3) +#define DebugMessageN4(msg, N1, N2, N3, N4) DebugMsg(msg, N1, N2, N3, N4) +#define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugMsg(msg, N1, N2, N3, N4, N5) +#define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugMsg(msg, N1, N2, N3, N4, N5, N6) +#define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7) +#define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7, N8) +#define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) + +// VC edit: Added __printflike and va_list versions. +void LogError(const char *fmt, ...) __printflike(1, 2); // writes to syslog (and stderr if debugging) +void vLogError(const char *fmt, va_list args); +void LogWarning(const char *fmt, ...) __printflike(1, 2); // writes to syslog (and stderr if debugging) +void vLogWarning(const char *fmt, va_list args); + +#define NO_ACTION (void)0 + +#if DEBUG || CoreAudio_Debug + +#pragma mark Debug Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + DebugMessage(inMessage); \ + __ASSERT_STOP; \ + } + +#define AssertFileLine(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + DebugMessageN3("%s, line %d: %s", __FILE__, __LINE__, inMessage); \ + __ASSERT_STOP; \ + } + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNotNULL(inPtr, inMessage) \ + { \ + if((inPtr) == NULL) \ + { \ + DebugMessage(inMessage); \ + __ASSERT_STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfError(inError, inAction, inHandler, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %ld (%s)", (long int)__Err, __4CC); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfNoMessage(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#if defined(__cplusplus) + +#define Throw(inException) __THROW_STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + DebugMessageN2(inMessage ", Code: %d, Facility: 0x%X", HRESULT_CODE(__Err), HRESULT_FACILITY(__Err)); \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + DebugMessage(inMethodName": Subclasses must implement this method"); \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#else + +#pragma mark Release Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + __ASSERT_STOP; \ + } + +#define AssertFileLine(inCondition, inMessage) Assert(inCondition, inMessage) + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNotNULL(inPtr, inMessage) \ + { \ + if((inPtr) == NULL) \ + { \ + __ASSERT_STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \ + if((inKernelError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfError(inError, inAction, inHandler, inMessage) \ + if((inError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNoMessage(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#if defined(__cplusplus) + +#define Throw(inException) __THROW_STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#endif // DEBUG || CoreAudio_Debug + +#endif diff --git a/app/PublicUtility/CADebugPrintf.cpp b/app/PublicUtility/CADebugPrintf.cpp new file mode 100644 index 0000000..747f806 --- /dev/null +++ b/app/PublicUtility/CADebugPrintf.cpp @@ -0,0 +1,114 @@ +// This file is part of Background Music. +// +// Background Music is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 2 of the +// License, or (at your option) any later version. +// +// Background Music is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Background Music. If not, see . + +// +// CADebugPrintf.cpp +// PublicUtility +// +// Copyright (C) 2014 Apple Inc. All Rights Reserved. +// Copyright © 2020 Kyle Neideck +// +// Original license header follows. +// + +/* + File: CADebugPrintf.cpp + Abstract: CADebugPrintf.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CADebugPrintf.h" + +#if TARGET_OS_WIN32 + #include + #include + #include + extern "C" + int CAWin32DebugPrintf(char* inFormat, ...) + { + if (VCDebugLoggingIsEnabled()) { + char theMessage[1024]; + va_list theArguments; + va_start(theArguments, inFormat); + _vsnprintf(theMessage, 1024, inFormat, theArguments); + va_end(theArguments); + OutputDebugString(theMessage); + } + + return 0; + } +#endif + +#if defined(CoreAudio_UseSideFile) + #include + FILE* sDebugPrintfSideFile = NULL; + extern "C" + void OpenDebugPrintfSideFile() + { + if(sDebugPrintfSideFile == NULL) + { + char theFileName[1024]; + snprintf(theFileName, sizeof(theFileName), CoreAudio_UseSideFile, getpid()); + sDebugPrintfSideFile = fopen(theFileName, "a+"); + DebugPrintfRtn(DebugPrintfFileComma "\n------------------------------\n"); + } + } +#endif + diff --git a/app/PublicUtility/CADebugPrintf.h b/app/PublicUtility/CADebugPrintf.h new file mode 100644 index 0000000..c443376 --- /dev/null +++ b/app/PublicUtility/CADebugPrintf.h @@ -0,0 +1,113 @@ +/* + File: CADebugPrintf.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CADebugPrintf_h__) +#define __CADebugPrintf_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "CoreAudioTypes.h" +#endif + +#include "VCDebugLogging.h" + +//============================================================================= +// Macros to redirect debugging output to various logging services +//============================================================================= + +//#define CoreAudio_UseSysLog 1 +//#define CoreAudio_UseSideFile "/CoreAudio-%d.txt" + +#if TARGET_OS_WIN32 + #if defined(__cplusplus) + extern "C" + #endif + extern int CAWin32DebugPrintf(char* inFormat, ...); + #define DebugPrintfRtn CAWin32DebugPrintf + #define DebugPrintfFile + #define DebugPrintfLineEnding "\n" + #define DebugPrintfFileComma +#else + #if CoreAudio_UseSysLog + #include + #define DebugPrintfRtn syslog + #define DebugPrintfFile LOG_NOTICE + #define DebugPrintfLineEnding "" + #define DebugPrintfFileComma DebugPrintfFile, + #elif defined(CoreAudio_UseSideFile) + #include + #if defined(__cplusplus) + extern "C" + #endif + void OpenDebugPrintfSideFile(); + extern FILE* sDebugPrintfSideFile; + #define DebugPrintfRtn fprintf + #define DebugPrintfFile ((sDebugPrintfSideFile != NULL) ? sDebugPrintfSideFile : stderr) + #define DebugPrintfLineEnding "\n" + #define DebugPrintfFileComma DebugPrintfFile, + #else + #include + #define DebugPrintfRtn fprintf + #define DebugPrintfFile stderr + #define DebugPrintfLineEnding "\n" + #define DebugPrintfFileComma DebugPrintfFile, + #endif +#endif + +#define DebugPrintf(inFormat, ...) \ + do { \ + if (VCDebugLoggingIsEnabled()) { \ + DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__); \ + } \ + } while (0) + +#endif + diff --git a/app/PublicUtility/CADebugger.cpp b/app/PublicUtility/CADebugger.cpp new file mode 100644 index 0000000..7f0141d --- /dev/null +++ b/app/PublicUtility/CADebugger.cpp @@ -0,0 +1,103 @@ +/* + File: CADebugger.cpp + Abstract: CADebugger.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CADebugger.h" + +//============================================================================= +// CADebugger +//============================================================================= + +#if TARGET_API_MAC_OSX + +#include +#include +#include + +bool CAIsDebuggerAttached(void) +{ + int mib[4]; + struct kinfo_proc info; + size_t size; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + size = sizeof(info); + info.kp_proc.p_flag = 0; + + sysctl(mib, 4, &info, &size, NULL, 0); + + return (info.kp_proc.p_flag & P_TRACED) == P_TRACED; +} + +#endif + +void CADebuggerStop(void) +{ + #if CoreAudio_Debug + #if TARGET_API_MAC_OSX + if(CAIsDebuggerAttached()) + { + #if defined(__i386__) || defined(__x86_64__) + asm("int3"); + #else + __builtin_trap(); + #endif + } + else + { + abort(); + } + #else + __debugbreak(); + #endif + #endif +} diff --git a/app/PublicUtility/CADebugger.h b/app/PublicUtility/CADebugger.h new file mode 100644 index 0000000..2bb988a --- /dev/null +++ b/app/PublicUtility/CADebugger.h @@ -0,0 +1,78 @@ +/* + File: CADebugger.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CADebugger_h__) +#define __CADebugger_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +//============================================================================= +// CADebugger +//============================================================================= + +// VC edit: Added extern "C" so CADebugger (and headers that include it) can be used in Obj-C. +#ifdef __cplusplus +extern "C" { +#endif + +#if TARGET_API_MAC_OSX + extern bool CAIsDebuggerAttached(void); +#endif +extern void CADebuggerStop(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/PublicUtility/CAException.h b/app/PublicUtility/CAException.h new file mode 100644 index 0000000..7217001 --- /dev/null +++ b/app/PublicUtility/CAException.h @@ -0,0 +1,83 @@ +/* + File: CAException.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAException_h__) +#define __CAException_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "CoreAudioTypes.h" +#endif + +//============================================================================= +// CAException +//============================================================================= + +class CAException +{ + +public: + CAException(OSStatus inError) : mError(inError) {} + CAException(const CAException& inException) : mError(inException.mError) {} + CAException& operator=(const CAException& inException) { mError = inException.mError; return *this; } + ~CAException() {} + + OSStatus GetError() const { return mError; } + +protected: + OSStatus mError; +}; + +#define CATry try{ +#define CACatch } catch(...) {} +#define CASwallowException(inExpression) try { inExpression; } catch(...) {} + +#endif diff --git a/app/PublicUtility/CAHALAudioDevice.cpp b/app/PublicUtility/CAHALAudioDevice.cpp new file mode 100644 index 0000000..9bce346 --- /dev/null +++ b/app/PublicUtility/CAHALAudioDevice.cpp @@ -0,0 +1,1156 @@ +/* + File: CAHALAudioDevice.cpp + Abstract: CAHALAudioDevice.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAHALAudioDevice.h" + +// PublicUtility Includes +#include "CAAutoDisposer.h" +#include "CAHALAudioStream.h" +#include "CAHALAudioSystemObject.h" +#include "CAPropertyAddress.h" + +//================================================================================================== +// CAHALAudioDevice +//================================================================================================== + +CAHALAudioDevice::CAHALAudioDevice(AudioObjectID inAudioDevice) +: + CAHALAudioObject(inAudioDevice) +{ +} + +CAHALAudioDevice::CAHALAudioDevice(CFStringRef inUID) +: + CAHALAudioObject(CAHALAudioSystemObject().GetAudioDeviceForUID(inUID)) +{ +} + +CAHALAudioDevice::~CAHALAudioDevice() +{ +} + +CFStringRef CAHALAudioDevice::CopyDeviceUID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDeviceUID); + return GetPropertyData_CFString(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::HasModelUID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyModelUID); + return HasProperty(theAddress); +} + +CFStringRef CAHALAudioDevice::CopyModelUID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyModelUID); + return GetPropertyData_CFString(theAddress, 0, NULL); +} + +CFStringRef CAHALAudioDevice::CopyConfigurationApplicationBundleID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyConfigurationApplication); + return GetPropertyData_CFString(theAddress, 0, NULL); +} + +CFURLRef CAHALAudioDevice::CopyIconLocation() const +{ + CFURLRef theAnswer = NULL; + CAPropertyAddress theAddress(kAudioDevicePropertyIcon); + UInt32 theSize = sizeof(CFURLRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +UInt32 CAHALAudioDevice::GetTransportType() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyTransportType); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::CanBeDefaultDevice(bool inIsInput, bool inIsSystem) const +{ + CAPropertyAddress theAddress(inIsSystem ? kAudioDevicePropertyDeviceCanBeDefaultSystemDevice : kAudioDevicePropertyDeviceCanBeDefaultDevice, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return GetPropertyData_UInt32(theAddress, 0, NULL) != 0; +} + +bool CAHALAudioDevice::HasDevicePlugInStatus() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlugIn); + return HasProperty(theAddress); +} + +OSStatus CAHALAudioDevice::GetDevicePlugInStatus() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlugIn); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::IsAlive() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDeviceIsAlive); + return GetPropertyData_UInt32(theAddress, 0, NULL) != 0; +} + +bool CAHALAudioDevice::IsHidden() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyIsHidden); + return GetPropertyData_UInt32(theAddress, 0, NULL) != 0; +} + +pid_t CAHALAudioDevice::GetHogModeOwner() const +{ + pid_t theAnswer = -1; + CAPropertyAddress theAddress(kAudioDevicePropertyHogMode); + if(HasProperty(theAddress)) + { + UInt32 theSize = sizeof(pid_t); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + return theAnswer; +} + +bool CAHALAudioDevice::IsHogModeSettable() const +{ + bool theAnswer = false; + CAPropertyAddress theAddress(kAudioDevicePropertyHogMode); + if(HasProperty(theAddress)) + { + theAnswer = IsPropertySettable(theAddress); + } + return theAnswer; +} + +bool CAHALAudioDevice::TakeHogMode() +{ + CAPropertyAddress theAddress(kAudioDevicePropertyHogMode); + pid_t thePID = getpid(); + if(HasProperty(theAddress)) + { + SetPropertyData(theAddress, 0, NULL, sizeof(pid_t), &thePID); + } + return thePID == getpid(); +} + +void CAHALAudioDevice::ReleaseHogMode() +{ + CAPropertyAddress theAddress(kAudioDevicePropertyHogMode); + if(HasProperty(theAddress)) + { + pid_t thePID = -1; + SetPropertyData(theAddress, 0, NULL, sizeof(pid_t), &thePID); + } +} + +bool CAHALAudioDevice::HasPreferredStereoChannels(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelsForStereo, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return HasProperty(theAddress); +} + +void CAHALAudioDevice::GetPreferredStereoChannels(bool inIsInput, UInt32& outLeft, UInt32& outRight) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelsForStereo, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theStereoPair[2] = { 0, 0 }; + UInt32 theSize = 2 * sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, theStereoPair); + outLeft = theStereoPair[0]; + outRight = theStereoPair[1]; +} + +void CAHALAudioDevice::SetPreferredStereoChannels(bool inIsInput, UInt32 inLeft, UInt32 inRight) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelsForStereo, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theStereoPair[2] = { inLeft, inRight }; + SetPropertyData(theAddress, 0, NULL, 2 * sizeof(UInt32), theStereoPair); +} + +bool CAHALAudioDevice::HasPreferredChannelLayout(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelLayout, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return HasProperty(theAddress); +} + +void CAHALAudioDevice::GetPreferredChannelLayout(bool inIsInput, AudioChannelLayout& outChannelLayout) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelLayout, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theSize = (SizeOf32(AudioChannelLayout) - SizeOf32(AudioChannelDescription)) + GetTotalNumberChannels(inIsInput) * SizeOf32(AudioChannelDescription); + GetPropertyData(theAddress, 0, NULL, theSize, &outChannelLayout); +} + +void CAHALAudioDevice::SetPreferredStereoChannels(bool inIsInput, AudioChannelLayout& inChannelLayout) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelLayout, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theSize = (SizeOf32(AudioChannelLayout) - SizeOf32(AudioChannelDescription)) + GetTotalNumberChannels(inIsInput) * SizeOf32(AudioChannelDescription); + SetPropertyData(theAddress, 0, NULL, theSize, &inChannelLayout); +} + +UInt32 CAHALAudioDevice::GetNumberRelatedAudioDevices() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyRelatedDevices); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= SizeOf32(AudioObjectID); + } + return theAnswer; +} + +void CAHALAudioDevice::GetRelatedAudioDevices(UInt32& ioNumberRelatedDevices, AudioObjectID* outRelatedDevices) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyRelatedDevices); + if(HasProperty(theAddress)) + { + UInt32 theSize = ioNumberRelatedDevices * SizeOf32(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, outRelatedDevices); + ioNumberRelatedDevices = theSize / SizeOf32(AudioObjectID); + } + else + { + UInt32 theSize = ioNumberRelatedDevices * SizeOf32(AudioObjectID); + memset(outRelatedDevices, 0, theSize); + ioNumberRelatedDevices = 0; + } +} + +AudioObjectID CAHALAudioDevice::GetRelatedAudioDeviceByIndex(UInt32 inIndex) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + UInt32 theNumberRelatedDevices = GetNumberRelatedAudioDevices(); + if((theNumberRelatedDevices > 0) && (inIndex < theNumberRelatedDevices)) + { + CAAutoArrayDelete theRelatedDeviceList(theNumberRelatedDevices); + GetRelatedAudioDevices(theNumberRelatedDevices, theRelatedDeviceList); + if((theNumberRelatedDevices > 0) && (inIndex < theNumberRelatedDevices)) + { + theAnswer = theRelatedDeviceList[inIndex]; + } + } + return theAnswer; +} + +UInt32 CAHALAudioDevice::GetNumberStreams(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStreams, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= SizeOf32(AudioObjectID); + return theAnswer; +} + +void CAHALAudioDevice::GetStreams(bool inIsInput, UInt32& ioNumberStreams, AudioObjectID* outStreamList) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStreams, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theSize = ioNumberStreams * SizeOf32(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, outStreamList); + ioNumberStreams = theSize / SizeOf32(AudioObjectID); +} + +AudioObjectID CAHALAudioDevice::GetStreamByIndex(bool inIsInput, UInt32 inIndex) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + UInt32 theNumberStreams = GetNumberStreams(inIsInput); + if((theNumberStreams > 0) && (inIndex < theNumberStreams)) + { + CAAutoArrayDelete theStreamList(theNumberStreams); + GetStreams(inIsInput, theNumberStreams, theStreamList); + if((theNumberStreams > 0) && (inIndex < theNumberStreams)) + { + theAnswer = theStreamList[inIndex]; + } + } + return theAnswer; +} + +UInt32 CAHALAudioDevice::GetTotalNumberChannels(bool inIsInput) const +{ + UInt32 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyStreamConfiguration, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + CAAutoFree theBufferList(theSize); + GetPropertyData(theAddress, 0, NULL, theSize, theBufferList); + for(UInt32 theIndex = 0; theIndex < theBufferList->mNumberBuffers; ++theIndex) + { + theAnswer += theBufferList->mBuffers[theIndex].mNumberChannels; + } + return theAnswer; +} + +void CAHALAudioDevice::GetCurrentVirtualFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const +{ + ioNumberStreams = std::min(ioNumberStreams, GetNumberStreams(inIsInput)); + for(UInt32 theIndex = 0; theIndex < ioNumberStreams; ++theIndex) + { + CAHALAudioStream theStream(GetStreamByIndex(inIsInput, theIndex)); + theStream.GetCurrentVirtualFormat(outFormats[theIndex]); + } +} + +void CAHALAudioDevice::GetCurrentPhysicalFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const +{ + ioNumberStreams = std::min(ioNumberStreams, GetNumberStreams(inIsInput)); + for(UInt32 theIndex = 0; theIndex < ioNumberStreams; ++theIndex) + { + CAHALAudioStream theStream(GetStreamByIndex(inIsInput, theIndex)); + theStream.GetCurrentPhysicalFormat(outFormats[theIndex]); + } +} + +bool CAHALAudioDevice::IsRunning() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDeviceIsRunning); + UInt32 theAnswer = GetPropertyData_UInt32(theAddress, 0, NULL); + return theAnswer != 0; +} + +bool CAHALAudioDevice::IsRunningSomewhere() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDeviceIsRunningSomewhere); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + theAnswer = GetPropertyData_UInt32(theAddress, 0, NULL); + } + return theAnswer != 0; +} + +UInt32 CAHALAudioDevice::GetLatency(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyLatency, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +UInt32 CAHALAudioDevice::GetSafetyOffset(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySafetyOffset, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::HasClockDomain() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockDomain); + return HasProperty(theAddress); +} + +UInt32 CAHALAudioDevice::GetClockDomain() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockDomain); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +Float64 CAHALAudioDevice::GetActualSampleRate() const +{ + Float64 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyActualSampleRate); + if(HasProperty(theAddress)) + { + UInt32 theSize = sizeof(Float64); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + else + { + theAnswer = GetNominalSampleRate(); + } + return theAnswer; +} + +Float64 CAHALAudioDevice::GetNominalSampleRate() const +{ + Float64 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyNominalSampleRate); + UInt32 theSize = sizeof(Float64); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetNominalSampleRate(Float64 inSampleRate) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyNominalSampleRate); + SetPropertyData(theAddress, 0, NULL, sizeof(Float64), &inSampleRate); +} + +UInt32 CAHALAudioDevice::GetNumberAvailableNominalSampleRateRanges() const +{ + UInt32 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyAvailableNominalSampleRates); + if(HasProperty(theAddress)) + { + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer = theSize / SizeOf32(AudioValueRange); + } + return theAnswer; +} + +void CAHALAudioDevice::GetAvailableNominalSampleRateRanges(UInt32& ioNumberRanges, AudioValueRange* outRanges) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyAvailableNominalSampleRates); + if(HasProperty(theAddress)) + { + UInt32 theSize = ioNumberRanges * SizeOf32(AudioValueRange); + GetPropertyData(theAddress, 0, NULL, theSize, outRanges); + ioNumberRanges = theSize / SizeOf32(AudioValueRange); + } + else + { + ioNumberRanges = 0; + } +} + +void CAHALAudioDevice::GetAvailableNominalSampleRateRangeByIndex(UInt32 inIndex, Float64& outMinimum, Float64& outMaximum) const +{ + UInt32 theNumberRanges = GetNumberAvailableNominalSampleRateRanges(); + ThrowIf(inIndex >= theNumberRanges, CAException(kAudioHardwareIllegalOperationError), "CAHALAudioDevice::GetAvailableNominalSampleRateRangeByIndex: index out of range"); + CAAutoArrayDelete theRanges(theNumberRanges); + GetAvailableNominalSampleRateRanges(theNumberRanges, theRanges); + outMinimum = theRanges[inIndex].mMinimum; + outMaximum = theRanges[inIndex].mMaximum; +} + +bool CAHALAudioDevice::IsValidNominalSampleRate(Float64 inSampleRate) const +{ + bool theAnswer = false; + UInt32 theNumberRanges = GetNumberAvailableNominalSampleRateRanges(); + CAAutoArrayDelete theRanges(theNumberRanges); + GetAvailableNominalSampleRateRanges(theNumberRanges, theRanges); + for(UInt32 theIndex = 0; !theAnswer && (theIndex < theNumberRanges); ++theIndex) + { + theAnswer = (inSampleRate >= theRanges[theIndex].mMinimum) && (inSampleRate <= theRanges[theIndex].mMinimum); + } + return theAnswer; +} + +bool CAHALAudioDevice::IsIOBufferSizeSettable() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSize); + return IsPropertySettable(theAddress); +} + +UInt32 CAHALAudioDevice::GetIOBufferSize() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSize); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +void CAHALAudioDevice::SetIOBufferSize(UInt32 inBufferSize) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSize); + SetPropertyData(theAddress, 0, NULL, sizeof(UInt32), &inBufferSize); +} + +bool CAHALAudioDevice::UsesVariableIOBufferSizes() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyUsesVariableBufferFrameSizes); + return HasProperty(theAddress); +} + +UInt32 CAHALAudioDevice::GetMaximumVariableIOBufferSize() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyUsesVariableBufferFrameSizes); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::HasIOBufferSizeRange() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSizeRange); + return HasProperty(theAddress); +} + +void CAHALAudioDevice::GetIOBufferSizeRange(UInt32& outMinimum, UInt32& outMaximum) const +{ + AudioValueRange theAnswer = { 0, 0 }; + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSizeRange); + UInt32 theSize = sizeof(AudioValueRange); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + outMinimum = static_cast(theAnswer.mMinimum); + outMaximum = static_cast(theAnswer.mMaximum); +} + +AudioDeviceIOProcID CAHALAudioDevice::CreateIOProcID(AudioDeviceIOProc inIOProc, void* inClientData) +{ + AudioDeviceIOProcID theAnswer = NULL; + OSStatus theError = AudioDeviceCreateIOProcID(mObjectID, inIOProc, inClientData, &theAnswer); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::CreateIOProcID: got an error creating the IOProc ID"); + return theAnswer; +} + +void CAHALAudioDevice::DestroyIOProcID(AudioDeviceIOProcID inIOProcID) +{ + OSStatus theError = AudioDeviceDestroyIOProcID(mObjectID, inIOProcID); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::DestroyIOProcID: got an error destroying the IOProc ID"); +} + +void CAHALAudioDevice::StartIOProc(AudioDeviceIOProcID inIOProcID) +{ + OSStatus theError = AudioDeviceStart(mObjectID, inIOProcID); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::StartIOProc: got an error starting an IOProc"); +} + +void CAHALAudioDevice::StartIOProcAtTime(AudioDeviceIOProcID inIOProcID, AudioTimeStamp& ioStartTime, bool inIsInput, bool inIgnoreHardware) +{ + UInt32 theFlags = 0; + if(inIsInput) + { + theFlags |= kAudioDeviceStartTimeIsInputFlag; + } + if(inIgnoreHardware) + { + theFlags |= kAudioDeviceStartTimeDontConsultDeviceFlag; + } + + OSStatus theError = AudioDeviceStartAtTime(mObjectID, inIOProcID, &ioStartTime, theFlags); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::StartIOProcAtTime: got an error starting an IOProc"); +} + +void CAHALAudioDevice::StopIOProc(AudioDeviceIOProcID inIOProcID) +{ + OSStatus theError = AudioDeviceStop(mObjectID, inIOProcID); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::StopIOProc: got an error stopping an IOProc"); +} + +void CAHALAudioDevice::GetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, bool* outStreamUsage) const +{ + // make an AudioHardwareIOProcStreamUsage the right size + UInt32 theNumberStreams = GetNumberStreams(inIsInput); + UInt32 theSize = SizeOf32(void*) + SizeOf32(UInt32) + (theNumberStreams * SizeOf32(UInt32)); + CAAutoFree theStreamUsage(theSize); + + // set it up + theStreamUsage->mIOProc = reinterpret_cast(inIOProcID); + theStreamUsage->mNumberStreams = theNumberStreams; + + // get the property + CAPropertyAddress theAddress(kAudioDevicePropertyIOProcStreamUsage, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + GetPropertyData(theAddress, 0, NULL, theSize, theStreamUsage); + + // fill out the return value + for(UInt32 theIndex = 0; theIndex < theNumberStreams; ++theIndex) + { + outStreamUsage[theIndex] = (theStreamUsage->mStreamIsOn[theIndex] != 0); + } +} + +void CAHALAudioDevice::SetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, const bool* inStreamUsage) +{ + // make an AudioHardwareIOProcStreamUsage the right size + UInt32 theNumberStreams = GetNumberStreams(inIsInput); + UInt32 theSize = SizeOf32(void*) + SizeOf32(UInt32) + (theNumberStreams * SizeOf32(UInt32)); + CAAutoFree theStreamUsage(theSize); + + // set it up + theStreamUsage->mIOProc = reinterpret_cast(inIOProcID); + theStreamUsage->mNumberStreams = theNumberStreams; + for(UInt32 theIndex = 0; theIndex < theNumberStreams; ++theIndex) + { + theStreamUsage->mStreamIsOn[theIndex] = (inStreamUsage[theIndex] ? 1 : 0); + } + + // set the property + CAPropertyAddress theAddress(kAudioDevicePropertyIOProcStreamUsage, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + SetPropertyData(theAddress, 0, NULL, theSize, theStreamUsage); +} + +Float32 CAHALAudioDevice::GetIOCycleUsage() const +{ + Float32 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyIOCycleUsage); + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetIOCycleUsage(Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyIOCycleUsage); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +void CAHALAudioDevice::GetCurrentTime(AudioTimeStamp& outTime) +{ + OSStatus theError = AudioDeviceGetCurrentTime(mObjectID, &outTime); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::GetCurrentTime: got an error getting the current time"); +} + +void CAHALAudioDevice::TranslateTime(const AudioTimeStamp& inTime, AudioTimeStamp& outTime) +{ + OSStatus theError = AudioDeviceTranslateTime(mObjectID, &inTime, &outTime); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::TranslateTime: got an error translating time"); +} + +void CAHALAudioDevice::GetNearestStartTime(AudioTimeStamp& ioTime, bool inIsInput, bool inIgnoreHardware) +{ + UInt32 theFlags = 0; + if(inIsInput) + { + theFlags |= kAudioDeviceStartTimeIsInputFlag; + } + if(inIgnoreHardware) + { + theFlags |= kAudioDeviceStartTimeDontConsultDeviceFlag; + } + + OSStatus theError = AudioDeviceGetNearestStartTime(mObjectID, &ioTime, theFlags); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::GetNearestStartTime: got an error getting the start time"); +} + +bool CAHALAudioDevice::HasVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalar, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::VolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalar, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +Float32 CAHALAudioDevice::GetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalar, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +Float32 CAHALAudioDevice::GetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeDecibels, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +void CAHALAudioDevice::SetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalar, inScope, inChannel); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +void CAHALAudioDevice::SetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeDecibels, inScope, inChannel); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +Float32 CAHALAudioDevice::GetVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeDecibelsToScalar, inScope, inChannel); + Float32 theValue = inValue; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +Float32 CAHALAudioDevice::GetVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalarToDecibels, inScope, inChannel); + Float32 theValue = inValue; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +bool CAHALAudioDevice::HasSubVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalar, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::SubVolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalar, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +Float32 CAHALAudioDevice::GetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalar, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +Float32 CAHALAudioDevice::GetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeDecibels, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +void CAHALAudioDevice::SetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalar, inScope, inChannel); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +void CAHALAudioDevice::SetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeDecibels, inScope, inChannel); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +Float32 CAHALAudioDevice::GetSubVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeDecibelsToScalar, inScope, inChannel); + Float32 theValue = inValue; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +Float32 CAHALAudioDevice::GetSubVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalarToDecibels, inScope, inChannel); + Float32 theValue = inValue; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +bool CAHALAudioDevice::HasMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyMute, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::MuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyMute, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +bool CAHALAudioDevice::GetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyMute, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +void CAHALAudioDevice::SetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyMute, inScope, inChannel); + UInt32 theValue = (inValue ? 1 : 0); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &theValue); +} + +bool CAHALAudioDevice::HasSoloControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySolo, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::SoloControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySolo, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +bool CAHALAudioDevice::GetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySolo, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +void CAHALAudioDevice::SetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertySolo, inScope, inChannel); + UInt32 theValue = (inValue ? 1 : 0); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &theValue); +} + +bool CAHALAudioDevice::HasStereoPanControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPan, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::StereoPanControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPan, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +Float32 CAHALAudioDevice::GetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPan, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +void CAHALAudioDevice::SetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPan, inScope, inChannel); + UInt32 theSize = sizeof(Float32); + SetPropertyData(theAddress, 0, NULL, theSize, &inValue); +} + +void CAHALAudioDevice::GetStereoPanControlChannels(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& outLeftChannel, UInt32& outRightChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPanChannels, inScope, inChannel); + UInt32 theValue[2] = { 0, 0 }; + UInt32 theSize = 2 * sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, theValue); + outLeftChannel = theValue[0]; + outRightChannel = theValue[1]; +} + +bool CAHALAudioDevice::HasJackControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyJackIsConnected, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::GetJackControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyJackIsConnected, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +bool CAHALAudioDevice::HasSubMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubMute, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::SubMuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubMute, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +bool CAHALAudioDevice::GetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubMute, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +void CAHALAudioDevice::SetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubMute, inScope, inChannel); + UInt32 theValue = (inValue ? 1 : 0); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &theValue); +} + +bool CAHALAudioDevice::HasiSubOwnerControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDriverShouldOwniSub, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::iSubOwnerControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDriverShouldOwniSub, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +bool CAHALAudioDevice::GetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDriverShouldOwniSub, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +void CAHALAudioDevice::SetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDriverShouldOwniSub, inScope, inChannel); + UInt32 theValue = (inValue ? 1 : 0); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &theValue); +} + +bool CAHALAudioDevice::HasDataSourceControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSource, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::DataSourceControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSource, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +UInt32 CAHALAudioDevice::GetCurrentDataSourceID(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSource, inScope, inChannel); + UInt32 theAnswer = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetCurrentDataSourceByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSource, inScope, inChannel); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &inID); +} + +UInt32 CAHALAudioDevice::GetNumberAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSources, inScope, inChannel); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer = theSize / SizeOf32(UInt32); + } + return theAnswer; +} + +void CAHALAudioDevice::GetAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberSources, UInt32* outSources) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSources, inScope, inChannel); + UInt32 theNumberSources = std::min(GetNumberAvailableDataSources(inScope, inChannel), ioNumberSources); + UInt32 theSize = theNumberSources * SizeOf32(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, outSources); + ioNumberSources = theSize / SizeOf32(UInt32); +} + +UInt32 CAHALAudioDevice::GetAvailableDataSourceByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const +{ + AudioStreamID theAnswer = 0; + UInt32 theNumberSources = GetNumberAvailableDataSources(inScope, inChannel); + if((theNumberSources > 0) && (inIndex < theNumberSources)) + { + CAAutoArrayDelete theSourceList(theNumberSources); + GetAvailableDataSources(inScope, inChannel, theNumberSources, theSourceList); + theAnswer = theSourceList[inIndex]; + } + return theAnswer; +} + +CFStringRef CAHALAudioDevice::CopyDataSourceNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSourceNameForIDCFString, inScope, inChannel); + CFStringRef theAnswer = NULL; + AudioValueTranslation theTranslation = { &inID, sizeof(UInt32), &theAnswer, sizeof(CFStringRef) }; + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theTranslation); + return theAnswer; +} + +bool CAHALAudioDevice::HasDataDestinationControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestination, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::DataDestinationControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestination, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +UInt32 CAHALAudioDevice::GetCurrentDataDestinationID(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestination, inScope, inChannel); + UInt32 theAnswer = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetCurrentDataDestinationByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestination, inScope, inChannel); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &inID); +} + +UInt32 CAHALAudioDevice::GetNumberAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestinations, inScope, inChannel); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer = theSize / SizeOf32(UInt32); + } + return theAnswer; +} + +void CAHALAudioDevice::GetAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberDestinations, UInt32* outDestinations) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestinations, inScope, inChannel); + UInt32 theNumberDestinations = std::min(GetNumberAvailableDataDestinations(inScope, inChannel), ioNumberDestinations); + UInt32 theSize = theNumberDestinations * SizeOf32(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, outDestinations); + ioNumberDestinations = theSize / SizeOf32(UInt32); +} + +UInt32 CAHALAudioDevice::GetAvailableDataDestinationByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const +{ + AudioStreamID theAnswer = 0; + UInt32 theNumberDestinations = GetNumberAvailableDataDestinations(inScope, inChannel); + if((theNumberDestinations > 0) && (inIndex < theNumberDestinations)) + { + CAAutoArrayDelete theDestinationList(theNumberDestinations); + GetAvailableDataDestinations(inScope, inChannel, theNumberDestinations, theDestinationList); + theAnswer = theDestinationList[inIndex]; + } + return theAnswer; +} + +CFStringRef CAHALAudioDevice::CopyDataDestinationNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestinationNameForIDCFString, inScope, inChannel); + CFStringRef theAnswer = NULL; + AudioValueTranslation theTranslation = { &inID, sizeof(UInt32), &theAnswer, sizeof(CFStringRef) }; + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theTranslation); + return theAnswer; +} + +bool CAHALAudioDevice::HasClockSourceControl() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSource); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::ClockSourceControlIsSettable() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSource); + return IsPropertySettable(theAddress); +} + +UInt32 CAHALAudioDevice::GetCurrentClockSourceID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSource); + UInt32 theAnswer = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetCurrentClockSourceByID(UInt32 inID) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSource); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &inID); +} + +UInt32 CAHALAudioDevice::GetNumberAvailableClockSources() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSources); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer = theSize / SizeOf32(UInt32); + } + return theAnswer; +} + +void CAHALAudioDevice::GetAvailableClockSources(UInt32& ioNumberSources, UInt32* outSources) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSources); + UInt32 theNumberSources = std::min(GetNumberAvailableClockSources(), ioNumberSources); + UInt32 theSize = theNumberSources * SizeOf32(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, outSources); + ioNumberSources = theSize / SizeOf32(UInt32); +} + +UInt32 CAHALAudioDevice::GetAvailableClockSourceByIndex(UInt32 inIndex) const +{ + AudioStreamID theAnswer = 0; + UInt32 theNumberSources = GetNumberAvailableClockSources(); + if((theNumberSources > 0) && (inIndex < theNumberSources)) + { + CAAutoArrayDelete theSourceList(theNumberSources); + GetAvailableClockSources(theNumberSources, theSourceList); + theAnswer = theSourceList[inIndex]; + } + return theAnswer; +} + +CFStringRef CAHALAudioDevice::CopyClockSourceNameForID(UInt32 inID) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSourceNameForIDCFString); + CFStringRef theAnswer = NULL; + AudioValueTranslation theTranslation = { &inID, sizeof(UInt32), &theAnswer, sizeof(CFStringRef) }; + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theTranslation); + return theAnswer; +} + +UInt32 CAHALAudioDevice::GetClockSourceKindForID(UInt32 inID) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSourceKindForID); + UInt32 theAnswer = 0; + AudioValueTranslation theTranslation = { &inID, sizeof(UInt32), &theAnswer, sizeof(UInt32) }; + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theTranslation); + return theAnswer; +} diff --git a/app/PublicUtility/CAHALAudioDevice.h b/app/PublicUtility/CAHALAudioDevice.h new file mode 100644 index 0000000..8cfb466 --- /dev/null +++ b/app/PublicUtility/CAHALAudioDevice.h @@ -0,0 +1,238 @@ +/* + File: CAHALAudioDevice.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAHALAudioDevice_h__) +#define __CAHALAudioDevice_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// Super Class Includes +#include "CAHALAudioObject.h" + +// PublicUtility Includes +#include "CADebugMacros.h" +#include "CAException.h" + +//================================================================================================== +// CAHALAudioDevice +//================================================================================================== + +class CAHALAudioDevice +: + public CAHALAudioObject +{ + +// Construction/Destruction +public: + CAHALAudioDevice(AudioObjectID inAudioDevice); + CAHALAudioDevice(CFStringRef inUID); + virtual ~CAHALAudioDevice(); + +// General Stuff +public: + CFStringRef CopyDeviceUID() const; + bool HasModelUID() const; + CFStringRef CopyModelUID() const; + CFStringRef CopyConfigurationApplicationBundleID() const; + CFURLRef CopyIconLocation() const; + UInt32 GetTransportType() const; + bool CanBeDefaultDevice(bool inIsInput, bool inIsSystem) const; + bool HasDevicePlugInStatus() const; + OSStatus GetDevicePlugInStatus() const; + bool IsAlive() const; + bool IsHidden() const; + pid_t GetHogModeOwner() const; + bool IsHogModeSettable() const; + bool TakeHogMode(); + void ReleaseHogMode(); + bool HasPreferredStereoChannels(bool inIsInput) const; + void GetPreferredStereoChannels(bool inIsInput, UInt32& outLeft, UInt32& outRight) const; + void SetPreferredStereoChannels(bool inIsInput, UInt32 inLeft, UInt32 inRight); + bool HasPreferredChannelLayout(bool inIsInput) const; + void GetPreferredChannelLayout(bool inIsInput, AudioChannelLayout& outChannelLayout) const; + void SetPreferredStereoChannels(bool inIsInput, AudioChannelLayout& inChannelLayout); + UInt32 GetNumberRelatedAudioDevices() const; + void GetRelatedAudioDevices(UInt32& ioNumberRelatedDevices, AudioObjectID* outRelatedDevices) const; + AudioObjectID GetRelatedAudioDeviceByIndex(UInt32 inIndex) const; + +// Stream Stuff +public: + UInt32 GetNumberStreams(bool inIsInput) const; + void GetStreams(bool inIsInput, UInt32& ioNumberStreams, AudioObjectID* outStreamList) const; + AudioObjectID GetStreamByIndex(bool inIsInput, UInt32 inIndex) const; + UInt32 GetTotalNumberChannels(bool inIsInput) const; + void GetCurrentVirtualFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const; + void GetCurrentPhysicalFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const; + +// IO Stuff +public: + bool IsRunning() const; + bool IsRunningSomewhere() const; + UInt32 GetLatency(bool inIsInput) const; + UInt32 GetSafetyOffset(bool inIsInput) const; + bool HasClockDomain() const; + UInt32 GetClockDomain() const; + Float64 GetActualSampleRate() const; + Float64 GetNominalSampleRate() const; + void SetNominalSampleRate(Float64 inSampleRate); + UInt32 GetNumberAvailableNominalSampleRateRanges() const; + void GetAvailableNominalSampleRateRanges(UInt32& ioNumberRanges, AudioValueRange* outRanges) const; + void GetAvailableNominalSampleRateRangeByIndex(UInt32 inIndex, Float64& outMinimum, Float64& outMaximum) const; + bool IsValidNominalSampleRate(Float64 inSampleRate) const; + bool IsIOBufferSizeSettable() const; + UInt32 GetIOBufferSize() const; + void SetIOBufferSize(UInt32 inBufferSize); + bool UsesVariableIOBufferSizes() const; + UInt32 GetMaximumVariableIOBufferSize() const; + bool HasIOBufferSizeRange() const; + void GetIOBufferSizeRange(UInt32& outMinimum, UInt32& outMaximum) const; + AudioDeviceIOProcID CreateIOProcID(AudioDeviceIOProc inIOProc, void* inClientData); + AudioDeviceIOProcID CreateIOProcIDWithBlock(dispatch_queue_t inDispatchQueue, AudioDeviceIOBlock inIOBlock); + void DestroyIOProcID(AudioDeviceIOProcID inIOProcID); + void StartIOProc(AudioDeviceIOProcID inIOProcID); + void StartIOProcAtTime(AudioDeviceIOProcID inIOProcID, AudioTimeStamp& ioStartTime, bool inIsInput, bool inIgnoreHardware); + void StopIOProc(AudioDeviceIOProcID inIOProcID); + void GetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, bool* outStreamUsage) const; + void SetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, const bool* inStreamUsage); + Float32 GetIOCycleUsage() const; + void SetIOCycleUsage(Float32 inValue); + +// Time Operations +public: + void GetCurrentTime(AudioTimeStamp& outTime); + void TranslateTime(const AudioTimeStamp& inTime, AudioTimeStamp& outTime); + void GetNearestStartTime(AudioTimeStamp& ioTime, bool inIsInput, bool inIgnoreHardware); + +// Controls +public: + bool HasVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool VolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + void SetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + Float32 GetVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const; + Float32 GetVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const; + + bool HasSubVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool SubVolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + void SetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + Float32 GetSubVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const; + Float32 GetSubVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const; + + bool HasMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool MuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue); + + bool HasSoloControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool SoloControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue); + + bool HasStereoPanControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool StereoPanControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + void GetStereoPanControlChannels(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& outLeftChannel, UInt32& outRightChannel) const; + + bool HasJackControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetJackControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + + bool HasSubMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool SubMuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue); + + bool HasiSubOwnerControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool iSubOwnerControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue); + + bool HasDataSourceControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool DataSourceControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + UInt32 GetCurrentDataSourceID(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetCurrentDataSourceByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID); + UInt32 GetNumberAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void GetAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberSources, UInt32* outSources) const; + UInt32 GetAvailableDataSourceByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const; + CFStringRef CopyDataSourceNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const; + + bool HasDataDestinationControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool DataDestinationControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + UInt32 GetCurrentDataDestinationID(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetCurrentDataDestinationByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID); + UInt32 GetNumberAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void GetAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberDestinations, UInt32* outDestinations) const; + UInt32 GetAvailableDataDestinationByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const; + CFStringRef CopyDataDestinationNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const; + + bool HasClockSourceControl() const; + bool ClockSourceControlIsSettable() const; + UInt32 GetCurrentClockSourceID() const; + void SetCurrentClockSourceByID(UInt32 inID); + UInt32 GetNumberAvailableClockSources() const; + void GetAvailableClockSources(UInt32& ioNumberSources, UInt32* outSources) const; + UInt32 GetAvailableClockSourceByIndex(UInt32 inIndex) const; + CFStringRef CopyClockSourceNameForID(UInt32 inID) const; + UInt32 GetClockSourceKindForID(UInt32 inID) const; + +}; + +inline AudioDeviceIOProcID CAHALAudioDevice::CreateIOProcIDWithBlock(dispatch_queue_t inDispatchQueue, AudioDeviceIOBlock inIOBlock) +{ + AudioDeviceIOProcID theAnswer = NULL; + OSStatus theError = AudioDeviceCreateIOProcIDWithBlock(&theAnswer, mObjectID, inDispatchQueue, inIOBlock); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::CreateIOProcIDWithBlock: got an error creating the IOProc ID"); + return theAnswer; +} + +#endif diff --git a/app/PublicUtility/CAHALAudioObject.cpp b/app/PublicUtility/CAHALAudioObject.cpp new file mode 100644 index 0000000..99d30ff --- /dev/null +++ b/app/PublicUtility/CAHALAudioObject.cpp @@ -0,0 +1,373 @@ +/* + File: CAHALAudioObject.cpp + Abstract: CAHALAudioObject.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAHALAudioObject.h" + +// PublicUtility Includes +#include "CAAutoDisposer.h" +#include "CADebugMacros.h" +#include "CAException.h" +#include "CAPropertyAddress.h" + +//================================================================================================== +// CAHALAudioObject +//================================================================================================== + +CAHALAudioObject::CAHALAudioObject(AudioObjectID inObjectID) +: + mObjectID(inObjectID) +{ +} + +CAHALAudioObject::~CAHALAudioObject() +{ +} + +AudioObjectID CAHALAudioObject::GetObjectID() const +{ + return mObjectID; +} + +void CAHALAudioObject::SetObjectID(AudioObjectID inObjectID) +{ + mObjectID = inObjectID; +} + +AudioClassID CAHALAudioObject::GetClassID() const +{ + // set up the return value + AudioClassID theAnswer = 0; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyClass); + + // make sure the property exists + if(HasProperty(theAddress)) + { + UInt32 theSize = sizeof(AudioClassID); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +AudioObjectID CAHALAudioObject::GetOwnerObjectID() const +{ + // set up the return value + AudioObjectID theAnswer = 0; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyOwner); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyOwningPlugInBundleID() const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyCreator); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyName() const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyName); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyManufacturer() const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyManufacturer); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyElementName, inScope, inElement); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyCategoryNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyElementCategoryName, inScope, inElement); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyNumberNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyElementNumberName, inScope, inElement); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +bool CAHALAudioObject::ObjectExists(AudioObjectID inObjectID) +{ + Boolean isSettable; + CAPropertyAddress theAddress(kAudioObjectPropertyClass); + // VC edit: Negated the expression returned. Seems to have been a bug. + //return (inObjectID == 0) || (AudioObjectIsPropertySettable(inObjectID, &theAddress, &isSettable) != 0); + return (inObjectID != kAudioObjectUnknown) && (AudioObjectIsPropertySettable(inObjectID, &theAddress, &isSettable) == kAudioHardwareNoError); + // VC edit end +} + +UInt32 CAHALAudioObject::GetNumberOwnedObjects(AudioClassID inClass) const +{ + // set up the return value + UInt32 theAnswer = 0; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyOwnedObjects); + + // figure out the qualifier + UInt32 theQualifierSize = 0; + void* theQualifierData = NULL; + if(inClass != 0) + { + theQualifierSize = sizeof(AudioObjectID); + theQualifierData = &inClass; + } + + // get the property data size + theAnswer = GetPropertyDataSize(theAddress, theQualifierSize, theQualifierData); + + // calculate the number of object IDs + theAnswer /= SizeOf32(AudioObjectID); + + return theAnswer; +} + +void CAHALAudioObject::GetAllOwnedObjects(AudioClassID inClass, UInt32& ioNumberObjects, AudioObjectID* ioObjectIDs) const +{ + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyOwnedObjects); + + // figure out the qualifier + UInt32 theQualifierSize = 0; + void* theQualifierData = NULL; + if(inClass != 0) + { + theQualifierSize = sizeof(AudioObjectID); + theQualifierData = &inClass; + } + + // get the property data + UInt32 theDataSize = ioNumberObjects * SizeOf32(AudioClassID); + GetPropertyData(theAddress, theQualifierSize, theQualifierData, theDataSize, ioObjectIDs); + + // set the number of object IDs being returned + ioNumberObjects = theDataSize / SizeOf32(AudioObjectID); +} + +AudioObjectID CAHALAudioObject::GetOwnedObjectByIndex(AudioClassID inClass, UInt32 inIndex) +{ + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyOwnedObjects); + + // figure out the qualifier + UInt32 theQualifierSize = 0; + void* theQualifierData = NULL; + if(inClass != 0) + { + theQualifierSize = sizeof(AudioObjectID); + theQualifierData = &inClass; + } + + // figure out how much space to allocate + UInt32 theDataSize = GetPropertyDataSize(theAddress, theQualifierSize, theQualifierData); + UInt32 theNumberObjectIDs = theDataSize / SizeOf32(AudioObjectID); + + // set up the return value + AudioObjectID theAnswer = 0; + + // maker sure the index is in range + if(inIndex < theNumberObjectIDs) + { + // allocate it + CAAutoArrayDelete theObjectList(theDataSize / sizeof(AudioObjectID)); + + // get the property data + GetPropertyData(theAddress, theQualifierSize, theQualifierData, theDataSize, theObjectList); + + // get the return value + theAnswer = theObjectList[inIndex]; + } + + return theAnswer; +} + +bool CAHALAudioObject::HasProperty(const AudioObjectPropertyAddress& inAddress) const +{ + return AudioObjectHasProperty(mObjectID, &inAddress); +} + +bool CAHALAudioObject::IsPropertySettable(const AudioObjectPropertyAddress& inAddress) const +{ + Boolean isSettable = false; + OSStatus theError = AudioObjectIsPropertySettable(mObjectID, &inAddress, &isSettable); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::IsPropertySettable: got an error getting info about a property"); + return isSettable != 0; +} + +UInt32 CAHALAudioObject::GetPropertyDataSize(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData) const +{ + UInt32 theDataSize = 0; + OSStatus theError = AudioObjectGetPropertyDataSize(mObjectID, &inAddress, inQualifierDataSize, inQualifierData, &theDataSize); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::GetPropertyDataSize: got an error getting the property data size"); + return theDataSize; +} + +void CAHALAudioObject::GetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32& ioDataSize, void* outData) const +{ + OSStatus theError = AudioObjectGetPropertyData(mObjectID, &inAddress, inQualifierDataSize, inQualifierData, &ioDataSize, outData); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::GetPropertyData: got an error getting the property data"); +} + +void CAHALAudioObject::SetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData) +{ + OSStatus theError = AudioObjectSetPropertyData(mObjectID, &inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::SetPropertyData: got an error setting the property data"); +} + +void CAHALAudioObject::AddPropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData) +{ + OSStatus theError = AudioObjectAddPropertyListener(mObjectID, &inAddress, inListenerProc, inClientData); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::AddPropertyListener: got an error adding a property listener"); +} + +void CAHALAudioObject::RemovePropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData) +{ + OSStatus theError = AudioObjectRemovePropertyListener(mObjectID, &inAddress, inListenerProc, inClientData); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::RemovePropertyListener: got an error removing a property listener"); +} diff --git a/app/PublicUtility/CAHALAudioObject.h b/app/PublicUtility/CAHALAudioObject.h new file mode 100644 index 0000000..d99ab0d --- /dev/null +++ b/app/PublicUtility/CAHALAudioObject.h @@ -0,0 +1,155 @@ +/* + File: CAHALAudioObject.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAHALAudioObject_h__) +#define __CAHALAudioObject_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// PublicUtility Includes +#include "CADebugMacros.h" +#include "CAException.h" + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +//================================================================================================== +// CAHALAudioObject +//================================================================================================== + +class CAHALAudioObject +{ + +// Construction/Destruction +public: + CAHALAudioObject(AudioObjectID inObjectID); + virtual ~CAHALAudioObject(); + +// Attributes +public: + AudioObjectID GetObjectID() const; + void SetObjectID(AudioObjectID inObjectID); + AudioClassID GetClassID() const; + AudioObjectID GetOwnerObjectID() const; + CFStringRef CopyOwningPlugInBundleID() const; + CFStringRef CopyName() const; + CFStringRef CopyManufacturer() const; + CFStringRef CopyNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const; + CFStringRef CopyCategoryNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const; + CFStringRef CopyNumberNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const; + + static bool ObjectExists(AudioObjectID inObjectID); + +// Owned Objects +public: + UInt32 GetNumberOwnedObjects(AudioClassID inClass) const; + void GetAllOwnedObjects(AudioClassID inClass, UInt32& ioNumberObjects, AudioObjectID* ioObjectIDs) const; + AudioObjectID GetOwnedObjectByIndex(AudioClassID inClass, UInt32 inIndex); + +// Property Operations +public: + bool HasProperty(const AudioObjectPropertyAddress& inAddress) const; + bool IsPropertySettable(const AudioObjectPropertyAddress& inAddress) const; + UInt32 GetPropertyDataSize(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData) const; + + void GetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32& ioDataSize, void* outData) const; + void SetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData); + + UInt32 GetPropertyData_UInt32(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { UInt32 theAnswer = 0; UInt32 theDataSize = SizeOf32(UInt32); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_UInt32(const AudioObjectPropertyAddress& inAddress, UInt32 inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(UInt32), &inValue); } + + Float32 GetPropertyData_Float32(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { Float32 theAnswer = 0; UInt32 theDataSize = SizeOf32(Float32); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_Float32(const AudioObjectPropertyAddress& inAddress, Float32 inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(Float32), &inValue); } + + Float64 GetPropertyData_Float64(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { Float64 theAnswer = 0; UInt32 theDataSize = SizeOf32(Float64); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_Float64(const AudioObjectPropertyAddress& inAddress, Float64 inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(Float64), &inValue); } + + CFTypeRef GetPropertyData_CFType(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { CFTypeRef theAnswer = NULL; UInt32 theDataSize = SizeOf32(CFTypeRef); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_CFType(const AudioObjectPropertyAddress& inAddress, CFTypeRef inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(CFTypeRef), &inValue); } + + CFStringRef GetPropertyData_CFString(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { CFStringRef theAnswer = NULL; UInt32 theDataSize = SizeOf32(CFStringRef); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_CFString(const AudioObjectPropertyAddress& inAddress, CFStringRef inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(CFStringRef), &inValue); } + + template void GetPropertyData_Struct(const AudioObjectPropertyAddress& inAddress, T& outStruct, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { UInt32 theDataSize = SizeOf32(T); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &outStruct); } + template void SetPropertyData_Struct(const AudioObjectPropertyAddress& inAddress, T& inStruct, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(T), &inStruct); } + + template UInt32 GetPropertyData_ArraySize(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { return GetPropertyDataSize(inAddress, inQualifierDataSize, inQualifierData) / SizeOf32(T); } + template void GetPropertyData_Array(const AudioObjectPropertyAddress& inAddress, UInt32& ioNumberItems, T* outArray, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { UInt32 theDataSize = ioNumberItems * SizeOf32(T); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, outArray); ioNumberItems = theDataSize / SizeOf32(T); } + template void SetPropertyData_Array(const AudioObjectPropertyAddress& inAddress, UInt32 inNumberItems, T* inArray, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, inNumberItems * SizeOf32(T), inArray); } + + void AddPropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData); + void RemovePropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData); + + void AddPropertyListenerBlock(const AudioObjectPropertyAddress& inAddress, dispatch_queue_t inDispatchQueue, AudioObjectPropertyListenerBlock inListenerBlock); + void RemovePropertyListenerBlock(const AudioObjectPropertyAddress& inAddress, dispatch_queue_t inDispatchQueue, AudioObjectPropertyListenerBlock inListenerBlock); + +// Implementation +protected: + AudioObjectID mObjectID; + +}; + +inline void CAHALAudioObject::AddPropertyListenerBlock(const AudioObjectPropertyAddress& inAddress, dispatch_queue_t inDispatchQueue, AudioObjectPropertyListenerBlock inListenerBlock) +{ + OSStatus theError = AudioObjectAddPropertyListenerBlock(mObjectID, &inAddress, inDispatchQueue, inListenerBlock); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::AddPropertyListenerBlock: got an error adding a property listener"); +} + +inline void CAHALAudioObject::RemovePropertyListenerBlock(const AudioObjectPropertyAddress& inAddress, dispatch_queue_t inDispatchQueue, AudioObjectPropertyListenerBlock inListenerBlock) +{ + OSStatus theError = AudioObjectRemovePropertyListenerBlock(mObjectID, &inAddress, inDispatchQueue, inListenerBlock); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::RemovePropertyListener: got an error removing a property listener"); +} + +#endif diff --git a/app/PublicUtility/CAHALAudioStream.cpp b/app/PublicUtility/CAHALAudioStream.cpp new file mode 100644 index 0000000..62b9b3c --- /dev/null +++ b/app/PublicUtility/CAHALAudioStream.cpp @@ -0,0 +1,182 @@ +/* + File: CAHALAudioStream.cpp + Abstract: CAHALAudioStream.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAHALAudioStream.h" + +// PublicUtility Includes +#include "CAAutoDisposer.h" +#include "CADebugMacros.h" +#include "CAException.h" +#include "CAPropertyAddress.h" + +//================================================================================================== +// CAHALAudioStream +//================================================================================================== + +CAHALAudioStream::CAHALAudioStream(AudioObjectID inAudioStream) +: + CAHALAudioObject(inAudioStream) +{ +} + +CAHALAudioStream::~CAHALAudioStream() +{ +} + +UInt32 CAHALAudioStream::GetDirection() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyDirection); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +UInt32 CAHALAudioStream::GetTerminalType() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyTerminalType); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +UInt32 CAHALAudioStream::GetStartingChannel() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyStartingChannel); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +UInt32 CAHALAudioStream::GetLatency() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyLatency); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +void CAHALAudioStream::GetCurrentVirtualFormat(AudioStreamBasicDescription& outFormat) const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyVirtualFormat); + UInt32 theSize = sizeof(AudioStreamBasicDescription); + GetPropertyData(theAddress, 0, NULL, theSize, &outFormat); +} + +void CAHALAudioStream::SetCurrentVirtualFormat(const AudioStreamBasicDescription& inFormat) +{ + CAPropertyAddress theAddress(kAudioStreamPropertyVirtualFormat); + SetPropertyData(theAddress, 0, NULL, sizeof(AudioStreamBasicDescription), &inFormat); +} + +UInt32 CAHALAudioStream::GetNumberAvailableVirtualFormats() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyAvailableVirtualFormats); + UInt32 theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= SizeOf32(AudioStreamRangedDescription); + return theAnswer; +} + +void CAHALAudioStream::GetAvailableVirtualFormats(UInt32& ioNumberFormats, AudioStreamRangedDescription* outFormats) const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyAvailableVirtualFormats); + UInt32 theSize = ioNumberFormats * SizeOf32(AudioStreamRangedDescription); + GetPropertyData(theAddress, 0, NULL, theSize, outFormats); + ioNumberFormats = theSize / SizeOf32(AudioStreamRangedDescription); +} + +void CAHALAudioStream::GetAvailableVirtualFormatByIndex(UInt32 inIndex, AudioStreamRangedDescription& outFormat) const +{ + UInt32 theNumberFormats = GetNumberAvailableVirtualFormats(); + if((theNumberFormats > 0) && (inIndex < theNumberFormats)) + { + CAAutoArrayDelete theFormats(theNumberFormats); + GetAvailableVirtualFormats(theNumberFormats, theFormats); + if((theNumberFormats > 0) && (inIndex < theNumberFormats)) + { + outFormat = theFormats[inIndex]; + } + } +} + +void CAHALAudioStream::GetCurrentPhysicalFormat(AudioStreamBasicDescription& outFormat) const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyPhysicalFormat); + UInt32 theSize = sizeof(AudioStreamBasicDescription); + GetPropertyData(theAddress, 0, NULL, theSize, &outFormat); +} + +void CAHALAudioStream::SetCurrentPhysicalFormat(const AudioStreamBasicDescription& inFormat) +{ + CAPropertyAddress theAddress(kAudioStreamPropertyPhysicalFormat); + SetPropertyData(theAddress, 0, NULL, sizeof(AudioStreamBasicDescription), &inFormat); +} + +UInt32 CAHALAudioStream::GetNumberAvailablePhysicalFormats() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyAvailablePhysicalFormats); + UInt32 theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= SizeOf32(AudioStreamRangedDescription); + return theAnswer; +} + +void CAHALAudioStream::GetAvailablePhysicalFormats(UInt32& ioNumberFormats, AudioStreamRangedDescription* outFormats) const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyAvailablePhysicalFormats); + UInt32 theSize = ioNumberFormats * SizeOf32(AudioStreamRangedDescription); + GetPropertyData(theAddress, 0, NULL, theSize, outFormats); + ioNumberFormats = theSize / SizeOf32(AudioStreamRangedDescription); +} + +void CAHALAudioStream::GetAvailablePhysicalFormatByIndex(UInt32 inIndex, AudioStreamRangedDescription& outFormat) const +{ + UInt32 theNumberFormats = GetNumberAvailablePhysicalFormats(); + if((theNumberFormats > 0) && (inIndex < theNumberFormats)) + { + CAAutoArrayDelete theFormats(theNumberFormats); + GetAvailablePhysicalFormats(theNumberFormats, theFormats); + if((theNumberFormats > 0) && (inIndex < theNumberFormats)) + { + outFormat = theFormats[inIndex]; + } + } +} diff --git a/app/PublicUtility/CAHALAudioStream.h b/app/PublicUtility/CAHALAudioStream.h new file mode 100644 index 0000000..0c6cb55 --- /dev/null +++ b/app/PublicUtility/CAHALAudioStream.h @@ -0,0 +1,94 @@ +/* + File: CAHALAudioStream.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAHALAudioStream_h__) +#define __CAHALAudioStream_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// Super Class Includes +#include "CAHALAudioObject.h" + +//================================================================================================== +// CAHALAudioStream +//================================================================================================== + +class CAHALAudioStream +: + public CAHALAudioObject +{ + +// Construction/Destruction +public: + CAHALAudioStream(AudioObjectID inAudioStream); + virtual ~CAHALAudioStream(); + +// Attributes +public: + UInt32 GetDirection() const; + UInt32 GetTerminalType() const; + UInt32 GetStartingChannel() const; + UInt32 GetLatency() const; + +// Format Info +public: + void GetCurrentVirtualFormat(AudioStreamBasicDescription& outFormat) const; + void SetCurrentVirtualFormat(const AudioStreamBasicDescription& inFormat); + UInt32 GetNumberAvailableVirtualFormats() const; + void GetAvailableVirtualFormats(UInt32& ioNumberFormats, AudioStreamRangedDescription* outFormats) const; + void GetAvailableVirtualFormatByIndex(UInt32 inIndex, AudioStreamRangedDescription& outFormat) const; + + void GetCurrentPhysicalFormat(AudioStreamBasicDescription& outFormat) const; + void SetCurrentPhysicalFormat(const AudioStreamBasicDescription& inFormat); + UInt32 GetNumberAvailablePhysicalFormats() const; + void GetAvailablePhysicalFormats(UInt32& ioNumberFormats, AudioStreamRangedDescription* outFormats) const; + void GetAvailablePhysicalFormatByIndex(UInt32 inIndex, AudioStreamRangedDescription& outFormat) const; + +}; + +#endif diff --git a/app/PublicUtility/CAHALAudioSystemObject.cpp b/app/PublicUtility/CAHALAudioSystemObject.cpp new file mode 100644 index 0000000..404dd98 --- /dev/null +++ b/app/PublicUtility/CAHALAudioSystemObject.cpp @@ -0,0 +1,181 @@ +/* + File: CAHALAudioSystemObject.cpp + Abstract: CAHALAudioSystemObject.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAHALAudioSystemObject.h" + +// PublicUtility Includes +#include "CAAutoDisposer.h" +#include "CACFString.h" +#include "CAHALAudioDevice.h" +#include "CAPropertyAddress.h" + +//================================================================================================== +// CAHALAudioSystemObject +//================================================================================================== + +CAHALAudioSystemObject::CAHALAudioSystemObject() +: + CAHALAudioObject(kAudioObjectSystemObject) +{ +} + +CAHALAudioSystemObject::~CAHALAudioSystemObject() +{ +} + +UInt32 CAHALAudioSystemObject::GetNumberAudioDevices() const +{ + CAPropertyAddress theAddress(kAudioHardwarePropertyDevices); + UInt32 theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= SizeOf32(AudioObjectID); + return theAnswer; +} + +void CAHALAudioSystemObject::GetAudioDevices(UInt32& ioNumberAudioDevices, AudioObjectID* outAudioDevices) const +{ + CAPropertyAddress theAddress(kAudioHardwarePropertyDevices); + UInt32 theSize = ioNumberAudioDevices * SizeOf32(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, outAudioDevices); + ioNumberAudioDevices = theSize / SizeOf32(AudioObjectID); +} + +AudioObjectID CAHALAudioSystemObject::GetAudioDeviceAtIndex(UInt32 inIndex) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + UInt32 theNumberDevices = GetNumberAudioDevices(); + if((theNumberDevices > 0) && (inIndex < theNumberDevices)) + { + CAAutoArrayDelete theDeviceList(theNumberDevices); + GetAudioDevices(theNumberDevices, theDeviceList); + if((theNumberDevices > 0) && (inIndex < theNumberDevices)) + { + theAnswer = theDeviceList[inIndex]; + } + } + return theAnswer; +} + +AudioObjectID CAHALAudioSystemObject::GetAudioDeviceForUID(CFStringRef inUID) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + AudioValueTranslation theValue = { &inUID, sizeof(CFStringRef), &theAnswer, sizeof(AudioObjectID) }; + CAPropertyAddress theAddress(kAudioHardwarePropertyDeviceForUID); + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theAnswer; +} + +void CAHALAudioSystemObject::LogBasicDeviceInfo() +{ + UInt32 theNumberDevices = GetNumberAudioDevices(); + CAAutoArrayDelete theDeviceList(theNumberDevices); + GetAudioDevices(theNumberDevices, theDeviceList); + DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo: %d devices", (int)theNumberDevices); + for(UInt32 theDeviceIndex = 0; theDeviceIndex < theNumberDevices; ++theDeviceIndex) + { + char theCString[256]; + UInt32 theCStringSize = sizeof(theCString); + DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo: Device %d", (int)theDeviceIndex); + + CAHALAudioDevice theDevice(theDeviceList[theDeviceIndex]); + DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo: Object ID: %d", (int)theDeviceList[theDeviceIndex]); + + CACFString theDeviceName(theDevice.CopyName()); + theCStringSize = sizeof(theCString); + theDeviceName.GetCString(theCString, theCStringSize); + DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo: Name: %s", theCString); + + CACFString theDeviceUID(theDevice.CopyDeviceUID()); + theCStringSize = sizeof(theCString); + theDeviceUID.GetCString(theCString, theCStringSize); + DebugMessageN1("CAHALAudioSystemObject::LogBasicDeviceInfo: UID: %s", theCString); + } +} + +static inline AudioObjectPropertySelector CAHALAudioSystemObject_CalculateDefaultDeviceProperySelector(bool inIsInput, bool inIsSystem) +{ + AudioObjectPropertySelector theAnswer = kAudioHardwarePropertyDefaultOutputDevice; + if(inIsInput) + { + theAnswer = kAudioHardwarePropertyDefaultInputDevice; + } + else if(inIsSystem) + { + theAnswer = kAudioHardwarePropertyDefaultSystemOutputDevice; + } + return theAnswer; +} + +AudioObjectID CAHALAudioSystemObject::GetDefaultAudioDevice(bool inIsInput, bool inIsSystem) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + CAPropertyAddress theAddress(CAHALAudioSystemObject_CalculateDefaultDeviceProperySelector(inIsInput, inIsSystem)); + UInt32 theSize = sizeof(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioSystemObject::SetDefaultAudioDevice(bool inIsInput, bool inIsSystem, AudioObjectID inNewDefaultDevice) +{ + CAPropertyAddress theAddress(CAHALAudioSystemObject_CalculateDefaultDeviceProperySelector(inIsInput, inIsSystem)); + UInt32 theSize = sizeof(AudioObjectID); + SetPropertyData(theAddress, 0, NULL, theSize, &inNewDefaultDevice); +} + +AudioObjectID CAHALAudioSystemObject::GetAudioPlugInForBundleID(CFStringRef inUID) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + AudioValueTranslation theValue = { &inUID, sizeof(CFStringRef), &theAnswer, sizeof(AudioObjectID) }; + CAPropertyAddress theAddress(kAudioHardwarePropertyPlugInForBundleID); + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theAnswer; +} diff --git a/app/PublicUtility/CAHALAudioSystemObject.h b/app/PublicUtility/CAHALAudioSystemObject.h new file mode 100644 index 0000000..0ade7a5 --- /dev/null +++ b/app/PublicUtility/CAHALAudioSystemObject.h @@ -0,0 +1,90 @@ +/* + File: CAHALAudioSystemObject.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAHALAudioSystemObject_h__) +#define __CAHALAudioSystemObject_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// Super Class Includes +#include "CAHALAudioObject.h" + +//================================================================================================== +// CAHALAudioSystemObject +//================================================================================================== + +class CAHALAudioSystemObject +: + public CAHALAudioObject +{ + +// Construction/Destruction +public: + CAHALAudioSystemObject(); + virtual ~CAHALAudioSystemObject(); + +// Audio Device List Management +public: + UInt32 GetNumberAudioDevices() const; + void GetAudioDevices(UInt32& ioNumberAudioDevices, AudioObjectID* outAudioDevices) const; + AudioObjectID GetAudioDeviceAtIndex(UInt32 inIndex) const; + AudioObjectID GetAudioDeviceForUID(CFStringRef inUID) const; + void LogBasicDeviceInfo(); + +// Default Device Management +public: + AudioObjectID GetDefaultAudioDevice(bool inIsInput, bool inIsSystem) const; + void SetDefaultAudioDevice(bool inIsInput, bool inIsSystem, AudioObjectID inNewDefaultDevice); + +// PlugIns +public: + AudioObjectID GetAudioPlugInForBundleID(CFStringRef inBundleID) const; + +}; + +#endif diff --git a/app/PublicUtility/CAHostTimeBase.cpp b/app/PublicUtility/CAHostTimeBase.cpp new file mode 100644 index 0000000..db78a4a --- /dev/null +++ b/app/PublicUtility/CAHostTimeBase.cpp @@ -0,0 +1,99 @@ +/* + File: CAHostTimeBase.cpp + Abstract: CAHostTimeBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CAHostTimeBase.h" + +Float64 CAHostTimeBase::sFrequency = 0; +Float64 CAHostTimeBase::sInverseFrequency = 0; +UInt32 CAHostTimeBase::sMinDelta = 0; +UInt32 CAHostTimeBase::sToNanosNumerator = 0; +UInt32 CAHostTimeBase::sToNanosDenominator = 0; +pthread_once_t CAHostTimeBase::sIsInited = PTHREAD_ONCE_INIT; +#if Track_Host_TimeBase +UInt64 CAHostTimeBase::sLastTime = 0; +#endif + +//============================================================================= +// CAHostTimeBase +// +// This class provides platform independent access to the host's time base. +//============================================================================= + +void CAHostTimeBase::Initialize() +{ + // get the info about Absolute time + #if TARGET_OS_MAC + struct mach_timebase_info theTimeBaseInfo; + mach_timebase_info(&theTimeBaseInfo); + sMinDelta = 1; + sToNanosNumerator = theTimeBaseInfo.numer; + sToNanosDenominator = theTimeBaseInfo.denom; + + // the frequency of that clock is: (sToNanosDenominator / sToNanosNumerator) * 10^9 + sFrequency = static_cast(sToNanosDenominator) / static_cast(sToNanosNumerator); + sFrequency *= 1000000000.0; + #elif TARGET_OS_WIN32 + LARGE_INTEGER theFrequency; + QueryPerformanceFrequency(&theFrequency); + sMinDelta = 1; + sToNanosNumerator = 1000000000ULL; + sToNanosDenominator = *((UInt64*)&theFrequency); + sFrequency = static_cast(*((UInt64*)&theFrequency)); + #endif + sInverseFrequency = 1.0 / sFrequency; + + #if Log_Host_Time_Base_Parameters + DebugPrintf("Host Time Base Parameters"); + DebugPrintf(" Minimum Delta: %lu", (unsigned long)sMinDelta); + DebugPrintf(" Frequency: %f", sFrequency); + DebugPrintf(" To Nanos Numerator: %lu", (unsigned long)sToNanosNumerator); + DebugPrintf(" To Nanos Denominator: %lu", (unsigned long)sToNanosDenominator); + #endif +} diff --git a/app/PublicUtility/CAHostTimeBase.h b/app/PublicUtility/CAHostTimeBase.h new file mode 100644 index 0000000..50e3507 --- /dev/null +++ b/app/PublicUtility/CAHostTimeBase.h @@ -0,0 +1,234 @@ +/* + File: CAHostTimeBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAHostTimeBase_h__) +#define __CAHostTimeBase_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#if TARGET_OS_MAC + #include + #include +#elif TARGET_OS_WIN32 + #include + #include "WinPThreadDefs.h" +#else + #error Unsupported operating system +#endif + +#include "CADebugPrintf.h" + +//============================================================================= +// CAHostTimeBase +// +// This class provides platform independent access to the host's time base. +//============================================================================= + +#if CoreAudio_Debug +// #define Log_Host_Time_Base_Parameters 1 +// #define Track_Host_TimeBase 1 +#endif + +class CAHostTimeBase +{ + +public: + static UInt64 ConvertToNanos(UInt64 inHostTime); + static UInt64 ConvertFromNanos(UInt64 inNanos); + + static UInt64 GetTheCurrentTime(); +#if TARGET_OS_MAC + static UInt64 GetCurrentTime() { return GetTheCurrentTime(); } +#endif + static UInt64 GetCurrentTimeInNanos(); + + static Float64 GetFrequency() { pthread_once(&sIsInited, Initialize); return sFrequency; } + static Float64 GetInverseFrequency() { pthread_once(&sIsInited, Initialize); return sInverseFrequency; } + static UInt32 GetMinimumDelta() { pthread_once(&sIsInited, Initialize); return sMinDelta; } + + static UInt64 AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime); + static SInt64 HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime); + + static UInt64 MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator); + +private: + static void Initialize(); + + static pthread_once_t sIsInited; + + static Float64 sFrequency; + static Float64 sInverseFrequency; + static UInt32 sMinDelta; + static UInt32 sToNanosNumerator; + static UInt32 sToNanosDenominator; +#if Track_Host_TimeBase + static UInt64 sLastTime; +#endif +}; + +inline UInt64 CAHostTimeBase::GetTheCurrentTime() +{ + UInt64 theTime = 0; + + #if TARGET_OS_MAC + theTime = mach_absolute_time(); + #elif TARGET_OS_WIN32 + LARGE_INTEGER theValue; + QueryPerformanceCounter(&theValue); + theTime = *((UInt64*)&theValue); + #endif + + #if Track_Host_TimeBase + if(sLastTime != 0) + { + if(theTime <= sLastTime) + { + DebugPrintf("CAHostTimeBase::GetTheCurrentTime: the current time is earlier than the last time, now: %qd, then: %qd", theTime, sLastTime); + } + sLastTime = theTime; + } + else + { + sLastTime = theTime; + } + #endif + + return theTime; +} + +inline UInt64 CAHostTimeBase::ConvertToNanos(UInt64 inHostTime) +{ + pthread_once(&sIsInited, Initialize); + + UInt64 theAnswer = MultiplyByRatio(inHostTime, sToNanosNumerator, sToNanosDenominator); + #if CoreAudio_Debug + if(((sToNanosNumerator > sToNanosDenominator) && (theAnswer < inHostTime)) || ((sToNanosDenominator > sToNanosNumerator) && (theAnswer > inHostTime))) + { + DebugPrintf("CAHostTimeBase::ConvertToNanos: The conversion wrapped"); + } + #endif + + return theAnswer; +} + +inline UInt64 CAHostTimeBase::ConvertFromNanos(UInt64 inNanos) +{ + pthread_once(&sIsInited, Initialize); + + UInt64 theAnswer = MultiplyByRatio(inNanos, sToNanosDenominator, sToNanosNumerator); + #if CoreAudio_Debug + if(((sToNanosDenominator > sToNanosNumerator) && (theAnswer < inNanos)) || ((sToNanosNumerator > sToNanosDenominator) && (theAnswer > inNanos))) + { + DebugPrintf("CAHostTimeBase::ConvertFromNanos: The conversion wrapped"); + } + #endif + + return theAnswer; +} + +inline UInt64 CAHostTimeBase::GetCurrentTimeInNanos() +{ + return ConvertToNanos(GetTheCurrentTime()); +} + +inline UInt64 CAHostTimeBase::AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime) +{ + UInt64 theAnswer; + + if(inStartTime <= inEndTime) + { + theAnswer = inEndTime - inStartTime; + } + else + { + theAnswer = inStartTime - inEndTime; + } + + return ConvertToNanos(theAnswer); +} + +inline SInt64 CAHostTimeBase::HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime) +{ + SInt64 theAnswer; + SInt64 theSign = 1; + + if(inStartTime <= inEndTime) + { + theAnswer = static_cast(inEndTime - inStartTime); + } + else + { + theAnswer = static_cast(inStartTime - inEndTime); + theSign = -1; + } + + return theSign * static_cast(ConvertToNanos(static_cast(theAnswer))); +} + +inline UInt64 CAHostTimeBase::MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator) +{ +#if TARGET_OS_MAC && TARGET_RT_64_BIT + __uint128_t theAnswer = inMuliplicand; +#else + long double theAnswer = inMuliplicand; +#endif + if(inNumerator != inDenominator) + { + theAnswer *= inNumerator; + theAnswer /= inDenominator; + } + return static_cast(theAnswer); +} + +#endif diff --git a/app/PublicUtility/CAMutex.cpp b/app/PublicUtility/CAMutex.cpp new file mode 100644 index 0000000..88cf9b0 --- /dev/null +++ b/app/PublicUtility/CAMutex.cpp @@ -0,0 +1,345 @@ +/* + File: CAMutex.cpp + Abstract: CAMutex.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAMutex.h" + +#if TARGET_OS_MAC + #include +#endif + +// PublicUtility Includes +#include "CADebugMacros.h" +#include "CAException.h" +#include "CAHostTimeBase.h" + +//================================================================================================== +// Logging +//================================================================================================== + +#if CoreAudio_Debug +// #define Log_Ownership 1 +// #define Log_Errors 1 +// #define Log_LongLatencies 1 +// #define LongLatencyThreshholdNS 1000000ULL // nanoseconds +#endif + +//================================================================================================== +// CAMutex +//================================================================================================== + +CAMutex::CAMutex(const char* inName) +: + mName(inName), + mOwner(0) +{ +#if TARGET_OS_MAC + OSStatus theError = pthread_mutex_init(&mMutex, NULL); + ThrowIf(theError != 0, CAException(theError), "CAMutex::CAMutex: Could not init the mutex"); + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::CAMutex: creating %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); + #endif +#elif TARGET_OS_WIN32 + mMutex = CreateMutex(NULL, false, NULL); + ThrowIfNULL(mMutex, CAException(GetLastError()), "CAMutex::CAMutex: could not create the mutex."); + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::CAMutex: creating %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); + #endif +#endif +} + +CAMutex::~CAMutex() +{ +#if TARGET_OS_MAC + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::~CAMutex: destroying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); + #endif + pthread_mutex_destroy(&mMutex); +#elif TARGET_OS_WIN32 + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::~CAMutex: destroying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); + #endif + if(mMutex != NULL) + { + CloseHandle(mMutex); + } +#endif +} + +bool CAMutex::Lock() +{ + bool theAnswer = false; + +#if TARGET_OS_MAC + pthread_t theCurrentThread = pthread_self(); + if(!pthread_equal(theCurrentThread, mOwner)) + { + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Lock: thread %p is locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); + #endif + + #if Log_LongLatencies + UInt64 lockTryTime = CAHostTimeBase::GetCurrentTimeInNanos(); + #endif + + OSStatus theError = pthread_mutex_lock(&mMutex); + ThrowIf(theError != 0, CAException(theError), "CAMutex::Lock: Could not lock the mutex"); + mOwner = theCurrentThread; + theAnswer = true; + + #if Log_LongLatencies + UInt64 lockAcquireTime = CAHostTimeBase::GetCurrentTimeInNanos(); + if (lockAcquireTime - lockTryTime >= LongLatencyThresholdNS) + DebugPrintfRtn(DebugPrintfFileComma "Thread %p took %.6fs to acquire the lock %s\n", theCurrentThread, (lockAcquireTime - lockTryTime) * 1.0e-9 /* nanos to seconds */, mName); + #endif + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Lock: thread %p has locked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + } +#elif TARGET_OS_WIN32 + if(mOwner != GetCurrentThreadId()) + { + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Lock: thread %lu is locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + OSStatus theError = WaitForSingleObject(mMutex, INFINITE); + ThrowIfError(theError, CAException(theError), "CAMutex::Lock: could not lock the mutex"); + mOwner = GetCurrentThreadId(); + theAnswer = true; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Lock: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + } +#endif + + return theAnswer; +} + +void CAMutex::Unlock() +{ +#if TARGET_OS_MAC + if(pthread_equal(pthread_self(), mOwner)) + { + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Unlock: thread %p is unlocking %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + + mOwner = 0; + OSStatus theError = pthread_mutex_unlock(&mMutex); + ThrowIf(theError != 0, CAException(theError), "CAMutex::Unlock: Could not unlock the mutex"); + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Unlock: thread %p has unlocked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + } + else + { + DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own"); + } +#elif TARGET_OS_WIN32 + if(mOwner == GetCurrentThreadId()) + { + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Unlock: thread %lu is unlocking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + mOwner = 0; + bool wasReleased = ReleaseMutex(mMutex); + ThrowIf(!wasReleased, CAException(GetLastError()), "CAMutex::Unlock: Could not unlock the mutex"); + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Unlock: thread %lu has unlocked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + } + else + { + DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own"); + } +#endif +} + +bool CAMutex::Try(bool& outWasLocked) +{ + bool theAnswer = false; + outWasLocked = false; + +#if TARGET_OS_MAC + pthread_t theCurrentThread = pthread_self(); + if(!pthread_equal(theCurrentThread, mOwner)) + { + // this means the current thread doesn't already own the lock + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p is try-locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); + #endif + + // go ahead and call trylock to see if we can lock it. + int theError = pthread_mutex_trylock(&mMutex); + if(theError == 0) + { + // return value of 0 means we successfully locked the lock + mOwner = theCurrentThread; + theAnswer = true; + outWasLocked = true; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p has locked %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); + #endif + } + else if(theError == EBUSY) + { + // return value of EBUSY means that the lock was already locked by another thread + theAnswer = false; + outWasLocked = false; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p failed to lock %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); + #endif + } + else + { + // any other return value means something really bad happenned + ThrowIfError(theError, CAException(theError), "CAMutex::Try: call to pthread_mutex_trylock failed"); + } + } + else + { + // this means the current thread already owns the lock + theAnswer = true; + outWasLocked = false; + } +#elif TARGET_OS_WIN32 + if(mOwner != GetCurrentThreadId()) + { + // this means the current thread doesn't own the lock + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu is try-locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + // try to acquire the mutex + OSStatus theError = WaitForSingleObject(mMutex, 0); + if(theError == WAIT_OBJECT_0) + { + // this means we successfully locked the lock + mOwner = GetCurrentThreadId(); + theAnswer = true; + outWasLocked = true; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + } + else if(theError == WAIT_TIMEOUT) + { + // this means that the lock was already locked by another thread + theAnswer = false; + outWasLocked = false; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu failed to lock %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + } + else + { + // any other return value means something really bad happenned + ThrowIfError(theError, CAException(GetLastError()), "CAMutex::Try: call to lock the mutex failed"); + } + } + else + { + // this means the current thread already owns the lock + theAnswer = true; + outWasLocked = false; + } +#endif + + return theAnswer; +} + +bool CAMutex::IsFree() const +{ + return mOwner == 0; +} + +bool CAMutex::IsOwnedByCurrentThread() const +{ + bool theAnswer = true; + +#if TARGET_OS_MAC + theAnswer = pthread_equal(pthread_self(), mOwner); +#elif TARGET_OS_WIN32 + theAnswer = (mOwner == GetCurrentThreadId()); +#endif + + return theAnswer; +} + + +CAMutex::Unlocker::Unlocker(CAMutex& inMutex) +: mMutex(inMutex), + mNeedsLock(false) +{ + Assert(mMutex.IsOwnedByCurrentThread(), "Major problem: Unlocker attempted to unlock a mutex not owned by the current thread!"); + + mMutex.Unlock(); + mNeedsLock = true; +} + +CAMutex::Unlocker::~Unlocker() +{ + if(mNeedsLock) + { + mMutex.Lock(); + } +} diff --git a/app/PublicUtility/CAMutex.h b/app/PublicUtility/CAMutex.h new file mode 100644 index 0000000..3f0299c --- /dev/null +++ b/app/PublicUtility/CAMutex.h @@ -0,0 +1,192 @@ +// This file is part of Background Music. +// +// Background Music is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 2 of the +// License, or (at your option) any later version. +// +// Background Music is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Background Music. If not, see . + +// +// CAMutex.h +// PublicUtility +// +// Copyright (C) 2014 Apple Inc. All Rights Reserved. +// Copyright © 2020 Kyle Neideck +// +// Original license header follows. +// + +/* + File: CAMutex.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAMutex_h__ +#define __CAMutex_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +#include "VCThreadSafetyAnalysis.h" + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#if TARGET_OS_MAC + #include +#elif TARGET_OS_WIN32 + #include +#else + #error Unsupported operating system +#endif + +//================================================================================================== +// A recursive mutex. +//================================================================================================== + +class CAPABILITY("mutex") CAMutex +{ +// Construction/Destruction +public: + CAMutex(const char* inName); + virtual ~CAMutex(); + +// Actions +public: + virtual bool Lock() ACQUIRE(); + virtual void Unlock() RELEASE(); + virtual bool Try(bool& outWasLocked) TRY_ACQUIRE(true); // returns true if lock is free, false if not + + virtual bool IsFree() const; + virtual bool IsOwnedByCurrentThread() const; + +// Implementation +protected: + const char* mName; +#if TARGET_OS_MAC + pthread_t mOwner; + pthread_mutex_t mMutex; +#elif TARGET_OS_WIN32 + UInt32 mOwner; + HANDLE mMutex; +#endif + +// Helper class to manage taking and releasing recursively +public: + class SCOPED_CAPABILITY Locker + { + + // Construction/Destruction + public: + Locker(CAMutex& inMutex) ACQUIRE(inMutex) : mMutex(&inMutex), mNeedsRelease(false) { mNeedsRelease = mMutex->Lock(); } + Locker(CAMutex* inMutex) ACQUIRE(inMutex) : mMutex(inMutex), mNeedsRelease(false) { mNeedsRelease = (mMutex != NULL && mMutex->Lock()); } + // in this case the mutex can be null + ~Locker() RELEASE() { if(mNeedsRelease) { mMutex->Unlock(); } } + + + private: + Locker(const Locker&); + Locker& operator=(const Locker&); + + // Implementation + private: + CAMutex* mMutex; + bool mNeedsRelease; + + }; + + // Clang's static analysis doesn't work for unlocker classes. See + // . +// Unlocker + class Unlocker + { + public: + Unlocker(CAMutex& inMutex); + ~Unlocker(); + + private: + CAMutex& mMutex; + bool mNeedsLock; + + // Hidden definitions of copy ctor, assignment operator + Unlocker(const Unlocker& copy); // Not implemented + Unlocker& operator=(const Unlocker& copy); // Not implemented + }; + +// you can use this with Try - if you take the lock in try, pass in the outWasLocked var + class SCOPED_CAPABILITY Tryer { + + // Construction/Destruction + public: + Tryer (CAMutex &mutex) TRY_ACQUIRE(true, mutex) : mMutex(mutex), mNeedsRelease(false), mHasLock(false) { mHasLock = mMutex.Try (mNeedsRelease); } + ~Tryer () RELEASE() { if (mNeedsRelease) mMutex.Unlock(); } + + bool HasLock () const { return mHasLock; } + + private: + Tryer(const Tryer&); + Tryer& operator=(const Tryer&); + + // Implementation + private: + CAMutex & mMutex; + bool mNeedsRelease; + bool mHasLock; + }; +}; + + +#endif // __CAMutex_h__ diff --git a/app/PublicUtility/CAPThread.cpp b/app/PublicUtility/CAPThread.cpp new file mode 100644 index 0000000..3da1058 --- /dev/null +++ b/app/PublicUtility/CAPThread.cpp @@ -0,0 +1,450 @@ +/* + File: CAPThread.cpp + Abstract: CAPThread.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CAPThread.h" + +// PublicUtility Includes +#include "CADebugMacros.h" +#include "CAException.h" + +// System Includes +#if TARGET_OS_MAC + #include +#endif + +// Standard Library Includes +#include + +//================================================================================================== +// CAPThread +//================================================================================================== + +// returns the thread's priority as it was last set by the API +#define CAPTHREAD_SET_PRIORITY 0 +// returns the thread's priority as it was last scheduled by the Kernel +#define CAPTHREAD_SCHEDULED_PRIORITY 1 + +//#define Log_SetPriority 1 + +CAPThread::CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPriority, bool inFixedPriority, bool inAutoDelete, const char* inThreadName) +: +#if TARGET_OS_MAC + mPThread(0), + mSpawningThreadPriority(getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY)), +#elif TARGET_OS_WIN32 + mThreadHandle(NULL), + mThreadID(0), +#endif + mThreadRoutine(inThreadRoutine), + mThreadParameter(inParameter), + mPriority(inPriority), + mPeriod(0), + mComputation(0), + mConstraint(0), + mIsPreemptible(true), + mTimeConstraintSet(false), + mFixedPriority(inFixedPriority), + mAutoDelete(inAutoDelete) +{ + if(inThreadName != NULL) + { + strlcpy(mThreadName, inThreadName, kMaxThreadNameLength); + } + else + { + memset(mThreadName, 0, kMaxThreadNameLength); + } +} + +CAPThread::CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible, bool inAutoDelete, const char* inThreadName) +: +#if TARGET_OS_MAC + mPThread(0), + mSpawningThreadPriority(getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY)), +#elif TARGET_OS_WIN32 + mThreadHandle(NULL), + mThreadID(0), +#endif + mThreadRoutine(inThreadRoutine), + mThreadParameter(inParameter), + mPriority(kDefaultThreadPriority), + mPeriod(inPeriod), + mComputation(inComputation), + mConstraint(inConstraint), + mIsPreemptible(inIsPreemptible), + mTimeConstraintSet(true), + mFixedPriority(false), + mAutoDelete(inAutoDelete) +{ + if(inThreadName != NULL) + { + strlcpy(mThreadName, inThreadName, kMaxThreadNameLength); + } + else + { + memset(mThreadName, 0, kMaxThreadNameLength); + } +} + +CAPThread::~CAPThread() +{ +} + +UInt32 CAPThread::GetScheduledPriority() +{ +#if TARGET_OS_MAC + return CAPThread::getScheduledPriority( mPThread, CAPTHREAD_SCHEDULED_PRIORITY ); +#elif TARGET_OS_WIN32 + UInt32 theAnswer = 0; + if(mThreadHandle != NULL) + { + theAnswer = GetThreadPriority(mThreadHandle); + } + return theAnswer; +#endif +} + +UInt32 CAPThread::GetScheduledPriority(NativeThread thread) +{ +#if TARGET_OS_MAC + return getScheduledPriority( thread, CAPTHREAD_SCHEDULED_PRIORITY ); +#elif TARGET_OS_WIN32 + return 0; // ??? +#endif +} + +void CAPThread::SetPriority(UInt32 inPriority, bool inFixedPriority) +{ + mPriority = inPriority; + mTimeConstraintSet = false; + mFixedPriority = inFixedPriority; +#if TARGET_OS_MAC + if(mPThread != 0) + { + SetPriority(mPThread, mPriority, mFixedPriority); + } +#elif TARGET_OS_WIN32 + if(mThreadID != NULL) + { + SetPriority(mThreadID, mPriority, mFixedPriority); + } +#endif +} + +void CAPThread::SetPriority(NativeThread inThread, UInt32 inPriority, bool inFixedPriority) +{ +#if TARGET_OS_MAC + if(inThread != 0) + { + kern_return_t theError = 0; + + // set whether or not this is a fixed priority thread + if (inFixedPriority) + { + thread_extended_policy_data_t theFixedPolicy = { false }; + theError = thread_policy_set(pthread_mach_thread_np(inThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT); + AssertNoKernelError(theError, "CAPThread::SetPriority: failed to set the fixed-priority policy"); + } + + // set the thread's absolute priority which is relative to the priority on which thread_policy_set() is called + UInt32 theCurrentThreadPriority = getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY); + thread_precedence_policy_data_t thePrecedencePolicy = { static_cast(inPriority - theCurrentThreadPriority) }; + theError = thread_policy_set(pthread_mach_thread_np(inThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT); + AssertNoKernelError(theError, "CAPThread::SetPriority: failed to set the precedence policy"); + + #if Log_SetPriority + DebugMessageN4("CAPThread::SetPriority: requsted: %lu spawning: %lu current: %lu assigned: %d", mPriority, mSpawningThreadPriority, theCurrentThreadPriority, thePrecedencePolicy.importance); + #endif + } +#elif TARGET_OS_WIN32 + if(inThread != NULL) + { + HANDLE hThread = OpenThread(NULL, FALSE, inThread); + if(hThread != NULL) { + SetThreadPriority(hThread, inPriority); + CloseHandle(hThread); + } + } +#endif +} + +void CAPThread::SetTimeConstraints(UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible) +{ + mPeriod = inPeriod; + mComputation = inComputation; + mConstraint = inConstraint; + mIsPreemptible = inIsPreemptible; + mTimeConstraintSet = true; +#if TARGET_OS_MAC + if(mPThread != 0) + { + thread_time_constraint_policy_data_t thePolicy; + thePolicy.period = mPeriod; + thePolicy.computation = mComputation; + thePolicy.constraint = mConstraint; + thePolicy.preemptible = mIsPreemptible; + AssertNoError(thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&thePolicy, THREAD_TIME_CONSTRAINT_POLICY_COUNT), "CAPThread::SetTimeConstraints: thread_policy_set failed"); + } +#elif TARGET_OS_WIN32 + if(mThreadHandle != NULL) + { + SetThreadPriority(mThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); + } +#endif +} + +void CAPThread::Start() +{ +#if TARGET_OS_MAC + Assert(mPThread == 0, "CAPThread::Start: can't start because the thread is already running"); + if(mPThread == 0) + { + OSStatus theResult; + pthread_attr_t theThreadAttributes; + + theResult = pthread_attr_init(&theThreadAttributes); + ThrowIf(theResult != 0, CAException(theResult), "CAPThread::Start: Thread attributes could not be created."); + + theResult = pthread_attr_setdetachstate(&theThreadAttributes, PTHREAD_CREATE_DETACHED); + ThrowIf(theResult != 0, CAException(theResult), "CAPThread::Start: A thread could not be created in the detached state."); + + theResult = pthread_create(&mPThread, &theThreadAttributes, (ThreadRoutine)CAPThread::Entry, this); + ThrowIf(theResult != 0 || !mPThread, CAException(theResult), "CAPThread::Start: Could not create a thread."); + + pthread_attr_destroy(&theThreadAttributes); + + } +#elif TARGET_OS_WIN32 + Assert(mThreadID == 0, "CAPThread::Start: can't start because the thread is already running"); + if(mThreadID == 0) + { + // clean up the existing thread handle + if(mThreadHandle != NULL) + { + CloseHandle(mThreadHandle); + mThreadHandle = NULL; + } + + // create a new thread + mThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Entry, this, 0, &mThreadID); + ThrowIf(mThreadHandle == NULL, CAException(GetLastError()), "CAPThread::Start: Could not create a thread."); + } +#endif +} + +#if TARGET_OS_MAC + +void* CAPThread::Entry(CAPThread* inCAPThread) +{ + void* theAnswer = NULL; + +#if TARGET_OS_MAC + inCAPThread->mPThread = pthread_self(); +#elif TARGET_OS_WIN32 + // do we need to do something here? +#endif + +#if !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) + if(inCAPThread->mThreadName[0] != 0) + { + pthread_setname_np(inCAPThread->mThreadName); + } +#endif + + try + { + if(inCAPThread->mTimeConstraintSet) + { + inCAPThread->SetTimeConstraints(inCAPThread->mPeriod, inCAPThread->mComputation, inCAPThread->mConstraint, inCAPThread->mIsPreemptible); + } + else + { + inCAPThread->SetPriority(inCAPThread->mPriority, inCAPThread->mFixedPriority); + } + + if(inCAPThread->mThreadRoutine != NULL) + { + theAnswer = inCAPThread->mThreadRoutine(inCAPThread->mThreadParameter); + } + } + catch (...) + { + // what should be done here? + } + inCAPThread->mPThread = 0; + if (inCAPThread->mAutoDelete) + delete inCAPThread; + return theAnswer; +} + +UInt32 CAPThread::getScheduledPriority(pthread_t inThread, int inPriorityKind) +{ + thread_basic_info_data_t threadInfo; + policy_info_data_t thePolicyInfo; + unsigned int count; + + if (inThread == NULL) + return 0; + + // get basic info + count = THREAD_BASIC_INFO_COUNT; + thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &count); + + switch (threadInfo.policy) { + case POLICY_TIMESHARE: + count = POLICY_TIMESHARE_INFO_COUNT; + thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&(thePolicyInfo.ts), &count); + if (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) { + return static_cast(thePolicyInfo.ts.cur_priority); + } + return static_cast(thePolicyInfo.ts.base_priority); + break; + + case POLICY_FIFO: + count = POLICY_FIFO_INFO_COUNT; + thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (thread_info_t)&(thePolicyInfo.fifo), &count); + if ( (thePolicyInfo.fifo.depressed) && (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) ) { + return static_cast(thePolicyInfo.fifo.depress_priority); + } + return static_cast(thePolicyInfo.fifo.base_priority); + break; + + case POLICY_RR: + count = POLICY_RR_INFO_COUNT; + thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (thread_info_t)&(thePolicyInfo.rr), &count); + if ( (thePolicyInfo.rr.depressed) && (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) ) { + return static_cast(thePolicyInfo.rr.depress_priority); + } + return static_cast(thePolicyInfo.rr.base_priority); + break; + } + + return 0; +} + +#elif TARGET_OS_WIN32 + +UInt32 WINAPI CAPThread::Entry(CAPThread* inCAPThread) +{ + UInt32 theAnswer = 0; + + try + { + if(inCAPThread->mTimeConstraintSet) + { + inCAPThread->SetTimeConstraints(inCAPThread->mPeriod, inCAPThread->mComputation, inCAPThread->mConstraint, inCAPThread->mIsPreemptible); + } + else + { + inCAPThread->SetPriority(inCAPThread->mPriority, inCAPThread->mFixedPriority); + } + + if(inCAPThread->mThreadRoutine != NULL) + { + theAnswer = reinterpret_cast(inCAPThread->mThreadRoutine(inCAPThread->mThreadParameter)); + } + inCAPThread->mThreadID = 0; + } + catch (...) + { + // what should be done here? + } + CloseHandle(inCAPThread->mThreadHandle); + inCAPThread->mThreadHandle = NULL; + if (inCAPThread->mAutoDelete) + delete inCAPThread; + return theAnswer; +} + +extern "C" +Boolean CompareAndSwap(UInt32 inOldValue, UInt32 inNewValue, UInt32* inOldValuePtr) +{ + return InterlockedCompareExchange((volatile LONG*)inOldValuePtr, inNewValue, inOldValue) == inOldValue; +} + +#endif + +void CAPThread::SetName(const char* inThreadName) +{ + if(inThreadName != NULL) + { + strlcpy(mThreadName, inThreadName, kMaxThreadNameLength); + } + else + { + memset(mThreadName, 0, kMaxThreadNameLength); + } +} + +#if CoreAudio_Debug +void CAPThread::DebugPriority(const char *label) +{ +#if !TARGET_OS_WIN32 + if (mTimeConstraintSet) + printf("CAPThread::%s %p: pri=