mirror of
https://github.com/morgan9e/VolumeControl
synced 2026-04-13 15:55:02 +09:00
Initial commit
This commit is contained in:
15
.editorconfig
Normal file
15
.editorconfig
Normal file
@@ -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
|
||||
|
||||
|
||||
39
.gitignore
vendored
Normal file
39
.gitignore
vendored
Normal file
@@ -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
|
||||
339
LICENSE
Normal file
339
LICENSE
Normal file
@@ -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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 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.
|
||||
56
LICENSE-Apple-Sample-Code
Normal file
56
LICENSE-Apple-Sample-Code
Normal file
@@ -0,0 +1,56 @@
|
||||
Background Music includes code from Core Audio User-Space Driver
|
||||
Examples, see
|
||||
<https://developer.apple.com/library/mac/samplecode/AudioDriverExamples>,
|
||||
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
|
||||
<https://developer.apple.com/library/content/samplecode/CoreAudioUtilityClasses>,
|
||||
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.
|
||||
|
||||
|
||||
151
Makefile
Normal file
151
Makefile
Normal file
@@ -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 '<?xml version="1.0" encoding="UTF-8"?>' > "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)"
|
||||
@echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)"
|
||||
@echo '<plist version="1.0"><dict>' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)"
|
||||
@echo ' <key>Label</key><string>com.volumecontrol.App</string>' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)"
|
||||
@echo ' <key>ProgramArguments</key><array><string>/Applications/VolumeControl.app/Contents/MacOS/VolumeControl</string></array>' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)"
|
||||
@echo ' <key>RunAtLoad</key><true/>' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)"
|
||||
@echo ' <key>KeepAlive</key><true/>' >> "$(LAUNCHAGENT_DIR)/$(LAUNCHAGENT_PLIST)"
|
||||
@echo '</dict></plist>' >> "$(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)
|
||||
24
app/Info.plist
Normal file
24
app/Info.plist
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>VolumeControl</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.volumecontrol.App</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>VolumeControl</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.14</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>VolumeControl reads system audio through a virtual input device to provide software volume control for HDMI and other outputs.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
318
app/PublicUtility/CAAtomic.h
Normal file
318
app/PublicUtility/CAAtomic.h
Normal file
@@ -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 <windows.h>
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_InterlockedOr)
|
||||
#pragma intrinsic(_InterlockedAnd)
|
||||
#else
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#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__
|
||||
508
app/PublicUtility/CAAutoDisposer.h
Normal file
508
app/PublicUtility/CAAutoDisposer.h
Normal file
@@ -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 <stdlib.h> // for malloc
|
||||
#include <new> // for bad_alloc
|
||||
#include <string.h> // 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 <typename T>
|
||||
struct CAPtrRef
|
||||
{
|
||||
T* ptr_;
|
||||
|
||||
explicit CAPtrRef(T* ptr) : ptr_(ptr) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CAAutoFree
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
|
||||
CAAutoFree() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoFree(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoFree(CAAutoFree<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoFree(CAAutoFree<T>& 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<T*>(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<T*>(clear ? CA_calloc(numItems, sizeof(T)) : CA_malloc(numItems * sizeof(T)));
|
||||
}
|
||||
|
||||
void allocBytes(size_t numBytes, bool clear = false)
|
||||
{
|
||||
free();
|
||||
ptr_ = static_cast<T*>(clear ? CA_calloc(1, numBytes) : CA_malloc(numBytes));
|
||||
}
|
||||
|
||||
void reallocBytes(size_t numBytes)
|
||||
{
|
||||
ptr_ = static_cast<T*>(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<T*>(CA_realloc(ptr_, numItems * sizeof(T)));
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoFree& operator=(CAAutoFree<U>& 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 <typename U>
|
||||
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<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoFree& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoFree<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CAAutoDelete
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
CAAutoDelete() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoDelete(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoDelete(CAAutoDelete<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoDelete(CAAutoDelete<T>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
~CAAutoDelete() { free(); }
|
||||
|
||||
template <typename U>
|
||||
CAAutoDelete& operator=(CAAutoDelete<U>& 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 <typename U>
|
||||
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<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoDelete& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoFree<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CAAutoArrayDelete
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
CAAutoArrayDelete() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoArrayDelete(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoArrayDelete(CAAutoArrayDelete<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoArrayDelete(CAAutoArrayDelete<T>& 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 <typename U>
|
||||
CAAutoArrayDelete& operator=(CAAutoArrayDelete<U>& 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 <typename U>
|
||||
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<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoArrayDelete& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoArrayDelete<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// convenience function
|
||||
template <typename T>
|
||||
void free(CAAutoFree<T>& p)
|
||||
{
|
||||
p.free();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
// example program showing ownership transfer
|
||||
|
||||
CAAutoFree<char> source()
|
||||
{
|
||||
// source allocates and returns ownership to the caller.
|
||||
const char* str = "this is a test";
|
||||
size_t size = strlen(str) + 1;
|
||||
CAAutoFree<char> captr(size, false);
|
||||
strlcpy(captr(), str, size);
|
||||
printf("source %08X %08X '%s'\n", &captr, captr(), captr());
|
||||
return captr;
|
||||
}
|
||||
|
||||
void user(CAAutoFree<char> 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<char> 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<char> 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
|
||||
206
app/PublicUtility/CABitOperations.h
Normal file
206
app/PublicUtility/CABitOperations.h
Normal file
@@ -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 <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#else
|
||||
// #include <MacTypes.h>
|
||||
#include "CFBase.h"
|
||||
#endif
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
// 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
|
||||
|
||||
821
app/PublicUtility/CACFArray.cpp
Normal file
821
app/PublicUtility/CACFArray.cpp
Normal file
@@ -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<CFBooleanRef>(theValue));
|
||||
theAnswer = true;
|
||||
}
|
||||
else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID()))
|
||||
{
|
||||
SInt32 theNumericValue = 0;
|
||||
CFNumberGetValue(static_cast<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(theValue), kCFNumberSInt32Type, &outValue);
|
||||
theAnswer = true;
|
||||
}
|
||||
else if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID()))
|
||||
{
|
||||
CFStringRef theString = static_cast<CFStringRef>(theValue);
|
||||
if(CFStringGetLength(theString) == 4)
|
||||
{
|
||||
char theCString[5];
|
||||
CFStringGetCString(theString, theCString, 5, kCFStringEncodingASCII);
|
||||
outValue = CFSwapInt32BigToHost(*reinterpret_cast<UInt32*>(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<CFStringRef>(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<CFArrayRef>(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<CFDictionaryRef>(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<CFDataRef>(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<CFUUIDRef>(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<CFIndex>(inIndex));
|
||||
theAnswer = outItem != NULL;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CACFArray::GetCACFString(UInt32 inIndex, CACFString& outItem) const
|
||||
{
|
||||
outItem = static_cast<CFStringRef>(NULL);
|
||||
CFTypeRef theItem = NULL;
|
||||
if(GetCFType(inIndex, theItem))
|
||||
{
|
||||
if((theItem != NULL) && (CFGetTypeID(theItem) == CFStringGetTypeID()))
|
||||
{
|
||||
outItem = static_cast<CFStringRef>(theItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CACFArray::GetCACFArray(UInt32 inIndex, CACFArray& outItem) const
|
||||
{
|
||||
outItem = static_cast<CFArrayRef>(NULL);
|
||||
CFTypeRef theItem = NULL;
|
||||
if(GetCFType(inIndex, theItem))
|
||||
{
|
||||
if((theItem != NULL) && (CFGetTypeID(theItem) == CFArrayGetTypeID()))
|
||||
{
|
||||
outItem = static_cast<CFArrayRef>(theItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CACFArray::GetCACFDictionary(UInt32 inIndex, CACFDictionary& outItem) const
|
||||
{
|
||||
outItem = static_cast<CFDictionaryRef>(NULL);
|
||||
CFTypeRef theItem = NULL;
|
||||
if(GetCFType(inIndex, theItem))
|
||||
{
|
||||
if((theItem != NULL) && (CFGetTypeID(theItem) == CFDictionaryGetTypeID()))
|
||||
{
|
||||
outItem = static_cast<CFDictionaryRef>(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<CFIndex>(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<CFIndex>(inIndex), inItem);
|
||||
theAnswer = true;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
195
app/PublicUtility/CACFArray.h
Normal file
195
app/PublicUtility/CACFArray.h
Normal file
@@ -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 <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#include <CoreFoundation.h>
|
||||
#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<CFIndex>(inMaxNumberItems), &kCFTypeArrayCallBacks)), mRelease(inRelease), mMutable(true) {}
|
||||
CACFArray(CFArrayRef inCFArray, bool inRelease) : mCFArray(const_cast<CFMutableArrayRef>(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<CFMutableArrayRef>(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<CFIndex>(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
|
||||
581
app/PublicUtility/CACFDictionary.cpp
Normal file
581
app/PublicUtility/CACFDictionary.cpp
Normal file
@@ -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<CFBooleanRef>(theValue));
|
||||
theAnswer = true;
|
||||
}
|
||||
else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID()))
|
||||
{
|
||||
SInt32 theNumericValue = 0;
|
||||
CFNumberGetValue(static_cast<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<Float32>(CFStringGetDoubleValue(static_cast<CFStringRef>(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<CFStringRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(theValue), kCFNumberSInt64Type, &theFixed64);
|
||||
outValue = static_cast<Float64>(theFixed64 >> 32);
|
||||
outValue += static_cast<Float64>(theFixed64 & 0x00000000FFFFFFFFLL) / static_cast<Float64>(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<CFNumberRef>(theValue), kCFNumberSInt32Type, &outValue);
|
||||
theAnswer = true;
|
||||
}
|
||||
else if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID()))
|
||||
{
|
||||
CFStringRef theString = static_cast<CFStringRef>(theValue);
|
||||
if(CFStringGetLength(theString) == 4)
|
||||
{
|
||||
char theCString[5];
|
||||
CFStringGetCString(theString, theCString, 5, kCFStringEncodingASCII);
|
||||
outValue = CFSwapInt32BigToHost(*reinterpret_cast<UInt32*>(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<CFStringRef>(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<CFArrayRef>(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<CFDictionaryRef>(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<CFDataRef>(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<CFURLRef>(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<CFStringRef>(NULL);
|
||||
CFTypeRef theValue = NULL;
|
||||
if(GetCFType(inKey, theValue))
|
||||
{
|
||||
if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID()))
|
||||
{
|
||||
outValue = static_cast<CFStringRef>(theValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CACFDictionary::GetCACFArray(const CFStringRef inKey, CACFArray& outValue) const
|
||||
{
|
||||
outValue = static_cast<CFArrayRef>(NULL);
|
||||
CFTypeRef theValue = NULL;
|
||||
if(GetCFType(inKey, theValue))
|
||||
{
|
||||
if((theValue != NULL) && (CFGetTypeID(theValue) == CFArrayGetTypeID()))
|
||||
{
|
||||
outValue = static_cast<CFArrayRef>(theValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CACFDictionary::GetCACFDictionary(const CFStringRef inKey, CACFDictionary& outValue) const
|
||||
{
|
||||
outValue = static_cast<CFDictionaryRef>(NULL);
|
||||
CFTypeRef theValue = NULL;
|
||||
if(GetCFType(inKey, theValue))
|
||||
{
|
||||
if((theValue != NULL) && (CFGetTypeID(theValue) == CFDictionaryGetTypeID()))
|
||||
{
|
||||
outValue = static_cast<CFDictionaryRef>(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;
|
||||
}
|
||||
176
app/PublicUtility/CACFDictionary.h
Normal file
176
app/PublicUtility/CACFDictionary.h
Normal file
@@ -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 <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <CoreFoundation.h>
|
||||
#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<CFMutableDictionaryRef>(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<CFMutableDictionaryRef>(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__
|
||||
83
app/PublicUtility/CACFNumber.cpp
Normal file
83
app/PublicUtility/CACFNumber.cpp
Normal file
@@ -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);
|
||||
}
|
||||
151
app/PublicUtility/CACFNumber.h
Normal file
151
app/PublicUtility/CACFNumber.h
Normal file
@@ -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 <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CFNumber.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#include <CFNumber.h>
|
||||
#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
|
||||
110
app/PublicUtility/CACFString.cpp
Normal file
110
app/PublicUtility/CACFString.cpp
Normal file
@@ -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<CFIndex>(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<UInt32>(theStringRange.length) > ioStringSize)
|
||||
{
|
||||
theStringRange.length = static_cast<CFIndex>(ioStringSize);
|
||||
}
|
||||
CFStringGetCharacters(inCFString, theStringRange, outString);
|
||||
ioStringSize = ToUInt32(theStringRange.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
outString[0] = 0;
|
||||
ioStringSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
196
app/PublicUtility/CACFString.h
Normal file
196
app/PublicUtility/CACFString.h
Normal file
@@ -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 <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#include <CFString.h>
|
||||
#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
|
||||
134
app/PublicUtility/CADebugMacros.cpp
Normal file
134
app/PublicUtility/CADebugMacros.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// 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 <stdio.h>
|
||||
#if TARGET_API_MAC_OSX
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
|
||||
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
|
||||
}
|
||||
612
app/PublicUtility/CADebugMacros.h
Normal file
612
app/PublicUtility/CADebugMacros.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// CADebugMacros.h
|
||||
// PublicUtility
|
||||
//
|
||||
// Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
// Copyright © 2016, 2020 Kyle Neideck
|
||||
//
|
||||
// Original license header follows.
|
||||
//
|
||||
|
||||
/*
|
||||
File: CADebugMacros.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
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 <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
//=============================================================================
|
||||
// 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 <pthread.h>
|
||||
#include "CAHostTimeBase.h"
|
||||
#if TARGET_RT_64_BIT
|
||||
#define DebugPrintfThreadIDFormat "%16p"
|
||||
#else
|
||||
#define DebugPrintfThreadIDFormat "%8p"
|
||||
#endif
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " DebugPrintfThreadIDFormat " " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), ## __VA_ARGS__) FlushRtn
|
||||
#elif CoreAudio_TimeStampMessages
|
||||
#include "CAHostTimeBase.h"
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), ## __VA_ARGS__) FlushRtn
|
||||
#else
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf(inFormat, ## __VA_ARGS__) FlushRtn
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
// can be used to break into debugger immediately, also see CADebugger
|
||||
#define BusError() { long* p=NULL; *p=0; }
|
||||
|
||||
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
|
||||
114
app/PublicUtility/CADebugPrintf.cpp
Normal file
114
app/PublicUtility/CADebugPrintf.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// CADebugPrintf.cpp
|
||||
// PublicUtility
|
||||
//
|
||||
// Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
// Original license header follows.
|
||||
//
|
||||
|
||||
/*
|
||||
File: CADebugPrintf.cpp
|
||||
Abstract: CADebugPrintf.h
|
||||
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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <Windows.h>
|
||||
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 <unistd.h>
|
||||
FILE* sDebugPrintfSideFile = NULL;
|
||||
extern "C"
|
||||
void OpenDebugPrintfSideFile()
|
||||
{
|
||||
if(sDebugPrintfSideFile == NULL)
|
||||
{
|
||||
char theFileName[1024];
|
||||
snprintf(theFileName, sizeof(theFileName), CoreAudio_UseSideFile, getpid());
|
||||
sDebugPrintfSideFile = fopen(theFileName, "a+");
|
||||
DebugPrintfRtn(DebugPrintfFileComma "\n------------------------------\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
113
app/PublicUtility/CADebugPrintf.h
Normal file
113
app/PublicUtility/CADebugPrintf.h
Normal file
@@ -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 <CoreAudio/CoreAudioTypes.h>
|
||||
#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 <sys/syslog.h>
|
||||
#define DebugPrintfRtn syslog
|
||||
#define DebugPrintfFile LOG_NOTICE
|
||||
#define DebugPrintfLineEnding ""
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#elif defined(CoreAudio_UseSideFile)
|
||||
#include <stdio.h>
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
void OpenDebugPrintfSideFile();
|
||||
extern FILE* sDebugPrintfSideFile;
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile ((sDebugPrintfSideFile != NULL) ? sDebugPrintfSideFile : stderr)
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile stderr
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DebugPrintf(inFormat, ...) \
|
||||
do { \
|
||||
if (VCDebugLoggingIsEnabled()) { \
|
||||
DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
103
app/PublicUtility/CADebugger.cpp
Normal file
103
app/PublicUtility/CADebugger.cpp
Normal file
@@ -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 <sys/sysctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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
|
||||
}
|
||||
78
app/PublicUtility/CADebugger.h
Normal file
78
app/PublicUtility/CADebugger.h
Normal file
@@ -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 <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#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
|
||||
83
app/PublicUtility/CAException.h
Normal file
83
app/PublicUtility/CAException.h
Normal file
@@ -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 <CoreAudio/CoreAudioTypes.h>
|
||||
#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
|
||||
1156
app/PublicUtility/CAHALAudioDevice.cpp
Normal file
1156
app/PublicUtility/CAHALAudioDevice.cpp
Normal file
File diff suppressed because it is too large
Load Diff
238
app/PublicUtility/CAHALAudioDevice.h
Normal file
238
app/PublicUtility/CAHALAudioDevice.h
Normal file
@@ -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
|
||||
373
app/PublicUtility/CAHALAudioObject.cpp
Normal file
373
app/PublicUtility/CAHALAudioObject.cpp
Normal file
@@ -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<AudioObjectID> 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");
|
||||
}
|
||||
155
app/PublicUtility/CAHALAudioObject.h
Normal file
155
app/PublicUtility/CAHALAudioObject.h
Normal file
@@ -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 <CoreAudio/CoreAudio.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <CoreAudio.h>
|
||||
#include <CoreFoundation.h>
|
||||
#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 <class T> 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 <class T> void SetPropertyData_Struct(const AudioObjectPropertyAddress& inAddress, T& inStruct, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(T), &inStruct); }
|
||||
|
||||
template <class T> UInt32 GetPropertyData_ArraySize(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { return GetPropertyDataSize(inAddress, inQualifierDataSize, inQualifierData) / SizeOf32(T); }
|
||||
template <class T> 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 <class T> 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
|
||||
182
app/PublicUtility/CAHALAudioStream.cpp
Normal file
182
app/PublicUtility/CAHALAudioStream.cpp
Normal file
@@ -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<AudioStreamRangedDescription> 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<AudioStreamRangedDescription> theFormats(theNumberFormats);
|
||||
GetAvailablePhysicalFormats(theNumberFormats, theFormats);
|
||||
if((theNumberFormats > 0) && (inIndex < theNumberFormats))
|
||||
{
|
||||
outFormat = theFormats[inIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
94
app/PublicUtility/CAHALAudioStream.h
Normal file
94
app/PublicUtility/CAHALAudioStream.h
Normal file
@@ -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
|
||||
181
app/PublicUtility/CAHALAudioSystemObject.cpp
Normal file
181
app/PublicUtility/CAHALAudioSystemObject.cpp
Normal file
@@ -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<AudioObjectID> 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<AudioObjectID> 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;
|
||||
}
|
||||
90
app/PublicUtility/CAHALAudioSystemObject.h
Normal file
90
app/PublicUtility/CAHALAudioSystemObject.h
Normal file
@@ -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
|
||||
99
app/PublicUtility/CAHostTimeBase.cpp
Normal file
99
app/PublicUtility/CAHostTimeBase.cpp
Normal file
@@ -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<Float64>(sToNanosDenominator) / static_cast<Float64>(sToNanosNumerator);
|
||||
sFrequency *= 1000000000.0;
|
||||
#elif TARGET_OS_WIN32
|
||||
LARGE_INTEGER theFrequency;
|
||||
QueryPerformanceFrequency(&theFrequency);
|
||||
sMinDelta = 1;
|
||||
sToNanosNumerator = 1000000000ULL;
|
||||
sToNanosDenominator = *((UInt64*)&theFrequency);
|
||||
sFrequency = static_cast<Float64>(*((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
|
||||
}
|
||||
234
app/PublicUtility/CAHostTimeBase.h
Normal file
234
app/PublicUtility/CAHostTimeBase.h
Normal file
@@ -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 <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <mach/mach_time.h>
|
||||
#include <pthread.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#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<SInt64>(inEndTime - inStartTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
theAnswer = static_cast<SInt64>(inStartTime - inEndTime);
|
||||
theSign = -1;
|
||||
}
|
||||
|
||||
return theSign * static_cast<SInt64>(ConvertToNanos(static_cast<UInt64>(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<UInt64>(theAnswer);
|
||||
}
|
||||
|
||||
#endif
|
||||
345
app/PublicUtility/CAMutex.cpp
Normal file
345
app/PublicUtility/CAMutex.cpp
Normal file
@@ -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 <errno.h>
|
||||
#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();
|
||||
}
|
||||
}
|
||||
192
app/PublicUtility/CAMutex.h
Normal file
192
app/PublicUtility/CAMutex.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// 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 <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <pthread.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#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
|
||||
// <https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#no-alias-analysis>.
|
||||
// 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__
|
||||
450
app/PublicUtility/CAPThread.cpp
Normal file
450
app/PublicUtility/CAPThread.cpp
Normal file
@@ -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 <mach/mach.h>
|
||||
#endif
|
||||
|
||||
// Standard Library Includes
|
||||
#include <stdio.h>
|
||||
|
||||
//==================================================================================================
|
||||
// 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<integer_t>(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<UInt32>(thePolicyInfo.ts.cur_priority);
|
||||
}
|
||||
return static_cast<UInt32>(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<UInt32>(thePolicyInfo.fifo.depress_priority);
|
||||
}
|
||||
return static_cast<UInt32>(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<UInt32>(thePolicyInfo.rr.depress_priority);
|
||||
}
|
||||
return static_cast<UInt32>(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<UInt32>(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=<time constraint>, spawning pri=%d, scheduled pri=%d\n", label, this,
|
||||
(int)mSpawningThreadPriority, (mPThread != NULL) ? (int)GetScheduledPriority() : -1);
|
||||
else
|
||||
printf("CAPThread::%s %p: pri=%d%s, spawning pri=%d, scheduled pri=%d\n", label, this, (int)mPriority, mFixedPriority ? " fixed" : "",
|
||||
(int)mSpawningThreadPriority, (mPThread != NULL) ? (int)GetScheduledPriority() : -1);
|
||||
#else
|
||||
if (mTimeConstraintSet)
|
||||
{
|
||||
printf("CAPThread::%s %p: pri=<time constraint>, spawning pri=%d, scheduled pri=%d\n", label, this,
|
||||
(int)mPriority, (mThreadHandle != NULL) ? (int)GetScheduledPriority() : -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CAPThread::%s %p: pri=%d%s, spawning pri=%d, scheduled pri=%d\n", label, this, (int)mPriority, mFixedPriority ? " fixed" : "",
|
||||
(int)mPriority, (mThreadHandle != NULL) ? (int)GetScheduledPriority() : -1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
191
app/PublicUtility/CAPThread.h
Normal file
191
app/PublicUtility/CAPThread.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
File: CAPThread.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(__CAPThread_h__)
|
||||
#define __CAPThread_h__
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// System Includes
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#else
|
||||
#include <CFBase.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#error Unsupported operating system
|
||||
#endif
|
||||
|
||||
//==================================================================================================
|
||||
// CAPThread
|
||||
//
|
||||
// This class wraps a pthread and a Win32 thread.
|
||||
// caution: long-running fixed priority threads can make the system unresponsive
|
||||
//==================================================================================================
|
||||
|
||||
class CAPThread
|
||||
{
|
||||
|
||||
// Types
|
||||
public:
|
||||
typedef void* (*ThreadRoutine)(void* inParameter);
|
||||
|
||||
// Constants
|
||||
public:
|
||||
enum
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
kMinThreadPriority = 1,
|
||||
kMaxThreadPriority = 63,
|
||||
kDefaultThreadPriority = 31,
|
||||
kMaxThreadNameLength = 64
|
||||
#elif TARGET_OS_WIN32
|
||||
kMinThreadPriority = 1,
|
||||
kMaxThreadPriority = 31,
|
||||
kDefaultThreadPriority = THREAD_PRIORITY_NORMAL,
|
||||
kMaxThreadNameLength = 256
|
||||
#endif
|
||||
};
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPriority = kDefaultThreadPriority, bool inFixedPriority=false, bool inAutoDelete=false, const char* inThreadName = NULL);
|
||||
CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible, bool inAutoDelete=false, const char* inThreadName = NULL);
|
||||
virtual ~CAPThread();
|
||||
|
||||
// Properties
|
||||
public:
|
||||
#if TARGET_OS_MAC
|
||||
typedef pthread_t NativeThread;
|
||||
|
||||
NativeThread GetNativeThread() { return mPThread; }
|
||||
static NativeThread GetCurrentThread() { return pthread_self(); }
|
||||
static bool IsNativeThreadsEqual(NativeThread a, NativeThread b) { return (a==b); }
|
||||
|
||||
bool operator==(NativeThread b) { return pthread_equal(mPThread,b); }
|
||||
|
||||
pthread_t GetPThread() const { return mPThread; }
|
||||
bool IsCurrentThread() const { return (0 != mPThread) && (pthread_self() == mPThread); }
|
||||
bool IsRunning() const { return 0 != mPThread; }
|
||||
static UInt32 getScheduledPriority(pthread_t inThread, int inPriorityKind);
|
||||
#elif TARGET_OS_WIN32
|
||||
typedef unsigned long NativeThread;
|
||||
|
||||
NativeThread GetNativeThread() { return mThreadID; }
|
||||
static NativeThread GetCurrentThread() { return GetCurrentThreadId(); }
|
||||
static bool IsNativeThreadsEqual(NativeThread a, NativeThread b) { return (a==b); }
|
||||
|
||||
bool operator ==(NativeThread b) { return (mThreadID==b); }
|
||||
|
||||
HANDLE GetThreadHandle() const { return mThreadHandle; }
|
||||
UInt32 GetThreadID() const { return mThreadID; }
|
||||
bool IsCurrentThread() const { return (0 != mThreadID) && (GetCurrentThreadId() == mThreadID); }
|
||||
bool IsRunning() const { return 0 != mThreadID; }
|
||||
#endif
|
||||
|
||||
bool IsTimeShareThread() const { return !mTimeConstraintSet; }
|
||||
bool IsTimeConstraintThread() const { return mTimeConstraintSet; }
|
||||
|
||||
UInt32 GetPriority() const { return mPriority; }
|
||||
UInt32 GetScheduledPriority();
|
||||
static UInt32 GetScheduledPriority(NativeThread thread);
|
||||
void SetPriority(UInt32 inPriority, bool inFixedPriority=false);
|
||||
static void SetPriority(NativeThread inThread, UInt32 inPriority, bool inFixedPriority = false);
|
||||
|
||||
void GetTimeConstraints(UInt32& outPeriod, UInt32& outComputation, UInt32& outConstraint, bool& outIsPreemptible) const { outPeriod = mPeriod; outComputation = mComputation; outConstraint = mConstraint; outIsPreemptible = mIsPreemptible; }
|
||||
void SetTimeConstraints(UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible);
|
||||
void ClearTimeConstraints() { SetPriority(mPriority); }
|
||||
|
||||
bool WillAutoDelete() const { return mAutoDelete; }
|
||||
void SetAutoDelete(bool b) { mAutoDelete = b; }
|
||||
|
||||
void SetName(const char* inThreadName);
|
||||
|
||||
#if CoreAudio_Debug
|
||||
void DebugPriority(const char *label);
|
||||
#endif
|
||||
|
||||
// Actions
|
||||
public:
|
||||
virtual void Start();
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
#if TARGET_OS_MAC
|
||||
static void* Entry(CAPThread* inCAPThread);
|
||||
#elif TARGET_OS_WIN32
|
||||
static UInt32 WINAPI Entry(CAPThread* inCAPThread);
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
pthread_t mPThread;
|
||||
UInt32 mSpawningThreadPriority;
|
||||
#elif TARGET_OS_WIN32
|
||||
HANDLE mThreadHandle;
|
||||
unsigned long mThreadID;
|
||||
#endif
|
||||
ThreadRoutine mThreadRoutine;
|
||||
void* mThreadParameter;
|
||||
char mThreadName[kMaxThreadNameLength];
|
||||
UInt32 mPriority;
|
||||
UInt32 mPeriod;
|
||||
UInt32 mComputation;
|
||||
UInt32 mConstraint;
|
||||
bool mIsPreemptible;
|
||||
bool mTimeConstraintSet;
|
||||
bool mFixedPriority;
|
||||
bool mAutoDelete; // delete self when thread terminates
|
||||
};
|
||||
|
||||
#endif
|
||||
292
app/PublicUtility/CAPropertyAddress.h
Normal file
292
app/PublicUtility/CAPropertyAddress.h
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
File: CAPropertyAddress.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(__CAPropertyAddress_h__)
|
||||
#define __CAPropertyAddress_h__
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
|
||||
// System Includes
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
|
||||
// Standard Library Includes
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
//==================================================================================================
|
||||
// CAPropertyAddress
|
||||
//
|
||||
// CAPropertyAddress extends the AudioObjectPropertyAddress structure to C++ including constructors
|
||||
// and other utility operations. Note that there is no defined operator< or operator== because the
|
||||
// presence of wildcards for the fields make comparisons ambiguous without specifying whether or
|
||||
// not to take the wildcards into account. Consequently, if you want to use this struct in an STL
|
||||
// data structure, you'll need to specify the approriate function object explicitly in the template
|
||||
// declaration.
|
||||
//==================================================================================================
|
||||
|
||||
struct CAPropertyAddress
|
||||
:
|
||||
public AudioObjectPropertyAddress
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAPropertyAddress() : AudioObjectPropertyAddress() { mSelector = 0; mScope = kAudioObjectPropertyScopeGlobal; mElement = kAudioObjectPropertyElementMaster; }
|
||||
CAPropertyAddress(AudioObjectPropertySelector inSelector) : AudioObjectPropertyAddress() { mSelector = inSelector; mScope = kAudioObjectPropertyScopeGlobal; mElement = kAudioObjectPropertyElementMaster; }
|
||||
CAPropertyAddress(AudioObjectPropertySelector inSelector, AudioObjectPropertyScope inScope) : AudioObjectPropertyAddress() { mSelector = inSelector; mScope = inScope; mElement = kAudioObjectPropertyElementMaster; }
|
||||
CAPropertyAddress(AudioObjectPropertySelector inSelector, AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) : AudioObjectPropertyAddress() { mSelector = inSelector; mScope = inScope; mElement = inElement; }
|
||||
CAPropertyAddress(const AudioObjectPropertyAddress& inAddress) : AudioObjectPropertyAddress(inAddress){}
|
||||
CAPropertyAddress(const CAPropertyAddress& inAddress) : AudioObjectPropertyAddress(inAddress){}
|
||||
CAPropertyAddress& operator=(const AudioObjectPropertyAddress& inAddress) { AudioObjectPropertyAddress::operator=(inAddress); return *this; }
|
||||
CAPropertyAddress& operator=(const CAPropertyAddress& inAddress) { AudioObjectPropertyAddress::operator=(inAddress); return *this; }
|
||||
|
||||
// Operations
|
||||
public:
|
||||
static bool IsSameAddress(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) { return (inAddress1.mScope == inAddress2.mScope) && (inAddress1.mSelector == inAddress2.mSelector) && (inAddress1.mElement == inAddress2.mElement); }
|
||||
static bool IsLessThanAddress(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) { bool theAnswer = false; if(inAddress1.mScope != inAddress2.mScope) { theAnswer = inAddress1.mScope < inAddress2.mScope; } else if(inAddress1.mSelector != inAddress2.mSelector) { theAnswer = inAddress1.mSelector < inAddress2.mSelector; } else { theAnswer = inAddress1.mElement < inAddress2.mElement; } return theAnswer; }
|
||||
static bool IsCongruentSelector(AudioObjectPropertySelector inSelector1, AudioObjectPropertySelector inSelector2) { return (inSelector1 == inSelector2) || (inSelector1 == kAudioObjectPropertySelectorWildcard) || (inSelector2 == kAudioObjectPropertySelectorWildcard); }
|
||||
static bool IsCongruentScope(AudioObjectPropertyScope inScope1, AudioObjectPropertyScope inScope2) { return (inScope1 == inScope2) || (inScope1 == kAudioObjectPropertyScopeWildcard) || (inScope2 == kAudioObjectPropertyScopeWildcard); }
|
||||
static bool IsCongruentElement(AudioObjectPropertyElement inElement1, AudioObjectPropertyElement inElement2) { return (inElement1 == inElement2) || (inElement1 == kAudioObjectPropertyElementWildcard) || (inElement2 == kAudioObjectPropertyElementWildcard); }
|
||||
static bool IsCongruentAddress(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) { return IsCongruentScope(inAddress1.mScope, inAddress2.mScope) && IsCongruentSelector(inAddress1.mSelector, inAddress2.mSelector) && IsCongruentElement(inAddress1.mElement, inAddress2.mElement); }
|
||||
static bool IsCongruentLessThanAddress(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) { bool theAnswer = false; if(!IsCongruentScope(inAddress1.mScope, inAddress2.mScope)) { theAnswer = inAddress1.mScope < inAddress2.mScope; } else if(!IsCongruentSelector(inAddress1.mSelector, inAddress2.mSelector)) { theAnswer = inAddress1.mSelector < inAddress2.mSelector; } else if(!IsCongruentElement(inAddress1.mElement, inAddress2.mElement)) { theAnswer = inAddress1.mElement < inAddress2.mElement; } return theAnswer; }
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
// CAPropertyAddressList
|
||||
//
|
||||
// An auto-resizing array of CAPropertyAddress structures.
|
||||
//==================================================================================================
|
||||
|
||||
class CAPropertyAddressList
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAPropertyAddressList() : mAddressList(), mToken(NULL) {}
|
||||
explicit CAPropertyAddressList(void* inToken) : mAddressList(), mToken(inToken) {}
|
||||
explicit CAPropertyAddressList(uintptr_t inToken) : mAddressList(), mToken(reinterpret_cast<void*>(inToken)) {}
|
||||
CAPropertyAddressList(const CAPropertyAddressList& inAddressList) : mAddressList(inAddressList.mAddressList), mToken(inAddressList.mToken) {}
|
||||
CAPropertyAddressList& operator=(const CAPropertyAddressList& inAddressList) { mAddressList = inAddressList.mAddressList; mToken = inAddressList.mToken; return *this; }
|
||||
~CAPropertyAddressList() {}
|
||||
|
||||
// Operations
|
||||
public:
|
||||
void* GetToken() const { return mToken; }
|
||||
void SetToken(void* inToken) { mToken = inToken; }
|
||||
|
||||
uintptr_t GetIntToken() const { return reinterpret_cast<uintptr_t>(mToken); }
|
||||
void SetIntToken(uintptr_t inToken) { mToken = reinterpret_cast<void*>(inToken); }
|
||||
|
||||
AudioObjectID GetAudioObjectIDToken() const { return static_cast<AudioObjectID>(reinterpret_cast<uintptr_t>(mToken)); }
|
||||
|
||||
bool IsEmpty() const { return mAddressList.empty(); }
|
||||
UInt32 GetNumberItems() const { return ToUInt32(mAddressList.size()); }
|
||||
void GetItemByIndex(UInt32 inIndex, AudioObjectPropertyAddress& outAddress) const { if(inIndex < mAddressList.size()) { outAddress = mAddressList.at(inIndex); } }
|
||||
const AudioObjectPropertyAddress* GetItems() const { return &(*mAddressList.begin()); }
|
||||
AudioObjectPropertyAddress* GetItems() { return &(*mAddressList.begin()); }
|
||||
|
||||
bool HasItem(const AudioObjectPropertyAddress& inAddress) const { AddressList::const_iterator theIterator = std::find_if(mAddressList.begin(), mAddressList.end(), [&inAddress](const CAPropertyAddress& addr) { return CAPropertyAddress::IsCongruentAddress(addr, inAddress); }); return theIterator != mAddressList.end(); }
|
||||
bool HasExactItem(const AudioObjectPropertyAddress& inAddress) const { AddressList::const_iterator theIterator = std::find_if(mAddressList.begin(), mAddressList.end(), [&inAddress](const CAPropertyAddress& addr) { return CAPropertyAddress::IsSameAddress(addr, inAddress); }); return theIterator != mAddressList.end(); }
|
||||
|
||||
void AppendItem(const AudioObjectPropertyAddress& inAddress) { mAddressList.push_back(inAddress); }
|
||||
void AppendUniqueItem(const AudioObjectPropertyAddress& inAddress) { if(!HasItem(inAddress)) { mAddressList.push_back(inAddress); } }
|
||||
void AppendUniqueExactItem(const AudioObjectPropertyAddress& inAddress) { if(!HasExactItem(inAddress)) { mAddressList.push_back(inAddress); } }
|
||||
void InsertItemAtIndex(UInt32 inIndex, const AudioObjectPropertyAddress& inAddress) { if(inIndex < mAddressList.size()) { AddressList::iterator theIterator = mAddressList.begin(); std::advance(theIterator, static_cast<int>(inIndex)); mAddressList.insert(theIterator, inAddress); } else { mAddressList.push_back(inAddress); } }
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
void EraseExactItem(const AudioObjectPropertyAddress& inAddress) { AddressList::iterator theIterator = std::find_if(mAddressList.begin(), mAddressList.end(), [&inAddress](const CAPropertyAddress& addr) { return CAPropertyAddress::IsSameAddress(addr, inAddress); }); if(theIterator != mAddressList.end()) { mAddressList.erase(theIterator); } }
|
||||
#pragma clang diagnostic pop
|
||||
void EraseItemAtIndex(UInt32 inIndex) { if(inIndex < mAddressList.size()) { AddressList::iterator theIterator = mAddressList.begin(); std::advance(theIterator, static_cast<int>(inIndex)); mAddressList.erase(theIterator); } }
|
||||
void EraseAllItems() { mAddressList.clear(); }
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
typedef std::vector<CAPropertyAddress> AddressList;
|
||||
|
||||
AddressList mAddressList;
|
||||
void* mToken;
|
||||
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
// CAPropertyAddressListVector
|
||||
//
|
||||
// An auto-resizing array of CAPropertyAddressList objects.
|
||||
//==================================================================================================
|
||||
|
||||
class CAPropertyAddressListVector
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAPropertyAddressListVector() : mAddressListVector() {}
|
||||
CAPropertyAddressListVector(const CAPropertyAddressListVector& inAddressListVector) : mAddressListVector(inAddressListVector.mAddressListVector) {}
|
||||
CAPropertyAddressListVector& operator=(const CAPropertyAddressListVector& inAddressListVector) { mAddressListVector = inAddressListVector.mAddressListVector; return *this; }
|
||||
~CAPropertyAddressListVector() {}
|
||||
|
||||
// Operations
|
||||
public:
|
||||
bool IsEmpty() const { return mAddressListVector.empty(); }
|
||||
bool HasAnyNonEmptyItems() const;
|
||||
bool HasAnyItemsWithAddress(const AudioObjectPropertyAddress& inAddress) const;
|
||||
bool HasAnyItemsWithExactAddress(const AudioObjectPropertyAddress& inAddress) const;
|
||||
|
||||
UInt32 GetNumberItems() const { return ToUInt32(mAddressListVector.size()); }
|
||||
const CAPropertyAddressList& GetItemByIndex(UInt32 inIndex) const { return mAddressListVector.at(inIndex); }
|
||||
CAPropertyAddressList& GetItemByIndex(UInt32 inIndex) { return mAddressListVector.at(inIndex); }
|
||||
const CAPropertyAddressList* GetItemByToken(void* inToken) const;
|
||||
CAPropertyAddressList* GetItemByToken(void* inToken);
|
||||
const CAPropertyAddressList* GetItemByIntToken(uintptr_t inToken) const;
|
||||
CAPropertyAddressList* GetItemByIntToken(uintptr_t inToken);
|
||||
|
||||
void AppendItem(const CAPropertyAddressList& inAddressList) { mAddressListVector.push_back(inAddressList); }
|
||||
void EraseAllItems() { mAddressListVector.clear(); }
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
typedef std::vector<CAPropertyAddressList> AddressListVector;
|
||||
|
||||
AddressListVector mAddressListVector;
|
||||
|
||||
};
|
||||
|
||||
inline bool CAPropertyAddressListVector::HasAnyNonEmptyItems() const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !theAnswer && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
theAnswer = !theIterator->IsEmpty();
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline bool CAPropertyAddressListVector::HasAnyItemsWithAddress(const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !theAnswer && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
theAnswer = theIterator->HasItem(inAddress);
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline bool CAPropertyAddressListVector::HasAnyItemsWithExactAddress(const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !theAnswer && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
theAnswer = theIterator->HasExactItem(inAddress);
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline const CAPropertyAddressList* CAPropertyAddressListVector::GetItemByToken(void* inToken) const
|
||||
{
|
||||
const CAPropertyAddressList* theAnswer = NULL;
|
||||
bool wasFound = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !wasFound && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
if(theIterator->GetToken() == inToken)
|
||||
{
|
||||
wasFound = true;
|
||||
theAnswer = &(*theIterator);
|
||||
}
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline CAPropertyAddressList* CAPropertyAddressListVector::GetItemByToken(void* inToken)
|
||||
{
|
||||
CAPropertyAddressList* theAnswer = NULL;
|
||||
bool wasFound = false;
|
||||
for(AddressListVector::iterator theIterator = mAddressListVector.begin(); !wasFound && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
if(theIterator->GetToken() == inToken)
|
||||
{
|
||||
wasFound = true;
|
||||
theAnswer = &(*theIterator);
|
||||
}
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline const CAPropertyAddressList* CAPropertyAddressListVector::GetItemByIntToken(uintptr_t inToken) const
|
||||
{
|
||||
const CAPropertyAddressList* theAnswer = NULL;
|
||||
bool wasFound = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !wasFound && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
if(theIterator->GetIntToken() == inToken)
|
||||
{
|
||||
wasFound = true;
|
||||
theAnswer = &(*theIterator);
|
||||
}
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline CAPropertyAddressList* CAPropertyAddressListVector::GetItemByIntToken(uintptr_t inToken)
|
||||
{
|
||||
CAPropertyAddressList* theAnswer = NULL;
|
||||
bool wasFound = false;
|
||||
for(AddressListVector::iterator theIterator = mAddressListVector.begin(); !wasFound && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
if(theIterator->GetIntToken() == inToken)
|
||||
{
|
||||
wasFound = true;
|
||||
theAnswer = &(*theIterator);
|
||||
}
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
#endif
|
||||
319
app/PublicUtility/CARingBuffer.cpp
Normal file
319
app/PublicUtility/CARingBuffer.cpp
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
File: CARingBuffer.cpp
|
||||
Abstract: CARingBuffer.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 "CARingBuffer.h"
|
||||
#include "CABitOperations.h"
|
||||
#include "CAAutoDisposer.h"
|
||||
#include "CAAtomic.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
CARingBuffer::CARingBuffer() :
|
||||
mBuffers(NULL), mNumberChannels(0), mCapacityFrames(0), mCapacityBytes(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CARingBuffer::~CARingBuffer()
|
||||
{
|
||||
Deallocate();
|
||||
}
|
||||
|
||||
|
||||
void CARingBuffer::Allocate(int nChannels, UInt32 bytesPerFrame, UInt32 capacityFrames)
|
||||
{
|
||||
Deallocate();
|
||||
|
||||
capacityFrames = NextPowerOfTwo(capacityFrames);
|
||||
|
||||
mNumberChannels = nChannels;
|
||||
mBytesPerFrame = bytesPerFrame;
|
||||
mCapacityFrames = capacityFrames;
|
||||
mCapacityFramesMask = capacityFrames - 1;
|
||||
mCapacityBytes = bytesPerFrame * capacityFrames;
|
||||
|
||||
// put everything in one memory allocation, first the pointers, then the deinterleaved channels
|
||||
UInt32 allocSize = (mCapacityBytes + sizeof(Byte *)) * nChannels;
|
||||
Byte *p = (Byte *)CA_malloc(allocSize);
|
||||
memset(p, 0, allocSize);
|
||||
mBuffers = (Byte **)p;
|
||||
p += nChannels * sizeof(Byte *);
|
||||
for (int i = 0; i < nChannels; ++i) {
|
||||
mBuffers[i] = p;
|
||||
p += mCapacityBytes;
|
||||
}
|
||||
|
||||
for (UInt32 i = 0; i<kGeneralRingTimeBoundsQueueSize; ++i)
|
||||
{
|
||||
mTimeBoundsQueue[i].mStartTime = 0;
|
||||
mTimeBoundsQueue[i].mEndTime = 0;
|
||||
mTimeBoundsQueue[i].mUpdateCounter = 0;
|
||||
}
|
||||
mTimeBoundsQueuePtr = 0;
|
||||
}
|
||||
|
||||
void CARingBuffer::Deallocate()
|
||||
{
|
||||
if (mBuffers) {
|
||||
free(mBuffers);
|
||||
mBuffers = NULL;
|
||||
}
|
||||
mNumberChannels = 0;
|
||||
mCapacityBytes = 0;
|
||||
mCapacityFrames = 0;
|
||||
}
|
||||
|
||||
inline void ZeroRange(Byte **buffers, int nchannels, int offset, int nbytes)
|
||||
{
|
||||
while (--nchannels >= 0) {
|
||||
memset(*buffers + offset, 0, nbytes);
|
||||
++buffers;
|
||||
}
|
||||
}
|
||||
|
||||
inline void StoreABL(Byte **buffers, int destOffset, const AudioBufferList *abl, int srcOffset, int nbytes)
|
||||
{
|
||||
int nchannels = abl->mNumberBuffers;
|
||||
const AudioBuffer *src = abl->mBuffers;
|
||||
while (--nchannels >= 0) {
|
||||
if (srcOffset > (int)src->mDataByteSize) continue;
|
||||
memcpy(*buffers + destOffset, (Byte *)src->mData + srcOffset, std::min(nbytes, (int)src->mDataByteSize - srcOffset));
|
||||
++buffers;
|
||||
++src;
|
||||
}
|
||||
}
|
||||
|
||||
inline void FetchABL(AudioBufferList *abl, int destOffset, Byte **buffers, int srcOffset, int nbytes)
|
||||
{
|
||||
int nchannels = abl->mNumberBuffers;
|
||||
AudioBuffer *dest = abl->mBuffers;
|
||||
while (--nchannels >= 0) {
|
||||
if (destOffset > (int)dest->mDataByteSize) continue;
|
||||
memcpy((Byte *)dest->mData + destOffset, *buffers + srcOffset, std::min(nbytes, (int)dest->mDataByteSize - destOffset));
|
||||
++buffers;
|
||||
++dest;
|
||||
}
|
||||
}
|
||||
|
||||
inline void ZeroABL(AudioBufferList *abl, int destOffset, int nbytes)
|
||||
{
|
||||
int nBuffers = abl->mNumberBuffers;
|
||||
AudioBuffer *dest = abl->mBuffers;
|
||||
while (--nBuffers >= 0) {
|
||||
if (destOffset > (int)dest->mDataByteSize) continue;
|
||||
memset((Byte *)dest->mData + destOffset, 0, std::min(nbytes, (int)dest->mDataByteSize - destOffset));
|
||||
++dest;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CARingBufferError CARingBuffer::Store(const AudioBufferList *abl, UInt32 framesToWrite, SampleTime startWrite)
|
||||
{
|
||||
if (framesToWrite == 0)
|
||||
return kCARingBufferError_OK;
|
||||
|
||||
if (framesToWrite > mCapacityFrames)
|
||||
return kCARingBufferError_TooMuch; // too big!
|
||||
|
||||
SampleTime endWrite = startWrite + framesToWrite;
|
||||
|
||||
if (startWrite < EndTime()) {
|
||||
// going backwards, throw everything out
|
||||
SetTimeBounds(startWrite, startWrite);
|
||||
} else if (endWrite - StartTime() <= mCapacityFrames) {
|
||||
// the buffer has not yet wrapped and will not need to
|
||||
} else {
|
||||
// advance the start time past the region we are about to overwrite
|
||||
SampleTime newStart = endWrite - mCapacityFrames; // one buffer of time behind where we're writing
|
||||
SampleTime newEnd = std::max(newStart, EndTime());
|
||||
SetTimeBounds(newStart, newEnd);
|
||||
}
|
||||
|
||||
// write the new frames
|
||||
Byte **buffers = mBuffers;
|
||||
int nchannels = mNumberChannels;
|
||||
int offset0, offset1, nbytes;
|
||||
SampleTime curEnd = EndTime();
|
||||
|
||||
if (startWrite > curEnd) {
|
||||
// we are skipping some samples, so zero the range we are skipping
|
||||
offset0 = FrameOffset(curEnd);
|
||||
offset1 = FrameOffset(startWrite);
|
||||
if (offset0 < offset1)
|
||||
ZeroRange(buffers, nchannels, offset0, offset1 - offset0);
|
||||
else {
|
||||
ZeroRange(buffers, nchannels, offset0, mCapacityBytes - offset0);
|
||||
ZeroRange(buffers, nchannels, 0, offset1);
|
||||
}
|
||||
offset0 = offset1;
|
||||
} else {
|
||||
offset0 = FrameOffset(startWrite);
|
||||
}
|
||||
|
||||
offset1 = FrameOffset(endWrite);
|
||||
if (offset0 < offset1)
|
||||
StoreABL(buffers, offset0, abl, 0, offset1 - offset0);
|
||||
else {
|
||||
nbytes = mCapacityBytes - offset0;
|
||||
StoreABL(buffers, offset0, abl, 0, nbytes);
|
||||
StoreABL(buffers, 0, abl, nbytes, offset1);
|
||||
}
|
||||
|
||||
// now update the end time
|
||||
SetTimeBounds(StartTime(), endWrite);
|
||||
|
||||
return kCARingBufferError_OK; // success
|
||||
}
|
||||
|
||||
void CARingBuffer::SetTimeBounds(SampleTime startTime, SampleTime endTime)
|
||||
{
|
||||
UInt32 nextPtr = mTimeBoundsQueuePtr + 1;
|
||||
UInt32 index = nextPtr & kGeneralRingTimeBoundsQueueMask;
|
||||
|
||||
mTimeBoundsQueue[index].mStartTime = startTime;
|
||||
mTimeBoundsQueue[index].mEndTime = endTime;
|
||||
mTimeBoundsQueue[index].mUpdateCounter = nextPtr;
|
||||
CAAtomicCompareAndSwap32Barrier(mTimeBoundsQueuePtr, mTimeBoundsQueuePtr + 1, (SInt32*)&mTimeBoundsQueuePtr);
|
||||
}
|
||||
|
||||
CARingBufferError CARingBuffer::GetTimeBounds(SampleTime &startTime, SampleTime &endTime)
|
||||
{
|
||||
for (int i=0; i<8; ++i) // fail after a few tries.
|
||||
{
|
||||
UInt32 curPtr = mTimeBoundsQueuePtr;
|
||||
UInt32 index = curPtr & kGeneralRingTimeBoundsQueueMask;
|
||||
CARingBuffer::TimeBounds* bounds = mTimeBoundsQueue + index;
|
||||
|
||||
startTime = bounds->mStartTime;
|
||||
endTime = bounds->mEndTime;
|
||||
UInt32 newPtr = bounds->mUpdateCounter;
|
||||
|
||||
if (newPtr == curPtr)
|
||||
return kCARingBufferError_OK;
|
||||
}
|
||||
return kCARingBufferError_CPUOverload;
|
||||
}
|
||||
|
||||
CARingBufferError CARingBuffer::ClipTimeBounds(SampleTime& startRead, SampleTime& endRead)
|
||||
{
|
||||
SampleTime startTime, endTime;
|
||||
|
||||
CARingBufferError err = GetTimeBounds(startTime, endTime);
|
||||
if (err) return err;
|
||||
|
||||
if (startRead > endTime || endRead < startTime) {
|
||||
endRead = startRead;
|
||||
return kCARingBufferError_OK;
|
||||
}
|
||||
|
||||
startRead = std::max(startRead, startTime);
|
||||
endRead = std::min(endRead, endTime);
|
||||
endRead = std::max(endRead, startRead);
|
||||
|
||||
return kCARingBufferError_OK; // success
|
||||
}
|
||||
|
||||
CARingBufferError CARingBuffer::Fetch(AudioBufferList *abl, UInt32 nFrames, SampleTime startRead)
|
||||
{
|
||||
if (nFrames == 0)
|
||||
return kCARingBufferError_OK;
|
||||
|
||||
startRead = std::max(0LL, startRead);
|
||||
|
||||
SampleTime endRead = startRead + nFrames;
|
||||
|
||||
SampleTime startRead0 = startRead;
|
||||
SampleTime endRead0 = endRead;
|
||||
|
||||
CARingBufferError err = ClipTimeBounds(startRead, endRead);
|
||||
if (err) return err;
|
||||
|
||||
if (startRead == endRead) {
|
||||
ZeroABL(abl, 0, nFrames * mBytesPerFrame);
|
||||
return kCARingBufferError_OK;
|
||||
}
|
||||
|
||||
SInt32 byteSize = (SInt32)((endRead - startRead) * mBytesPerFrame);
|
||||
|
||||
SInt32 destStartByteOffset = std::max((SInt32)0, (SInt32)((startRead - startRead0) * mBytesPerFrame));
|
||||
|
||||
if (destStartByteOffset > 0) {
|
||||
ZeroABL(abl, 0, std::min((SInt32)(nFrames * mBytesPerFrame), destStartByteOffset));
|
||||
}
|
||||
|
||||
SInt32 destEndSize = std::max((SInt32)0, (SInt32)(endRead0 - endRead));
|
||||
if (destEndSize > 0) {
|
||||
ZeroABL(abl, destStartByteOffset + byteSize, destEndSize * mBytesPerFrame);
|
||||
}
|
||||
|
||||
Byte **buffers = mBuffers;
|
||||
int offset0 = FrameOffset(startRead);
|
||||
int offset1 = FrameOffset(endRead);
|
||||
int nbytes;
|
||||
|
||||
if (offset0 < offset1) {
|
||||
nbytes = offset1 - offset0;
|
||||
FetchABL(abl, destStartByteOffset, buffers, offset0, nbytes);
|
||||
} else {
|
||||
nbytes = mCapacityBytes - offset0;
|
||||
FetchABL(abl, destStartByteOffset, buffers, offset0, nbytes);
|
||||
FetchABL(abl, destStartByteOffset + nbytes, buffers, 0, offset1);
|
||||
nbytes += offset1;
|
||||
}
|
||||
|
||||
int nchannels = abl->mNumberBuffers;
|
||||
AudioBuffer *dest = abl->mBuffers;
|
||||
while (--nchannels >= 0)
|
||||
{
|
||||
dest->mDataByteSize = nbytes;
|
||||
dest++;
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
126
app/PublicUtility/CARingBuffer.h
Normal file
126
app/PublicUtility/CARingBuffer.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
File: CARingBuffer.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(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef CARingBuffer_Header
|
||||
#define CARingBuffer_Header
|
||||
|
||||
enum {
|
||||
kCARingBufferError_OK = 0,
|
||||
kCARingBufferError_TooMuch = 3, // fetch start time is earlier than buffer start time and fetch end time is later than buffer end time
|
||||
kCARingBufferError_CPUOverload = 4 // the reader is unable to get enough CPU cycles to capture a consistent snapshot of the time bounds
|
||||
};
|
||||
|
||||
typedef SInt32 CARingBufferError;
|
||||
|
||||
const UInt32 kGeneralRingTimeBoundsQueueSize = 32;
|
||||
const UInt32 kGeneralRingTimeBoundsQueueMask = kGeneralRingTimeBoundsQueueSize - 1;
|
||||
|
||||
class CARingBuffer {
|
||||
public:
|
||||
typedef SInt64 SampleTime;
|
||||
|
||||
CARingBuffer();
|
||||
~CARingBuffer();
|
||||
|
||||
void Allocate(int nChannels, UInt32 bytesPerFrame, UInt32 capacityFrames);
|
||||
// capacityFrames will be rounded up to a power of 2
|
||||
void Deallocate();
|
||||
|
||||
CARingBufferError Store(const AudioBufferList *abl, UInt32 nFrames, SampleTime frameNumber);
|
||||
// Copy nFrames of data into the ring buffer at the specified sample time.
|
||||
// The sample time should normally increase sequentially, though gaps
|
||||
// are filled with zeroes. A sufficiently large gap effectively empties
|
||||
// the buffer before storing the new data.
|
||||
|
||||
// If frameNumber is less than the previous frame number, the behavior is undefined.
|
||||
|
||||
// Return false for failure (buffer not large enough).
|
||||
|
||||
CARingBufferError Fetch(AudioBufferList *abl, UInt32 nFrames, SampleTime frameNumber);
|
||||
// will alter mDataByteSize of the buffers
|
||||
|
||||
CARingBufferError GetTimeBounds(SampleTime &startTime, SampleTime &endTime);
|
||||
|
||||
protected:
|
||||
|
||||
UInt32 FrameOffset(SampleTime frameNumber) { return (frameNumber & mCapacityFramesMask) * mBytesPerFrame; }
|
||||
|
||||
CARingBufferError ClipTimeBounds(SampleTime& startRead, SampleTime& endRead);
|
||||
|
||||
// these should only be called from Store.
|
||||
SampleTime StartTime() const { return mTimeBoundsQueue[mTimeBoundsQueuePtr & kGeneralRingTimeBoundsQueueMask].mStartTime; }
|
||||
SampleTime EndTime() const { return mTimeBoundsQueue[mTimeBoundsQueuePtr & kGeneralRingTimeBoundsQueueMask].mEndTime; }
|
||||
void SetTimeBounds(SampleTime startTime, SampleTime endTime);
|
||||
|
||||
protected:
|
||||
Byte ** mBuffers; // allocated in one chunk of memory
|
||||
int mNumberChannels;
|
||||
UInt32 mBytesPerFrame; // within one deinterleaved channel
|
||||
UInt32 mCapacityFrames; // per channel, must be a power of 2
|
||||
UInt32 mCapacityFramesMask;
|
||||
UInt32 mCapacityBytes; // per channel
|
||||
|
||||
// range of valid sample time in the buffer
|
||||
typedef struct {
|
||||
volatile SampleTime mStartTime;
|
||||
volatile SampleTime mEndTime;
|
||||
volatile UInt32 mUpdateCounter;
|
||||
} TimeBounds;
|
||||
|
||||
CARingBuffer::TimeBounds mTimeBoundsQueue[kGeneralRingTimeBoundsQueueSize];
|
||||
UInt32 mTimeBoundsQueuePtr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
50
app/PublicUtility/VCDebugLogging.c
Normal file
50
app/PublicUtility/VCDebugLogging.c
Normal file
@@ -0,0 +1,50 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VCDebugLogging.c
|
||||
// PublicUtility
|
||||
//
|
||||
// Copyright © 2020, 2024 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "VCDebugLogging.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
// It's probably not ideal to use a global variable for this, but it's a lot easier.
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
// Enable debug logging by default in debug builds.
|
||||
int gDebugLoggingIsEnabled = 1;
|
||||
#else
|
||||
int gDebugLoggingIsEnabled = 0;
|
||||
#endif
|
||||
|
||||
// We don't bother synchronising accesses of gDebugLoggingIsEnabled because it isn't really
|
||||
// necessary and would complicate code that accesses it on realtime threads.
|
||||
int VCDebugLoggingIsEnabled(void)
|
||||
{
|
||||
return gDebugLoggingIsEnabled;
|
||||
}
|
||||
|
||||
void VCSetDebugLoggingEnabled(int inEnabled)
|
||||
{
|
||||
gDebugLoggingIsEnabled = inEnabled;
|
||||
}
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
63
app/PublicUtility/VCDebugLogging.h
Normal file
63
app/PublicUtility/VCDebugLogging.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VCDebugLogging.h
|
||||
// PublicUtility
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
// Functions to globally enable/disable debug logging, i.e. more detailed logging to help diagnose
|
||||
// bugs. If debug logging is enabled, the DebugMsg macro from CADebugMacros.h (and possibly others)
|
||||
// will log messages. If not, it won't do anything.
|
||||
//
|
||||
// If the preprocessor macro CoreAudio_UseSysLog is true, which is currently the case for all build
|
||||
// variants (see VCApp/VCApp.xcodeproj/project.pbxproj and
|
||||
// VCDriver/VCDriver.xcodeproj/project.pbxproj), those messages will be logged using syslog and
|
||||
// can be read using Console.app. Try searching for "background music", "bgm" or "coreaudiod".
|
||||
//
|
||||
// Debug logging is enabled by default in debug builds, but in release builds you have to enable it
|
||||
// by option-clicking the status bar icon and then checking the Debug Logging menu item. Enabling
|
||||
// debug logging probably won't cause glitches, but we don't try to guarantee that and it's not
|
||||
// well tested.
|
||||
//
|
||||
|
||||
#ifndef PublicUtility__VCDebugLogging
|
||||
#define PublicUtility__VCDebugLogging
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
/*!
|
||||
* @return Non-zero if debug logging is globally enabled. (Probably -- it's not synchronised.)
|
||||
* Real-time safe.
|
||||
*/
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
int VCDebugLoggingIsEnabled(void);
|
||||
|
||||
/*!
|
||||
* @param inEnabled Non-zero to globally enable debug logging, zero to disable it. The change might
|
||||
* not be visible to other threads immediately.
|
||||
*/
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
void VCSetDebugLoggingEnabled(int inEnabled);
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* PublicUtility__VCDebugLogging */
|
||||
|
||||
104
app/PublicUtility/VCThreadSafetyAnalysis.h
Normal file
104
app/PublicUtility/VCThreadSafetyAnalysis.h
Normal file
@@ -0,0 +1,104 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Original licence at the end of this file.
|
||||
|
||||
//
|
||||
// VCThreadSafetyAnalysis.h
|
||||
// PublicUtility
|
||||
//
|
||||
// © Copyright 2007-2020, The Clang Team
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
// Macros that wrap Clang's attributes for statically checking concurrency properties. From
|
||||
// <https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#mutexheader>.
|
||||
//
|
||||
|
||||
|
||||
#ifndef PublicUtility__VCThreadSafetyAnalysis
|
||||
#define PublicUtility__VCThreadSafetyAnalysis
|
||||
|
||||
// Enable thread safety attributes only with clang.
|
||||
// The attributes can be safely erased when compiling with other compilers.
|
||||
#if defined(__clang__) && (!defined(SWIG))
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||
#endif
|
||||
|
||||
#define CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
|
||||
|
||||
#define SCOPED_CAPABILITY \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
|
||||
|
||||
#define GUARDED_BY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
|
||||
|
||||
#define PT_GUARDED_BY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
|
||||
|
||||
#define ACQUIRED_BEFORE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
|
||||
|
||||
#define ACQUIRED_AFTER(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
|
||||
|
||||
#define REQUIRES(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
|
||||
|
||||
#define REQUIRES_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define ACQUIRE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define ACQUIRE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define RELEASE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
|
||||
|
||||
#define RELEASE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define TRY_ACQUIRE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define TRY_ACQUIRE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define EXCLUDES(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
|
||||
|
||||
#define ASSERT_CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
|
||||
|
||||
#define ASSERT_SHARED_CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
|
||||
|
||||
#define RETURN_CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
|
||||
|
||||
#define NO_THREAD_SAFETY_ANALYSIS \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
#endif /* PublicUtility__VCThreadSafetyAnalysis */
|
||||
|
||||
/*
|
||||
This file is derived from "mutex.h" from the Clang documentation at
|
||||
<https://clang.llvm.org/docs/ThreadSafetyAnalysis.html>. See the LLVM license at
|
||||
<https://llvm.org/docs/DeveloperPolicy.html#legacy>.
|
||||
*/
|
||||
387
app/VCAudioDevice.cpp
Normal file
387
app/VCAudioDevice.cpp
Normal file
@@ -0,0 +1,387 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VCAudioDevice.cpp
|
||||
// VCApp
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "VCAudioDevice.h"
|
||||
|
||||
// Local Includes
|
||||
#include "VC_Types.h"
|
||||
|
||||
// System Includes
|
||||
#include <AudioToolbox/AudioServices.h>
|
||||
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
VCAudioDevice::VCAudioDevice(AudioObjectID inAudioDevice)
|
||||
:
|
||||
CAHALAudioDevice(inAudioDevice)
|
||||
{
|
||||
}
|
||||
|
||||
VCAudioDevice::VCAudioDevice(CFStringRef inUID)
|
||||
:
|
||||
CAHALAudioDevice(inUID)
|
||||
{
|
||||
}
|
||||
|
||||
VCAudioDevice::VCAudioDevice(const CAHALAudioDevice& inDevice)
|
||||
:
|
||||
VCAudioDevice(inDevice.GetObjectID())
|
||||
{
|
||||
}
|
||||
|
||||
VCAudioDevice::~VCAudioDevice()
|
||||
{
|
||||
}
|
||||
|
||||
bool VCAudioDevice::CanBeOutputDeviceInVCApp() const
|
||||
{
|
||||
CFStringRef uid = CopyDeviceUID();
|
||||
assert(uid != nullptr);
|
||||
|
||||
CFRelease(uid);
|
||||
|
||||
bool hasOutputChannels = GetTotalNumberChannels(/* inIsInput = */ false) > 0;
|
||||
bool canBeDefault = CanBeDefaultDevice(/* inIsInput = */ false, /* inIsSystem = */ false);
|
||||
|
||||
return !IsVCDeviceInstance() &&
|
||||
!IsHidden() &&
|
||||
hasOutputChannels &&
|
||||
canBeDefault;
|
||||
}
|
||||
|
||||
#pragma mark Available Controls
|
||||
|
||||
bool VCAudioDevice::HasSettableMasterVolume(AudioObjectPropertyScope inScope) const
|
||||
{
|
||||
return HasVolumeControl(inScope, kMasterChannel) &&
|
||||
VolumeControlIsSettable(inScope, kMasterChannel);
|
||||
}
|
||||
|
||||
bool VCAudioDevice::HasSettableVirtualMasterVolume(AudioObjectPropertyScope inScope) const
|
||||
{
|
||||
AudioObjectPropertyAddress virtualMasterVolumeAddress = {
|
||||
kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
|
||||
inScope,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
// TODO: Replace these calls deprecated AudioToolbox functions. There are more below.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
Boolean virtualMasterVolumeIsSettable;
|
||||
OSStatus err = AudioHardwareServiceIsPropertySettable(GetObjectID(),
|
||||
&virtualMasterVolumeAddress,
|
||||
&virtualMasterVolumeIsSettable);
|
||||
virtualMasterVolumeIsSettable &= (err == kAudioServicesNoError);
|
||||
|
||||
bool hasVirtualMasterVolume =
|
||||
AudioHardwareServiceHasProperty(GetObjectID(), &virtualMasterVolumeAddress);
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
return hasVirtualMasterVolume && virtualMasterVolumeIsSettable;
|
||||
}
|
||||
|
||||
bool VCAudioDevice::HasSettableMasterMute(AudioObjectPropertyScope inScope) const
|
||||
{
|
||||
return HasMuteControl(inScope, kMasterChannel) &&
|
||||
MuteControlIsSettable(inScope, kMasterChannel);
|
||||
}
|
||||
|
||||
#pragma mark Control Values Accessors
|
||||
|
||||
void VCAudioDevice::CopyMuteFrom(const VCAudioDevice inDevice,
|
||||
AudioObjectPropertyScope inScope)
|
||||
{
|
||||
// TODO: Support for devices that have per-channel mute controls but no master mute control
|
||||
if(HasSettableMasterMute(inScope) && inDevice.HasMuteControl(inScope, kMasterChannel))
|
||||
{
|
||||
SetMuteControlValue(inScope,
|
||||
kMasterChannel,
|
||||
inDevice.GetMuteControlValue(inScope, kMasterChannel));
|
||||
}
|
||||
}
|
||||
|
||||
void VCAudioDevice::CopyVolumeFrom(const VCAudioDevice inDevice,
|
||||
AudioObjectPropertyScope inScope)
|
||||
{
|
||||
// Get the volume of the other device.
|
||||
bool didGetVolume = false;
|
||||
Float32 volume = FLT_MIN;
|
||||
|
||||
if(inDevice.HasVolumeControl(inScope, kMasterChannel))
|
||||
{
|
||||
volume = inDevice.GetVolumeControlScalarValue(inScope, kMasterChannel);
|
||||
didGetVolume = true;
|
||||
}
|
||||
|
||||
// Use the average channel volume of the other device if it has no master volume.
|
||||
if(!didGetVolume)
|
||||
{
|
||||
UInt32 numChannels =
|
||||
inDevice.GetTotalNumberChannels(inScope == kAudioObjectPropertyScopeInput);
|
||||
volume = 0;
|
||||
|
||||
for(UInt32 channel = 1; channel <= numChannels; channel++)
|
||||
{
|
||||
if(inDevice.HasVolumeControl(inScope, channel))
|
||||
{
|
||||
volume += inDevice.GetVolumeControlScalarValue(inScope, channel);
|
||||
didGetVolume = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(numChannels > 0) // Avoid divide by zero.
|
||||
{
|
||||
volume /= numChannels;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the volume of this device.
|
||||
if(didGetVolume && volume != FLT_MIN)
|
||||
{
|
||||
bool didSetVolume = false;
|
||||
|
||||
try
|
||||
{
|
||||
didSetVolume = SetMasterVolumeScalar(inScope, volume);
|
||||
}
|
||||
catch(CAException e)
|
||||
{
|
||||
OSStatus err = e.GetError();
|
||||
char err4CC[5] = CA4CCToCString(err);
|
||||
CFStringRef uid = CopyDeviceUID();
|
||||
LogWarning("VCAudioDevice::CopyVolumeFrom: CAException '%s' trying to set master "
|
||||
"volume of %s",
|
||||
err4CC,
|
||||
CFStringGetCStringPtr(uid, kCFStringEncodingUTF8));
|
||||
CFRelease(uid);
|
||||
}
|
||||
|
||||
if(!didSetVolume)
|
||||
{
|
||||
// Couldn't find a master volume control to set, so try to find a virtual one
|
||||
Float32 virtualMasterVolume;
|
||||
bool success = inDevice.GetVirtualMasterVolumeScalar(inScope, virtualMasterVolume);
|
||||
if(success)
|
||||
{
|
||||
didSetVolume = SetVirtualMasterVolumeScalar(inScope, virtualMasterVolume);
|
||||
}
|
||||
}
|
||||
|
||||
if(!didSetVolume)
|
||||
{
|
||||
// Couldn't set a master or virtual master volume, so as a fallback try to set each
|
||||
// channel individually.
|
||||
UInt32 numChannels = GetTotalNumberChannels(inScope == kAudioObjectPropertyScopeInput);
|
||||
for(UInt32 channel = 1; channel <= numChannels; channel++)
|
||||
{
|
||||
if(HasVolumeControl(inScope, channel) && VolumeControlIsSettable(inScope, channel))
|
||||
{
|
||||
SetVolumeControlScalarValue(inScope, channel, volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VCAudioDevice::SetMasterVolumeScalar(AudioObjectPropertyScope inScope, Float32 inVolume)
|
||||
{
|
||||
if(HasSettableMasterVolume(inScope))
|
||||
{
|
||||
SetVolumeControlScalarValue(inScope, kMasterChannel, inVolume);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VCAudioDevice::GetVirtualMasterVolumeScalar(AudioObjectPropertyScope inScope,
|
||||
Float32& outVirtualMasterVolume) const
|
||||
{
|
||||
AudioObjectPropertyAddress virtualMasterVolumeAddress = {
|
||||
kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
|
||||
inScope,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if(!AudioHardwareServiceHasProperty(GetObjectID(), &virtualMasterVolumeAddress))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
UInt32 virtualMasterVolumePropertySize = sizeof(Float32);
|
||||
return kAudioServicesNoError == AHSGetPropertyData(GetObjectID(),
|
||||
&virtualMasterVolumeAddress,
|
||||
&virtualMasterVolumePropertySize,
|
||||
&outVirtualMasterVolume);
|
||||
}
|
||||
|
||||
bool VCAudioDevice::SetVirtualMasterVolumeScalar(AudioObjectPropertyScope inScope,
|
||||
Float32 inVolume)
|
||||
{
|
||||
// TODO: For me, setting the virtual master volume sets all the device's channels to the same volume, meaning you can't
|
||||
// keep any channels quieter than the others. The expected behaviour is to scale the channel volumes
|
||||
// proportionally. So to do this properly I think we'd have to store VCDevice's previous volume and calculate
|
||||
// each channel's new volume from its current volume and the distance between VCDevice's old and new volumes.
|
||||
//
|
||||
// The docs kAudioHardwareServiceDeviceProperty_VirtualMasterVolume for say
|
||||
// "If the device has individual channel volume controls, this property will apply to those identified by the
|
||||
// device's preferred multi-channel layout (or preferred stereo pair if the device is stereo only). Note that
|
||||
// this control maintains the relative balance between all the channels it affects.
|
||||
// so I'm not sure why that's not working here. As a workaround we take the to device's (virtual master) balance
|
||||
// before changing the volume and set it back after, but of course that'll only work for stereo devices.
|
||||
|
||||
bool didSetVolume = false;
|
||||
|
||||
if(HasSettableVirtualMasterVolume(inScope))
|
||||
{
|
||||
// Not sure why, but setting the virtual master volume sets all channels to the same volume. As a workaround, we store
|
||||
// the current balance here so we can reset it after setting the volume.
|
||||
Float32 virtualMasterBalance;
|
||||
bool didGetVirtualMasterBalance = GetVirtualMasterBalance(inScope, virtualMasterBalance);
|
||||
|
||||
AudioObjectPropertyAddress virtualMasterVolumeAddress = {
|
||||
kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
|
||||
inScope,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
didSetVolume = (kAudioServicesNoError == AHSSetPropertyData(GetObjectID(),
|
||||
&virtualMasterVolumeAddress,
|
||||
sizeof(Float32),
|
||||
&inVolume));
|
||||
|
||||
// Reset the balance
|
||||
AudioObjectPropertyAddress virtualMasterBalanceAddress = {
|
||||
kAudioHardwareServiceDeviceProperty_VirtualMainBalance,
|
||||
inScope,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if(didSetVolume &&
|
||||
didGetVirtualMasterBalance &&
|
||||
AudioHardwareServiceHasProperty(GetObjectID(), &virtualMasterBalanceAddress))
|
||||
{
|
||||
Boolean balanceIsSettable;
|
||||
OSStatus err = AudioHardwareServiceIsPropertySettable(GetObjectID(),
|
||||
&virtualMasterBalanceAddress,
|
||||
&balanceIsSettable);
|
||||
if(err == kAudioServicesNoError && balanceIsSettable)
|
||||
{
|
||||
AHSSetPropertyData(GetObjectID(),
|
||||
&virtualMasterBalanceAddress,
|
||||
sizeof(Float32),
|
||||
&virtualMasterBalance);
|
||||
}
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
return didSetVolume;
|
||||
}
|
||||
|
||||
bool VCAudioDevice::GetVirtualMasterBalance(AudioObjectPropertyScope inScope,
|
||||
Float32& outVirtualMasterBalance) const
|
||||
{
|
||||
AudioObjectPropertyAddress virtualMasterBalanceAddress = {
|
||||
kAudioHardwareServiceDeviceProperty_VirtualMainBalance,
|
||||
inScope,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if(!AudioHardwareServiceHasProperty(GetObjectID(), &virtualMasterBalanceAddress))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
UInt32 virtualMasterVolumePropertySize = sizeof(Float32);
|
||||
return kAudioServicesNoError == AHSGetPropertyData(GetObjectID(),
|
||||
&virtualMasterBalanceAddress,
|
||||
&virtualMasterVolumePropertySize,
|
||||
&outVirtualMasterBalance);
|
||||
}
|
||||
|
||||
#pragma mark Implementation
|
||||
|
||||
bool VCAudioDevice::IsVCDevice(bool inIncludeUISoundsInstance) const
|
||||
{
|
||||
bool isVCDevice = false;
|
||||
|
||||
if(GetObjectID() != kAudioObjectUnknown)
|
||||
{
|
||||
// Check the device's UID to see whether it's VCDevice.
|
||||
CFStringRef uid = CopyDeviceUID();
|
||||
if (uid == nullptr) {
|
||||
return isVCDevice;
|
||||
}
|
||||
|
||||
isVCDevice = CFEqual(uid, CFSTR(kVCDeviceUID));
|
||||
|
||||
CFRelease(uid);
|
||||
}
|
||||
|
||||
return isVCDevice;
|
||||
}
|
||||
|
||||
// static
|
||||
OSStatus VCAudioDevice::AHSGetPropertyData(AudioObjectID inObjectID,
|
||||
const AudioObjectPropertyAddress* inAddress,
|
||||
UInt32* ioDataSize,
|
||||
void* outData)
|
||||
{
|
||||
// The docs for AudioHardwareServiceGetPropertyData specifically allow passing NULL for
|
||||
// inQualifierData as we do here, but it's declared in an assume_nonnull section so we have to
|
||||
// disable the warning here. I'm not sure why inQualifierData isn't __nullable. I'm assuming
|
||||
// it's either a backwards compatibility thing or just a bug.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnonnull"
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
// The non-depreciated version of this (and the setter below) doesn't seem to support devices
|
||||
// other than the default
|
||||
return AudioHardwareServiceGetPropertyData(inObjectID, inAddress, 0, NULL, ioDataSize, outData);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
// static
|
||||
OSStatus VCAudioDevice::AHSSetPropertyData(AudioObjectID inObjectID,
|
||||
const AudioObjectPropertyAddress* inAddress,
|
||||
UInt32 inDataSize,
|
||||
const void* inData)
|
||||
{
|
||||
// See the explanation about these pragmas in AHSGetPropertyData
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnonnull"
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
return AudioHardwareServiceSetPropertyData(inObjectID, inAddress, 0, NULL, inDataSize, inData);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
121
app/VCAudioDevice.h
Normal file
121
app/VCAudioDevice.h
Normal file
@@ -0,0 +1,121 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// VCAudioDevice.h
|
||||
// VCApp
|
||||
//
|
||||
// Copyright © 2017, 2020 Kyle Neideck
|
||||
//
|
||||
// A HAL audio device. Note that this class's only state is the AudioObjectID of the device.
|
||||
//
|
||||
|
||||
#ifndef VCApp__VCAudioDevice
|
||||
#define VCApp__VCAudioDevice
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CAHALAudioDevice.h"
|
||||
|
||||
|
||||
class VCAudioDevice
|
||||
:
|
||||
public CAHALAudioDevice
|
||||
{
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
public:
|
||||
VCAudioDevice(AudioObjectID inAudioDevice);
|
||||
/*!
|
||||
Creates a VCAudioDevice with the Audio Object ID of the device whose UID is inUID or, if no
|
||||
such device is found, kAudioObjectUnknown.
|
||||
|
||||
@throws CAException If the HAL returns an error when queried for the device's ID.
|
||||
@see kAudioPlugInPropertyTranslateUIDToDevice in AudioHardwareBase.h.
|
||||
*/
|
||||
VCAudioDevice(CFStringRef inUID);
|
||||
VCAudioDevice(const CAHALAudioDevice& inDevice);
|
||||
virtual ~VCAudioDevice();
|
||||
|
||||
#if defined(__OBJC__)
|
||||
|
||||
// Hack/workaround for Objective-C classes so we don't have to use pointers for instance
|
||||
// variables.
|
||||
VCAudioDevice() : VCAudioDevice(kAudioObjectUnknown) { }
|
||||
|
||||
#endif /* defined(__OBJC__) */
|
||||
|
||||
operator AudioObjectID() const { return GetObjectID(); }
|
||||
|
||||
/*!
|
||||
@return True if this device is VCDevice. (Specifically, the main instance of VCDevice, not
|
||||
the instance used for UI sounds.)
|
||||
@throws CAException If the HAL returns an error when queried.
|
||||
*/
|
||||
bool IsVCDevice() const { return IsVCDevice(false); };
|
||||
/*!
|
||||
@return True if this device is either the main instance of VCDevice (the device named
|
||||
"Background Music") or the instance used for UI sounds (the device named "Background
|
||||
Music (UI Sounds)").
|
||||
@throws CAException If the HAL returns an error when queried.
|
||||
*/
|
||||
bool IsVCDeviceInstance() const { return IsVCDevice(true); };
|
||||
|
||||
/*!
|
||||
@return True if this device can be set as the output device in VCApp.
|
||||
@throws CAException If the HAL returns an error when queried.
|
||||
*/
|
||||
bool CanBeOutputDeviceInVCApp() const;
|
||||
|
||||
#pragma mark Available Controls
|
||||
|
||||
bool HasSettableMasterVolume(AudioObjectPropertyScope inScope) const;
|
||||
bool HasSettableVirtualMasterVolume(AudioObjectPropertyScope inScope) const;
|
||||
bool HasSettableMasterMute(AudioObjectPropertyScope inScope) const;
|
||||
|
||||
#pragma mark Control Values Accessors
|
||||
|
||||
void CopyMuteFrom(const VCAudioDevice inDevice,
|
||||
AudioObjectPropertyScope inScope);
|
||||
void CopyVolumeFrom(const VCAudioDevice inDevice,
|
||||
AudioObjectPropertyScope inScope);
|
||||
|
||||
bool SetMasterVolumeScalar(AudioObjectPropertyScope inScope, Float32 inVolume);
|
||||
|
||||
bool GetVirtualMasterVolumeScalar(AudioObjectPropertyScope inScope,
|
||||
Float32& outVirtualMasterVolume) const;
|
||||
bool SetVirtualMasterVolumeScalar(AudioObjectPropertyScope inScope,
|
||||
Float32 inVolume);
|
||||
|
||||
bool GetVirtualMasterBalance(AudioObjectPropertyScope inScope,
|
||||
Float32& outVirtualMasterBalance) const;
|
||||
|
||||
#pragma mark Implementation
|
||||
|
||||
private:
|
||||
bool IsVCDevice(bool inIncludingUISoundsInstance) const;
|
||||
|
||||
static OSStatus AHSGetPropertyData(AudioObjectID inObjectID,
|
||||
const AudioObjectPropertyAddress* inAddress,
|
||||
UInt32* ioDataSize,
|
||||
void* outData);
|
||||
static OSStatus AHSSetPropertyData(AudioObjectID inObjectID,
|
||||
const AudioObjectPropertyAddress* inAddress,
|
||||
UInt32 inDataSize,
|
||||
const void* inData);
|
||||
|
||||
};
|
||||
|
||||
#endif /* VCApp__VCAudioDevice */
|
||||
|
||||
55
app/VCAudioDeviceManager.h
Normal file
55
app/VCAudioDeviceManager.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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.
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
// Local Includes
|
||||
#import "VCVirtualDevice.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#import "CAHALAudioDevice.h"
|
||||
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
// System Includes
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreAudio/AudioHardwareBase.h>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
@interface VCAudioDeviceManager : NSObject
|
||||
|
||||
// Called on any volume change (scroll, keyboard, system slider).
|
||||
@property (nonatomic, copy) void (^onVolumeChanged)(void);
|
||||
|
||||
// Returns nil if the virtual device driver isn't installed.
|
||||
- (instancetype) init;
|
||||
|
||||
- (NSError* __nullable) setVCDeviceAsOSDefault;
|
||||
- (NSError* __nullable) unsetVCDeviceAsOSDefault;
|
||||
|
||||
#ifdef __cplusplus
|
||||
- (VCVirtualDevice) vcDevice;
|
||||
- (CAHALAudioDevice) outputDevice;
|
||||
#endif
|
||||
|
||||
- (BOOL) isVirtualDeviceActive;
|
||||
|
||||
// Scans connected devices. If any lack hardware volume, activates the virtual device and starts
|
||||
// playthrough. Otherwise bypasses. Called at launch and on device hotplug.
|
||||
- (void) evaluateAndActivate;
|
||||
|
||||
// Universal volume control — works on both virtual device and native hardware.
|
||||
- (float) volume;
|
||||
- (void) setVolume:(float)vol;
|
||||
- (BOOL) isMuted;
|
||||
- (void) setMuted:(BOOL)muted;
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
465
app/VCAudioDeviceManager.mm
Normal file
465
app/VCAudioDeviceManager.mm
Normal file
@@ -0,0 +1,465 @@
|
||||
// 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.
|
||||
|
||||
#import "VCAudioDeviceManager.h"
|
||||
|
||||
#import "VC_Types.h"
|
||||
#import "VC_Utils.h"
|
||||
#import "VCAudioDevice.h"
|
||||
#import "VCPlayThrough.h"
|
||||
|
||||
#import "CAAtomic.h"
|
||||
#import "CAAutoDisposer.h"
|
||||
#import "CAHALAudioSystemObject.h"
|
||||
#import "CAPropertyAddress.h"
|
||||
|
||||
static NSString* const kVCVolumeKey = @"VCVolume";
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
@implementation VCAudioDeviceManager {
|
||||
VCVirtualDevice* vcDevice;
|
||||
VCAudioDevice outputDevice;
|
||||
VCPlayThrough playThrough;
|
||||
NSRecursiveLock* stateLock;
|
||||
BOOL virtualDeviceActive;
|
||||
AudioObjectPropertyListenerBlock deviceListListener;
|
||||
AudioObjectPropertyListenerBlock defaultDeviceListener;
|
||||
AudioObjectPropertyListenerBlock volumeListenerBlock;
|
||||
AudioObjectID listenedDeviceID;
|
||||
dispatch_source_t debounceTimer;
|
||||
}
|
||||
|
||||
#pragma mark Init / Dealloc
|
||||
|
||||
- (instancetype) init {
|
||||
if ((self = [super init])) {
|
||||
stateLock = [NSRecursiveLock new];
|
||||
outputDevice = kAudioObjectUnknown;
|
||||
listenedDeviceID = kAudioObjectUnknown;
|
||||
virtualDeviceActive = NO;
|
||||
|
||||
try {
|
||||
vcDevice = new VCVirtualDevice;
|
||||
} catch (const CAException& e) {
|
||||
LogError("VCAudioDeviceManager::init: VCDevice not found. (%d)", e.GetError());
|
||||
self = nil;
|
||||
return self;
|
||||
}
|
||||
|
||||
[self listenForDeviceChanges];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
@try {
|
||||
[stateLock lock];
|
||||
|
||||
[self stopVolumeListener];
|
||||
|
||||
if (deviceListListener) {
|
||||
VCLogAndSwallowExceptions("VCAudioDeviceManager::dealloc[devices]", [&] {
|
||||
CAHALAudioSystemObject().RemovePropertyListenerBlock(
|
||||
CAPropertyAddress(kAudioHardwarePropertyDevices),
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
|
||||
deviceListListener);
|
||||
});
|
||||
}
|
||||
|
||||
if (defaultDeviceListener) {
|
||||
VCLogAndSwallowExceptions("VCAudioDeviceManager::dealloc[defaultDevice]", [&] {
|
||||
CAHALAudioSystemObject().RemovePropertyListenerBlock(
|
||||
CAPropertyAddress(kAudioHardwarePropertyDefaultOutputDevice),
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
|
||||
defaultDeviceListener);
|
||||
});
|
||||
}
|
||||
|
||||
if (vcDevice) {
|
||||
delete vcDevice;
|
||||
vcDevice = nullptr;
|
||||
}
|
||||
} @finally {
|
||||
[stateLock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Default Device
|
||||
|
||||
- (NSError* __nullable) setVCDeviceAsOSDefault {
|
||||
try {
|
||||
CAMemoryBarrier();
|
||||
vcDevice->SetAsOSDefault();
|
||||
} catch (const CAException& e) {
|
||||
VCLogExceptionIn("VCAudioDeviceManager::setVCDeviceAsOSDefault", e);
|
||||
return [NSError errorWithDomain:@kVCAppBundleID code:e.GetError() userInfo:nil];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError* __nullable) unsetVCDeviceAsOSDefault {
|
||||
@try {
|
||||
[stateLock lock];
|
||||
|
||||
AudioDeviceID outputDeviceID = outputDevice.GetObjectID();
|
||||
|
||||
if (outputDeviceID == kAudioObjectUnknown) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
try {
|
||||
vcDevice->UnsetAsOSDefault(outputDeviceID);
|
||||
} catch (const CAException& e) {
|
||||
VCLogExceptionIn("VCAudioDeviceManager::unsetVCDeviceAsOSDefault", e);
|
||||
return [NSError errorWithDomain:@kVCAppBundleID code:e.GetError() userInfo:nil];
|
||||
}
|
||||
} @finally {
|
||||
[stateLock unlock];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark Accessors
|
||||
|
||||
- (VCVirtualDevice) vcDevice { return *vcDevice; }
|
||||
- (CAHALAudioDevice) outputDevice { return outputDevice; }
|
||||
|
||||
- (BOOL) isVirtualDeviceActive {
|
||||
@try {
|
||||
[stateLock lock];
|
||||
return virtualDeviceActive;
|
||||
} @finally {
|
||||
[stateLock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Device Evaluation
|
||||
|
||||
- (BOOL) deviceHasHardwareVolume:(const VCAudioDevice&)device {
|
||||
AudioObjectPropertyScope scope = kAudioDevicePropertyScopeOutput;
|
||||
|
||||
try {
|
||||
if (device.HasSettableMasterVolume(scope) ||
|
||||
device.HasSettableVirtualMasterVolume(scope)) {
|
||||
return YES;
|
||||
}
|
||||
} catch (const CAException& e) {
|
||||
VCLogException(e);
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) listenForDeviceChanges {
|
||||
VCAudioDeviceManager* __weak weakSelf = self;
|
||||
|
||||
deviceListListener = ^(UInt32 inNumberAddresses,
|
||||
const AudioObjectPropertyAddress* inAddresses) {
|
||||
#pragma unused (inNumberAddresses, inAddresses)
|
||||
// Debounce: coalesce rapid hotplug events into one evaluation.
|
||||
VCAudioDeviceManager* strongSelf = weakSelf;
|
||||
if (!strongSelf) return;
|
||||
|
||||
@synchronized (strongSelf) {
|
||||
if (strongSelf->debounceTimer) {
|
||||
dispatch_source_cancel(strongSelf->debounceTimer);
|
||||
}
|
||||
strongSelf->debounceTimer = dispatch_source_create(
|
||||
DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
|
||||
dispatch_source_set_timer(strongSelf->debounceTimer,
|
||||
dispatch_time(DISPATCH_TIME_NOW, 200 * NSEC_PER_MSEC),
|
||||
DISPATCH_TIME_FOREVER, 50 * NSEC_PER_MSEC);
|
||||
dispatch_source_set_event_handler(strongSelf->debounceTimer, ^{
|
||||
[weakSelf evaluateAndActivate];
|
||||
});
|
||||
dispatch_resume(strongSelf->debounceTimer);
|
||||
}
|
||||
};
|
||||
|
||||
VCLogAndSwallowExceptions("VCAudioDeviceManager::listenForDeviceChanges", [&] {
|
||||
CAHALAudioSystemObject().AddPropertyListenerBlock(
|
||||
CAPropertyAddress(kAudioHardwarePropertyDevices),
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
|
||||
deviceListListener);
|
||||
});
|
||||
|
||||
// When the default output device changes, re-attach volume listener to the new device.
|
||||
defaultDeviceListener = ^(UInt32 inNumberAddresses,
|
||||
const AudioObjectPropertyAddress* inAddresses) {
|
||||
#pragma unused (inNumberAddresses, inAddresses)
|
||||
VCAudioDeviceManager* strongSelf = weakSelf;
|
||||
if (!strongSelf) return;
|
||||
|
||||
AudioObjectID newDefault = [strongSelf currentDefaultOutputDevice];
|
||||
if (newDefault != kAudioObjectUnknown && newDefault != strongSelf->listenedDeviceID) {
|
||||
[strongSelf startVolumeListenerOnDevice:newDefault];
|
||||
}
|
||||
|
||||
if (strongSelf.onVolumeChanged) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
strongSelf.onVolumeChanged();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
VCLogAndSwallowExceptions("VCAudioDeviceManager::listenForDefaultDeviceChanges", [&] {
|
||||
CAHALAudioSystemObject().AddPropertyListenerBlock(
|
||||
CAPropertyAddress(kAudioHardwarePropertyDefaultOutputDevice),
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
|
||||
defaultDeviceListener);
|
||||
});
|
||||
}
|
||||
|
||||
- (void) evaluateAndActivate {
|
||||
@try {
|
||||
[stateLock lock];
|
||||
|
||||
CAHALAudioSystemObject audioSystem;
|
||||
UInt32 numDevices = audioSystem.GetNumberAudioDevices();
|
||||
|
||||
if (numDevices == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
CAAutoArrayDelete<AudioObjectID> devices(numDevices);
|
||||
audioSystem.GetAudioDevices(numDevices, devices);
|
||||
|
||||
// Find a device needing software volume, and a fallback with hardware volume.
|
||||
AudioObjectID deviceNeedingSoftwareVolume = kAudioObjectUnknown;
|
||||
AudioObjectID fallbackDevice = kAudioObjectUnknown;
|
||||
|
||||
for (UInt32 i = 0; i < numDevices; i++) {
|
||||
VCAudioDevice device(devices[i]);
|
||||
|
||||
VCLogAndSwallowExceptions("evaluateAndActivate", [&] {
|
||||
if (!device.CanBeOutputDeviceInVCApp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (![self deviceHasHardwareVolume:device]) {
|
||||
deviceNeedingSoftwareVolume = devices[i];
|
||||
} else if (fallbackDevice == kAudioObjectUnknown) {
|
||||
fallbackDevice = devices[i];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AudioObjectID targetDevice;
|
||||
BOOL needsVirtualDevice;
|
||||
|
||||
if (deviceNeedingSoftwareVolume != kAudioObjectUnknown) {
|
||||
targetDevice = deviceNeedingSoftwareVolume;
|
||||
needsVirtualDevice = YES;
|
||||
} else if (fallbackDevice != kAudioObjectUnknown) {
|
||||
targetDevice = fallbackDevice;
|
||||
needsVirtualDevice = NO;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// No change needed?
|
||||
if (targetDevice == outputDevice.GetObjectID() &&
|
||||
needsVirtualDevice == virtualDeviceActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
VCAudioDevice newOutputDevice(targetDevice);
|
||||
|
||||
if (needsVirtualDevice) {
|
||||
NSLog(@"VolumeControl: Activating for device %u (no hardware volume)", targetDevice);
|
||||
|
||||
try {
|
||||
vcDevice->SetHidden(false);
|
||||
|
||||
playThrough.Deactivate();
|
||||
playThrough.SetDevices(vcDevice, &newOutputDevice);
|
||||
playThrough.Activate();
|
||||
|
||||
outputDevice = newOutputDevice;
|
||||
virtualDeviceActive = YES;
|
||||
|
||||
[self setVCDeviceAsOSDefault];
|
||||
[self restoreVolume];
|
||||
[self startVolumeListenerOnDevice:vcDevice->GetObjectID()];
|
||||
|
||||
playThrough.Start();
|
||||
playThrough.StopIfIdle();
|
||||
} catch (const CAException& e) {
|
||||
NSLog(@"VolumeControl: Failed to start playthrough for device %u (error %d)",
|
||||
targetDevice, e.GetError());
|
||||
}
|
||||
} else {
|
||||
NSLog(@"VolumeControl: Bypassing for device %u (has hardware volume)", targetDevice);
|
||||
|
||||
[self saveVolume];
|
||||
playThrough.Deactivate();
|
||||
virtualDeviceActive = NO;
|
||||
outputDevice = newOutputDevice;
|
||||
|
||||
[self unsetVCDeviceAsOSDefault];
|
||||
vcDevice->SetHidden(true);
|
||||
[self startVolumeListenerOnDevice:targetDevice];
|
||||
}
|
||||
} @finally {
|
||||
[stateLock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Universal Volume
|
||||
|
||||
// Returns the current system default output device.
|
||||
- (AudioObjectID) currentDefaultOutputDevice {
|
||||
AudioObjectID defaultDevice = kAudioObjectUnknown;
|
||||
VCLogAndSwallowExceptions("currentDefaultOutputDevice", [&] {
|
||||
CAHALAudioSystemObject audioSystem;
|
||||
defaultDevice = audioSystem.GetDefaultAudioDevice(false, false);
|
||||
});
|
||||
return defaultDevice;
|
||||
}
|
||||
|
||||
- (float) volume {
|
||||
float vol = 0.5f;
|
||||
VCLogAndSwallowExceptions("volume", [&] {
|
||||
AudioObjectID devID = [self currentDefaultOutputDevice];
|
||||
if (devID == kAudioObjectUnknown) return;
|
||||
CAHALAudioDevice device(devID);
|
||||
AudioObjectPropertyScope scope = kAudioDevicePropertyScopeOutput;
|
||||
if (device.HasVolumeControl(scope, kMasterChannel)) {
|
||||
vol = device.GetVolumeControlScalarValue(scope, kMasterChannel);
|
||||
}
|
||||
});
|
||||
return vol;
|
||||
}
|
||||
|
||||
- (void) setVolume:(float)vol {
|
||||
if (vol < 0.0f) vol = 0.0f;
|
||||
if (vol > 1.0f) vol = 1.0f;
|
||||
|
||||
VCLogAndSwallowExceptions("setVolume", [&] {
|
||||
AudioObjectID devID = [self currentDefaultOutputDevice];
|
||||
if (devID == kAudioObjectUnknown) return;
|
||||
CAHALAudioDevice device(devID);
|
||||
AudioObjectPropertyScope scope = kAudioDevicePropertyScopeOutput;
|
||||
if (device.HasVolumeControl(scope, kMasterChannel)) {
|
||||
device.SetVolumeControlScalarValue(scope, kMasterChannel, vol);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (BOOL) isMuted {
|
||||
BOOL muted = NO;
|
||||
VCLogAndSwallowExceptions("isMuted", [&] {
|
||||
AudioObjectID devID = [self currentDefaultOutputDevice];
|
||||
if (devID == kAudioObjectUnknown) return;
|
||||
CAHALAudioDevice device(devID);
|
||||
AudioObjectPropertyScope scope = kAudioDevicePropertyScopeOutput;
|
||||
if (device.HasMuteControl(scope, kMasterChannel)) {
|
||||
muted = device.GetMuteControlValue(scope, kMasterChannel);
|
||||
}
|
||||
});
|
||||
return muted;
|
||||
}
|
||||
|
||||
- (void) setMuted:(BOOL)muted {
|
||||
VCLogAndSwallowExceptions("setMuted", [&] {
|
||||
AudioObjectID devID = [self currentDefaultOutputDevice];
|
||||
if (devID == kAudioObjectUnknown) return;
|
||||
CAHALAudioDevice device(devID);
|
||||
AudioObjectPropertyScope scope = kAudioDevicePropertyScopeOutput;
|
||||
if (device.HasMuteControl(scope, kMasterChannel)) {
|
||||
device.SetMuteControlValue(scope, kMasterChannel, muted);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark Volume Persistence
|
||||
|
||||
- (void) restoreVolume {
|
||||
Float32 saved = [[NSUserDefaults standardUserDefaults] floatForKey:kVCVolumeKey];
|
||||
if (saved <= 0.0f) {
|
||||
saved = 0.5f; // Default if never saved.
|
||||
}
|
||||
|
||||
VCLogAndSwallowExceptions("restoreVolume", [&] {
|
||||
AudioObjectPropertyScope scope = kAudioDevicePropertyScopeOutput;
|
||||
if (vcDevice->HasVolumeControl(scope, kMasterChannel)) {
|
||||
vcDevice->SetVolumeControlScalarValue(scope, kMasterChannel, saved);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void) saveVolume {
|
||||
VCLogAndSwallowExceptions("saveVolume", [&] {
|
||||
AudioObjectPropertyScope scope = kAudioDevicePropertyScopeOutput;
|
||||
if (vcDevice->HasVolumeControl(scope, kMasterChannel)) {
|
||||
Float32 vol = vcDevice->GetVolumeControlScalarValue(scope, kMasterChannel);
|
||||
[[NSUserDefaults standardUserDefaults] setFloat:vol forKey:kVCVolumeKey];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void) startVolumeListenerOnDevice:(AudioObjectID)deviceID {
|
||||
[self stopVolumeListener];
|
||||
|
||||
VCAudioDeviceManager* __weak weakSelf = self;
|
||||
volumeListenerBlock = ^(UInt32 inNumberAddresses,
|
||||
const AudioObjectPropertyAddress* inAddresses) {
|
||||
#pragma unused (inNumberAddresses, inAddresses)
|
||||
VCAudioDeviceManager* strongSelf = weakSelf;
|
||||
if (!strongSelf) return;
|
||||
|
||||
if (strongSelf->virtualDeviceActive) {
|
||||
[strongSelf saveVolume];
|
||||
}
|
||||
|
||||
if (strongSelf.onVolumeChanged) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
strongSelf.onVolumeChanged();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
listenedDeviceID = deviceID;
|
||||
|
||||
VCLogAndSwallowExceptions("startVolumeListener", [&] {
|
||||
CAHALAudioDevice device(deviceID);
|
||||
device.AddPropertyListenerBlock(
|
||||
CAPropertyAddress(kAudioDevicePropertyVolumeScalar,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kMasterChannel),
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
|
||||
volumeListenerBlock);
|
||||
});
|
||||
}
|
||||
|
||||
- (void) stopVolumeListener {
|
||||
if (!volumeListenerBlock) return;
|
||||
|
||||
VCLogAndSwallowExceptions("stopVolumeListener", [&] {
|
||||
if (CAHALAudioObject::ObjectExists(listenedDeviceID)) {
|
||||
CAHALAudioDevice device(listenedDeviceID);
|
||||
device.RemovePropertyListenerBlock(
|
||||
CAPropertyAddress(kAudioDevicePropertyVolumeScalar,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kMasterChannel),
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
|
||||
volumeListenerBlock);
|
||||
}
|
||||
});
|
||||
volumeListenerBlock = nil;
|
||||
listenedDeviceID = kAudioObjectUnknown;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
1250
app/VCPlayThrough.cpp
Normal file
1250
app/VCPlayThrough.cpp
Normal file
File diff suppressed because it is too large
Load Diff
238
app/VCPlayThrough.h
Normal file
238
app/VCPlayThrough.h
Normal file
@@ -0,0 +1,238 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VCPlayThrough.h
|
||||
// VCApp
|
||||
//
|
||||
// Copyright © 2016, 2017, 2020 Kyle Neideck
|
||||
//
|
||||
// Reads audio from an input device and immediately writes it to an output device. We currently use this class with the input
|
||||
// device always set to VCDevice and the output device set to the one selected in the preferences menu.
|
||||
//
|
||||
// Apple's CAPlayThrough sample code (https://developer.apple.com/library/mac/samplecode/CAPlayThrough/Introduction/Intro.html)
|
||||
// has a similar class, but I couldn't get it fast enough to use here. Soundflower also has a similar class
|
||||
// (https://github.com/mattingalls/Soundflower/blob/master/SoundflowerBed/AudioThruEngine.h) that seems to be based on Apple
|
||||
// sample code from 2004. This class's main addition is pausing playthrough when idle to save CPU.
|
||||
//
|
||||
// Playing audio with this class uses more CPU, mostly in the coreaudiod process, than playing audio normally because we need
|
||||
// an input IOProc as well as an output one, and VCDriver is running in addition to the output device's driver. For me, it
|
||||
// usually adds around 1-2% (as a percentage of total usage -- it doesn't seem to be relative to the CPU used when playing
|
||||
// audio normally).
|
||||
//
|
||||
// This class will hopefully not be needed after CoreAudio's aggregate devices get support for controls, which is planned for
|
||||
// a future release.
|
||||
//
|
||||
|
||||
#ifndef VCApp__VCPlayThrough
|
||||
#define VCApp__VCPlayThrough
|
||||
|
||||
// Local Includes
|
||||
#include "VCAudioDevice.h"
|
||||
#include "VCPlayThroughRTLogger.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CAMutex.h"
|
||||
#include "CARingBuffer.h"
|
||||
#include "VCThreadSafetyAnalysis.h"
|
||||
|
||||
// STL Includes
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
// System Includes
|
||||
#include <mach/semaphore.h>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
class VCPlayThrough
|
||||
{
|
||||
|
||||
public:
|
||||
// Error codes
|
||||
static const OSStatus kDeviceNotStarting = 100;
|
||||
|
||||
public:
|
||||
VCPlayThrough(VCAudioDevice inInputDevice, VCAudioDevice inOutputDevice);
|
||||
~VCPlayThrough();
|
||||
// Disallow copying
|
||||
VCPlayThrough(const VCPlayThrough&) = delete;
|
||||
VCPlayThrough& operator=(const VCPlayThrough&) = delete;
|
||||
|
||||
#ifdef __OBJC__
|
||||
// Only intended as a convenience (hack) for Objective-C instance vars. Call
|
||||
// SetDevices to initialise the instance before using it.
|
||||
VCPlayThrough() { }
|
||||
#endif
|
||||
|
||||
private:
|
||||
/*! @throws CAException */
|
||||
void Init(VCAudioDevice inInputDevice, VCAudioDevice inOutputDevice)
|
||||
REQUIRES(mStateMutex);
|
||||
|
||||
public:
|
||||
/*! @throws CAException */
|
||||
void Activate();
|
||||
/*! @throws CAException */
|
||||
void Deactivate();
|
||||
|
||||
private:
|
||||
void AllocateBuffer() REQUIRES(mStateMutex);
|
||||
void DeallocateBuffer();
|
||||
|
||||
/*! @throws CAException */
|
||||
void CreateIOProcIDs();
|
||||
/*! @throws CAException */
|
||||
void DestroyIOProcIDs();
|
||||
/*!
|
||||
@return True if both IOProcs are stopped.
|
||||
@nonthreadsafe
|
||||
*/
|
||||
bool CheckIOProcsAreStopped() const noexcept REQUIRES(mStateMutex);
|
||||
|
||||
public:
|
||||
/*!
|
||||
Pass null for either param to only change one of the devices.
|
||||
@throws CAException
|
||||
*/
|
||||
void SetDevices(const VCAudioDevice* __nullable inInputDevice,
|
||||
const VCAudioDevice* __nullable inOutputDevice);
|
||||
|
||||
/*! @throws CAException */
|
||||
void Start();
|
||||
|
||||
// Blocks until the output device has started our IOProc. Returns one of the error constants
|
||||
// from AudioHardwareBase.h (e.g. kAudioHardwareNoError).
|
||||
OSStatus WaitForOutputDeviceToStart() noexcept;
|
||||
|
||||
private:
|
||||
/*! Real-time safe. */
|
||||
void ReleaseThreadsWaitingForOutputToStart();
|
||||
|
||||
public:
|
||||
OSStatus Stop();
|
||||
void StopIfIdle();
|
||||
|
||||
private:
|
||||
|
||||
static OSStatus VCDeviceListenerProc(AudioObjectID inObjectID,
|
||||
UInt32 inNumberAddresses,
|
||||
const AudioObjectPropertyAddress* inAddresses,
|
||||
void* __nullable inClientData);
|
||||
static void HandleVCDeviceIsRunning(VCPlayThrough* refCon);
|
||||
static void HandleVCDeviceIsRunningSomewhereOtherThanVCApp(VCPlayThrough* refCon);
|
||||
|
||||
static bool IsRunningSomewhereOtherThanVCApp(const VCAudioDevice& inVCDevice);
|
||||
|
||||
static OSStatus InputDeviceIOProc(AudioObjectID inDevice,
|
||||
const AudioTimeStamp* inNow,
|
||||
const AudioBufferList* inInputData,
|
||||
const AudioTimeStamp* inInputTime,
|
||||
AudioBufferList* outOutputData,
|
||||
const AudioTimeStamp* inOutputTime,
|
||||
void* __nullable inClientData);
|
||||
static OSStatus OutputDeviceIOProc(AudioObjectID inDevice,
|
||||
const AudioTimeStamp* inNow,
|
||||
const AudioBufferList* inInputData,
|
||||
const AudioTimeStamp* inInputTime,
|
||||
AudioBufferList* outOutputData,
|
||||
const AudioTimeStamp* inOutputTime,
|
||||
void* __nullable inClientData);
|
||||
|
||||
/*! Fills the given ABL with zeroes to make it silent. */
|
||||
static inline void FillWithSilence(AudioBufferList* ioBuffer);
|
||||
|
||||
// The state of an IOProc. Used by the IOProc to tell other threads when it's finished starting. Used by other
|
||||
// threads to tell the IOProc to stop itself. (Probably used for other things as well.)
|
||||
enum class IOState
|
||||
{
|
||||
Stopped, Starting, Running, Stopping
|
||||
};
|
||||
|
||||
// The IOProcs call this to update their IOState member. Also stops the IOProc if its state has been set to Stopping.
|
||||
// Returns true if it changes the state.
|
||||
static bool UpdateIOProcState(const char* inCallerName,
|
||||
VCPlayThroughRTLogger& inRTLogger,
|
||||
std::atomic<IOState>& inState,
|
||||
AudioDeviceIOProcID __nullable inIOProcID,
|
||||
VCAudioDevice& inDevice,
|
||||
IOState& outNewState);
|
||||
|
||||
private:
|
||||
std::unique_ptr<CARingBuffer> mBuffer PT_GUARDED_BY(mBufferInputMutex)
|
||||
PT_GUARDED_BY(mBufferOutputMutex) { nullptr };
|
||||
|
||||
AudioDeviceIOProcID __nullable mInputDeviceIOProcID { nullptr };
|
||||
AudioDeviceIOProcID __nullable mOutputDeviceIOProcID { nullptr };
|
||||
|
||||
VCAudioDevice mInputDevice { kAudioObjectUnknown };
|
||||
VCAudioDevice mOutputDevice { kAudioObjectUnknown };
|
||||
|
||||
// mStateMutex is the general purpose mutex. mBufferInputMutex and mBufferOutputMutex are
|
||||
// just used to make sure mBuffer, the ring buffer, is allocated when the IOProcs access it. See
|
||||
// the comments in the IOProcs for details.
|
||||
//
|
||||
// If a thread might lock more than one of these mutexes, it *must* take them in this order:
|
||||
// 1. mStateMutex
|
||||
// 2. mBufferInputMutex
|
||||
// 3. mBufferOutputMutex
|
||||
//
|
||||
// The ACQUIRED_BEFORE annotations don't do anything yet. From clang's docs: "ACQUIRED_BEFORE(…)
|
||||
// and ACQUIRED_AFTER(…) are currently unimplemented. To be fixed in a future update." After
|
||||
// they've fixed that, the compiler will enforce the ordering statically.
|
||||
//
|
||||
// TODO: We can't use std::shared_lock because we're still on C++11, but we could use std::lock
|
||||
// to help ensure the locks are always taken in the right order.
|
||||
// TODO: It would be better to have a separate class for the buffer and its mutexes.
|
||||
CAMutex mStateMutex ACQUIRED_BEFORE(mBufferInputMutex)
|
||||
ACQUIRED_BEFORE(mBufferOutputMutex) { "Playthrough state" };
|
||||
CAMutex mBufferInputMutex ACQUIRED_BEFORE(mBufferOutputMutex)
|
||||
{ "Playthrough ring buffer input" };
|
||||
CAMutex mBufferOutputMutex { "Playthrough ring buffer output" };
|
||||
|
||||
// Signalled when the output IOProc runs. We use it to tell VCDriver when the output device is ready to receive audio data.
|
||||
semaphore_t mOutputDeviceIOProcSemaphore { SEMAPHORE_NULL };
|
||||
|
||||
bool mActive = false;
|
||||
bool mPlayingThrough = false;
|
||||
|
||||
UInt64 mLastNotifiedIOStoppedOnVCDevice { 0 };
|
||||
|
||||
std::atomic<IOState> mInputDeviceIOProcState { IOState::Stopped };
|
||||
std::atomic<IOState> mOutputDeviceIOProcState { IOState::Stopped };
|
||||
|
||||
// For debug logging.
|
||||
UInt64 mToldOutputDeviceToStartAt { 0 };
|
||||
|
||||
// IOProc vars. (Should only be used inside IOProcs.)
|
||||
|
||||
// The earliest/latest sample times seen by the IOProcs since starting playthrough. -1 for unset.
|
||||
Float64 mFirstInputSampleTime = -1;
|
||||
Float64 mLastInputSampleTime = -1;
|
||||
Float64 mLastOutputSampleTime = -1;
|
||||
|
||||
// Subtract this from the output time to get the input time.
|
||||
Float64 mInToOutSampleOffset { 0.0 };
|
||||
|
||||
VCPlayThroughRTLogger mRTLogger;
|
||||
|
||||
};
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* VCApp__VCPlayThrough */
|
||||
|
||||
521
app/VCPlayThroughRTLogger.cpp
Normal file
521
app/VCPlayThroughRTLogger.cpp
Normal file
@@ -0,0 +1,521 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VCPlayThroughRTLogger.cpp
|
||||
// VCApp
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "VCPlayThroughRTLogger.h"
|
||||
|
||||
// Local Includes
|
||||
#include "VC_Utils.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
|
||||
// STL Includes
|
||||
#include <atomic>
|
||||
|
||||
// System Includes
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/task.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
// Track the number of messages logged when built for the unit tests.
|
||||
#if VC_UnitTest
|
||||
#define LogSync_Debug(inFormat, ...) do { \
|
||||
mNumDebugMessagesLogged++; \
|
||||
DebugMsg(inFormat, ## __VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define LogSync_Debug(inFormat, ...) DebugMsg(inFormat, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
VCPlayThroughRTLogger::VCPlayThroughRTLogger()
|
||||
{
|
||||
// Create the semaphore we use to wake up the logging thread when it has messages to log.
|
||||
mWakeUpLoggingThreadSemaphore = CreateSemaphore();
|
||||
|
||||
// Create the logging thread last because it starts immediately and expects the other member
|
||||
// variables to be initialised.
|
||||
mLoggingThread = std::thread(&VCPlayThroughRTLogger::LoggingThreadEntry, this);
|
||||
}
|
||||
|
||||
// static
|
||||
semaphore_t VCPlayThroughRTLogger::CreateSemaphore()
|
||||
{
|
||||
// TODO: Make a VCMachSemaphore class to reduce some of this repetitive semaphore code.
|
||||
|
||||
// Create the semaphore.
|
||||
semaphore_t semaphore;
|
||||
kern_return_t error =
|
||||
semaphore_create(mach_task_self(), &semaphore, SYNC_POLICY_FIFO, 0);
|
||||
|
||||
// Check the error code.
|
||||
VC_Utils::ThrowIfMachError("VCPlayThroughRTLogger::CreateSemaphore",
|
||||
"semaphore_create",
|
||||
error);
|
||||
ThrowIf(semaphore == SEMAPHORE_NULL,
|
||||
CAException(kAudioHardwareUnspecifiedError),
|
||||
"VCPlayThroughRTLogger::CreateSemaphore: Failed to create semaphore");
|
||||
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
VCPlayThroughRTLogger::~VCPlayThroughRTLogger()
|
||||
{
|
||||
// Stop the logging thread.
|
||||
mLoggingThreadShouldExit = true;
|
||||
kern_return_t error = semaphore_signal(mWakeUpLoggingThreadSemaphore);
|
||||
|
||||
VC_Utils::LogIfMachError("VCPlayThroughRTLogger::~VCPlayThroughRTLogger",
|
||||
"semaphore_signal",
|
||||
error);
|
||||
|
||||
if(error == KERN_SUCCESS)
|
||||
{
|
||||
// Wait for it to stop.
|
||||
mLoggingThread.join();
|
||||
|
||||
// Destroy the semaphore.
|
||||
error = semaphore_destroy(mach_task_self(), mWakeUpLoggingThreadSemaphore);
|
||||
VC_Utils::LogIfMachError("VCPlayThroughRTLogger::~VCPlayThroughRTLogger",
|
||||
"semaphore_destroy",
|
||||
error);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we couldn't tell it to wake up, it's not safe to wait for it to stop or to destroy the
|
||||
// semaphore. We have to detach it so its destructor doesn't cause a crash.
|
||||
mLoggingThread.detach();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Log Messages
|
||||
|
||||
void VCPlayThroughRTLogger::LogReleasingWaitingThreads()
|
||||
{
|
||||
if(!VCDebugLoggingIsEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mLogReleasingWaitingThreadsMsg.is_lock_free())
|
||||
{
|
||||
// Modifying mLogReleasingWaitingThreadsMsg might cause the thread to lock a mutex that
|
||||
// isn't safe to lock on a realtime thread, so just give up.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the flag that tells the logging thread to log the message.
|
||||
mLogReleasingWaitingThreadsMsg = true;
|
||||
|
||||
// Wake the logging thread so it can log the message.
|
||||
WakeLoggingThread();
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogIfMachError_ReleaseWaitingThreadsSignal(mach_error_t inError)
|
||||
{
|
||||
if(inError == KERN_SUCCESS)
|
||||
{
|
||||
// No error.
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mReleaseWaitingThreadsSignalError.is_lock_free())
|
||||
{
|
||||
// Modifying mReleaseWaitingThreadsSignalError might cause the thread to lock a mutex that
|
||||
// isn't safe to lock on a realtime thread, so just give up.
|
||||
return;
|
||||
}
|
||||
|
||||
mReleaseWaitingThreadsSignalError = inError;
|
||||
WakeLoggingThread();
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogIfDroppedFrames(Float64 inFirstInputSampleTime,
|
||||
Float64 inLastInputSampleTime)
|
||||
{
|
||||
if(inFirstInputSampleTime == inLastInputSampleTime || !VCDebugLoggingIsEnabled())
|
||||
{
|
||||
// Either we didn't drop any initial frames or we don't need to log a message about it.
|
||||
return;
|
||||
}
|
||||
|
||||
LogAsync(mDroppedFrames, [&]()
|
||||
{
|
||||
// Store the data to include in the log message.
|
||||
mDroppedFrames.firstInputSampleTime = inFirstInputSampleTime;
|
||||
mDroppedFrames.lastInputSampleTime = inLastInputSampleTime;
|
||||
});
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogNoSamplesReady(CARingBuffer::SampleTime inLastInputSampleTime,
|
||||
CARingBuffer::SampleTime inReadHeadSampleTime,
|
||||
Float64 inInToOutSampleOffset)
|
||||
{
|
||||
if(!VCDebugLoggingIsEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LogAsync(mNoSamplesReady, [&]()
|
||||
{
|
||||
// Store the data to include in the log message.
|
||||
mNoSamplesReady.lastInputSampleTime = inLastInputSampleTime;
|
||||
mNoSamplesReady.readHeadSampleTime = inReadHeadSampleTime;
|
||||
mNoSamplesReady.inToOutSampleOffset = inInToOutSampleOffset;
|
||||
});
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogExceptionStoppingIOProc(const char* inCallerName,
|
||||
OSStatus inError,
|
||||
bool inErrorKnown)
|
||||
{
|
||||
LogAsync(mExceptionStoppingIOProc, [&]()
|
||||
{
|
||||
// Store the data to include in the log message.
|
||||
mExceptionStoppingIOProc.callerName = inCallerName;
|
||||
mExceptionStoppingIOProc.error = inError;
|
||||
mExceptionStoppingIOProc.errorKnown = inErrorKnown;
|
||||
});
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogUnexpectedIOStateAfterStopping(const char* inCallerName,
|
||||
int inIOState)
|
||||
{
|
||||
LogAsync(mUnexpectedIOStateAfterStopping, [&]()
|
||||
{
|
||||
// Store the data to include in the log message.
|
||||
mUnexpectedIOStateAfterStopping.callerName = inCallerName;
|
||||
mUnexpectedIOStateAfterStopping.ioState = inIOState;
|
||||
});
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogRingBufferUnavailable(const char* inCallerName, bool inGotLock)
|
||||
{
|
||||
LogAsync(mRingBufferUnavailable, [&]()
|
||||
{
|
||||
// Store the data to include in the log message.
|
||||
mRingBufferUnavailable.callerName = inCallerName;
|
||||
mRingBufferUnavailable.gotLock = inGotLock;
|
||||
});
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogIfRingBufferError(CARingBufferError inError,
|
||||
std::atomic<CARingBufferError>& outError)
|
||||
{
|
||||
if(inError == kCARingBufferError_OK)
|
||||
{
|
||||
// No error.
|
||||
return;
|
||||
}
|
||||
|
||||
if(!outError.is_lock_free())
|
||||
{
|
||||
// Modifying outError might cause the thread to lock a mutex that isn't safe to lock on
|
||||
// a realtime thread, so just give up.
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the error.
|
||||
outError = inError;
|
||||
|
||||
// Wake the logging thread so it can log the error.
|
||||
WakeLoggingThread();
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void VCPlayThroughRTLogger::LogAsync(T& inMessageData, F&& inStoreMessageData)
|
||||
{
|
||||
if(!inMessageData.shouldLogMessage.is_lock_free())
|
||||
{
|
||||
// Modifying shouldLogMessage might cause the thread to lock a mutex that isn't safe to
|
||||
// lock on a realtime thread, so just give up.
|
||||
return;
|
||||
}
|
||||
|
||||
if(inMessageData.shouldLogMessage)
|
||||
{
|
||||
// The logging thread could be reading inMessageData.
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the data to include in the log message.
|
||||
//
|
||||
// std::forward lets the compiler treat inStoreMessageData as an rvalue if the caller gave it as
|
||||
// an rvalue. No idea if that actually does anything.
|
||||
std::forward<F>(inStoreMessageData)();
|
||||
|
||||
// shouldLogMessage is a std::atomic, so this store also makes sure that the non-atomic stores
|
||||
// in inStoreMessageData will be visible to the logger thread (since the default memory order is
|
||||
// memory_order_seq_cst).
|
||||
inMessageData.shouldLogMessage = true;
|
||||
|
||||
WakeLoggingThread();
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_Warning(const char* inFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, inFormat);
|
||||
|
||||
#if VC_UnitTest
|
||||
mNumWarningMessagesLogged++;
|
||||
#endif
|
||||
|
||||
vLogWarning(inFormat, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_Error(const char* inFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, inFormat);
|
||||
|
||||
#if VC_UnitTest
|
||||
mNumErrorMessagesLogged++;
|
||||
|
||||
if(!mContinueOnErrorLogged)
|
||||
{
|
||||
vLogError(inFormat, args);
|
||||
}
|
||||
#else
|
||||
vLogError(inFormat, args);
|
||||
#endif
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#pragma mark Logging Thread
|
||||
|
||||
void VCPlayThroughRTLogger::WakeLoggingThread()
|
||||
{
|
||||
kern_return_t error = semaphore_signal(mWakeUpLoggingThreadSemaphore);
|
||||
|
||||
VCAssert(error == KERN_SUCCESS, "semaphore_signal (%d)", error);
|
||||
|
||||
// We can't do anything useful with the error in release builds. At least, not easily.
|
||||
(void)error;
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogMessages()
|
||||
{
|
||||
// Log the messages/errors from the realtime threads (if any).
|
||||
LogSync_ReleasingWaitingThreads();
|
||||
LogSync_ReleaseWaitingThreadsSignalError();
|
||||
LogSync_DroppedFrames();
|
||||
LogSync_NoSamplesReady();
|
||||
LogSync_ExceptionStoppingIOProc();
|
||||
LogSync_UnexpectedIOStateAfterStopping();
|
||||
LogSync_RingBufferUnavailable();
|
||||
LogSync_RingBufferError(mRingBufferStoreError, "InputDeviceIOProc");
|
||||
LogSync_RingBufferError(mRingBufferFetchError, "OutputDeviceIOProc");
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_ReleasingWaitingThreads()
|
||||
{
|
||||
if(mLogReleasingWaitingThreadsMsg)
|
||||
{
|
||||
LogSync_Debug("VCPlayThrough::ReleaseThreadsWaitingForOutputToStart: "
|
||||
"Releasing waiting threads");
|
||||
// Reset it.
|
||||
mLogReleasingWaitingThreadsMsg = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_ReleaseWaitingThreadsSignalError()
|
||||
{
|
||||
if(mReleaseWaitingThreadsSignalError != KERN_SUCCESS)
|
||||
{
|
||||
VC_Utils::LogIfMachError("VCPlayThrough::ReleaseThreadsWaitingForOutputToStart",
|
||||
"semaphore_signal_all",
|
||||
mReleaseWaitingThreadsSignalError);
|
||||
// Reset it.
|
||||
mReleaseWaitingThreadsSignalError = KERN_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_DroppedFrames()
|
||||
{
|
||||
if(mDroppedFrames.shouldLogMessage)
|
||||
{
|
||||
LogSync_Debug("VCPlayThrough::OutputDeviceIOProc: "
|
||||
"Dropped %f frames before output started. %s%f %s%f",
|
||||
(mDroppedFrames.lastInputSampleTime - mDroppedFrames.firstInputSampleTime),
|
||||
"mFirstInputSampleTime=",
|
||||
mDroppedFrames.firstInputSampleTime,
|
||||
"mLastInputSampleTime=",
|
||||
mDroppedFrames.lastInputSampleTime);
|
||||
mDroppedFrames.shouldLogMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_NoSamplesReady()
|
||||
{
|
||||
if(mNoSamplesReady.shouldLogMessage)
|
||||
{
|
||||
LogSync_Debug("VCPlayThrough::OutputDeviceIOProc: "
|
||||
"No input samples ready at output sample time. %s%lld %s%lld %s%f",
|
||||
"lastInputSampleTime=", mNoSamplesReady.lastInputSampleTime,
|
||||
"readHeadSampleTime=", mNoSamplesReady.readHeadSampleTime,
|
||||
"mInToOutSampleOffset=", mNoSamplesReady.inToOutSampleOffset);
|
||||
mNoSamplesReady.shouldLogMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_ExceptionStoppingIOProc()
|
||||
{
|
||||
if(mExceptionStoppingIOProc.shouldLogMessage)
|
||||
{
|
||||
const char error4CC[5] = CA4CCToCString(mExceptionStoppingIOProc.error);
|
||||
LogSync_Error("VCPlayThrough::UpdateIOProcState: "
|
||||
"Exception while stopping IOProc %s: %s (%d)",
|
||||
mExceptionStoppingIOProc.callerName,
|
||||
mExceptionStoppingIOProc.errorKnown ? error4CC : "unknown",
|
||||
mExceptionStoppingIOProc.error);
|
||||
mExceptionStoppingIOProc.shouldLogMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_UnexpectedIOStateAfterStopping()
|
||||
{
|
||||
if(mUnexpectedIOStateAfterStopping.shouldLogMessage)
|
||||
{
|
||||
LogSync_Warning("VCPlayThrough::UpdateIOProcState: "
|
||||
"%s IO state changed since last read. state = %d",
|
||||
mUnexpectedIOStateAfterStopping.callerName,
|
||||
mUnexpectedIOStateAfterStopping.ioState);
|
||||
mUnexpectedIOStateAfterStopping.shouldLogMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_RingBufferUnavailable()
|
||||
{
|
||||
if(mRingBufferUnavailable.shouldLogMessage)
|
||||
{
|
||||
LogSync_Warning("VCPlayThrough::%s: Ring buffer unavailable. %s",
|
||||
mRingBufferUnavailable.callerName,
|
||||
mRingBufferUnavailable.gotLock ?
|
||||
"No buffer currently allocated." :
|
||||
"Buffer locked for allocation/deallocation by another thread.");
|
||||
mRingBufferUnavailable.shouldLogMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VCPlayThroughRTLogger::LogSync_RingBufferError(
|
||||
std::atomic<CARingBufferError>& ioRingBufferError,
|
||||
const char* inMethodName)
|
||||
{
|
||||
CARingBufferError error = ioRingBufferError;
|
||||
|
||||
switch(error)
|
||||
{
|
||||
case kCARingBufferError_OK:
|
||||
// No error.
|
||||
return;
|
||||
case kCARingBufferError_CPUOverload:
|
||||
// kCARingBufferError_CPUOverload might not be our fault, so just log a warning.
|
||||
LogSync_Warning("VCPlayThrough::%s: Ring buffer error: "
|
||||
"kCARingBufferError_CPUOverload (%d)",
|
||||
inMethodName,
|
||||
error);
|
||||
break;
|
||||
default:
|
||||
// Other types of CARingBuffer errors should never occur. This will crash debug builds.
|
||||
LogSync_Error("VCPlayThrough::%s: Ring buffer error: %s (%d)",
|
||||
inMethodName,
|
||||
(error == kCARingBufferError_TooMuch ?
|
||||
"kCARingBufferError_TooMuch" :
|
||||
"unknown error"),
|
||||
error);
|
||||
break;
|
||||
};
|
||||
|
||||
// Reset it.
|
||||
ioRingBufferError = kCARingBufferError_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void* __nullable VCPlayThroughRTLogger::LoggingThreadEntry(VCPlayThroughRTLogger* inRefCon)
|
||||
{
|
||||
DebugMsg("VCPlayThroughRTLogger::IOProcLoggingThreadEntry: "
|
||||
"Starting the IOProc logging thread");
|
||||
|
||||
while(!inRefCon->mLoggingThreadShouldExit)
|
||||
{
|
||||
// Log the messages, if there are any to log.
|
||||
inRefCon->LogMessages();
|
||||
|
||||
// Wait until woken up.
|
||||
kern_return_t error = semaphore_wait(inRefCon->mWakeUpLoggingThreadSemaphore);
|
||||
VC_Utils::LogIfMachError("VCPlayThroughRTLogger::IOProcLoggingThreadEntry",
|
||||
"semaphore_wait",
|
||||
error);
|
||||
}
|
||||
|
||||
DebugMsg("VCPlayThroughRTLogger::IOProcLoggingThreadEntry: IOProc logging thread exiting");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if VC_UnitTest
|
||||
|
||||
#pragma mark Test Helpers
|
||||
|
||||
bool VCPlayThroughRTLogger::WaitUntilLoggerThreadIdle()
|
||||
{
|
||||
int msWaited = 0;
|
||||
|
||||
while(mLogReleasingWaitingThreadsMsg ||
|
||||
mReleaseWaitingThreadsSignalError != KERN_SUCCESS ||
|
||||
mDroppedFrames.shouldLogMessage ||
|
||||
mNoSamplesReady.shouldLogMessage ||
|
||||
mUnexpectedIOStateAfterStopping.shouldLogMessage ||
|
||||
mRingBufferUnavailable.shouldLogMessage ||
|
||||
mExceptionStoppingIOProc.shouldLogMessage ||
|
||||
mRingBufferStoreError != kCARingBufferError_OK ||
|
||||
mRingBufferFetchError != kCARingBufferError_OK)
|
||||
{
|
||||
// Poll until the logger thread has nothing left to log. (Ideally we'd use a semaphore
|
||||
// instead of polling, but it isn't worth the effort at this point.)
|
||||
usleep(10 * 1000);
|
||||
msWaited += 10;
|
||||
|
||||
// Time out after 5 seconds.
|
||||
if(msWaited > 5000)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* VC_UnitTest */
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
227
app/VCPlayThroughRTLogger.h
Normal file
227
app/VCPlayThroughRTLogger.h
Normal file
@@ -0,0 +1,227 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VCPlayThroughRTLogger.h
|
||||
// VCApp
|
||||
//
|
||||
// Copyright © 2020 Kyle Neideck
|
||||
//
|
||||
// A real-time safe logger for VCPlayThrough. The messages are logged asynchronously by a
|
||||
// non-realtime thread.
|
||||
//
|
||||
// For the sake of simplicity, this class is very closely coupled with VCPlayThrough and its
|
||||
// methods make assumptions about where they will be called. Also, if the same logging method is
|
||||
// called multiple times before the logging thread next checks for messages, it will only log the
|
||||
// message for one of those calls and ignore the others.
|
||||
//
|
||||
// This class's methods are real-time safe in that they return in a bounded amount of time and we
|
||||
// think they're probably fast enough that the callers won't miss their deadlines, but we don't try
|
||||
// to guarantee it. Some of them should only be called in unusual cases where it's worth increasing
|
||||
// the risk of a thread missing its deadline.
|
||||
//
|
||||
|
||||
#ifndef VCApp__VCPlayThroughRTLogger
|
||||
#define VCApp__VCPlayThroughRTLogger
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CARingBuffer.h"
|
||||
|
||||
// STL Includes
|
||||
#include <thread>
|
||||
|
||||
// System Includes
|
||||
#include <mach/error.h>
|
||||
#include <mach/semaphore.h>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
class VCPlayThroughRTLogger
|
||||
{
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
public:
|
||||
VCPlayThroughRTLogger();
|
||||
~VCPlayThroughRTLogger();
|
||||
VCPlayThroughRTLogger(const VCPlayThroughRTLogger&) = delete;
|
||||
VCPlayThroughRTLogger& operator=(
|
||||
const VCPlayThroughRTLogger&) = delete;
|
||||
private:
|
||||
static semaphore_t CreateSemaphore();
|
||||
|
||||
#pragma mark Log Messages
|
||||
|
||||
public:
|
||||
/*! For VCPlayThrough::ReleaseThreadsWaitingForOutputToStart. */
|
||||
void LogReleasingWaitingThreads();
|
||||
/*! For VCPlayThrough::ReleaseThreadsWaitingForOutputToStart. */
|
||||
void LogIfMachError_ReleaseWaitingThreadsSignal(mach_error_t inError);
|
||||
|
||||
/*! For VCPlayThrough::OutputDeviceIOProc. Not thread-safe. */
|
||||
void LogIfDroppedFrames(Float64 inFirstInputSampleTime,
|
||||
Float64 inLastInputSampleTime);
|
||||
/*! For VCPlayThrough::OutputDeviceIOProc. Not thread-safe. */
|
||||
void LogNoSamplesReady(CARingBuffer::SampleTime inLastInputSampleTime,
|
||||
CARingBuffer::SampleTime inReadHeadSampleTime,
|
||||
Float64 inInToOutSampleOffset);
|
||||
|
||||
/*! For VCPlayThrough::UpdateIOProcState. Not thread-safe. */
|
||||
void LogExceptionStoppingIOProc(const char* inCallerName)
|
||||
{
|
||||
LogExceptionStoppingIOProc(inCallerName, noErr, false);
|
||||
}
|
||||
/*! For VCPlayThrough::UpdateIOProcState. Not thread-safe. */
|
||||
void LogExceptionStoppingIOProc(const char* inCallerName, OSStatus inError)
|
||||
{
|
||||
LogExceptionStoppingIOProc(inCallerName, inError, true);
|
||||
}
|
||||
|
||||
private:
|
||||
void LogExceptionStoppingIOProc(const char* inCallerName,
|
||||
OSStatus inError,
|
||||
bool inErrorKnown);
|
||||
|
||||
public:
|
||||
/*! For VCPlayThrough::UpdateIOProcState. Not thread-safe. */
|
||||
void LogUnexpectedIOStateAfterStopping(const char* inCallerName,
|
||||
int inIOState);
|
||||
/*! For VCPlayThrough::InputDeviceIOProc and VCPlayThrough::OutputDeviceIOProc. */
|
||||
void LogRingBufferUnavailable(const char* inCallerName, bool inGotLock);
|
||||
/*! For VCPlayThrough::OutputDeviceIOProc. */
|
||||
void LogIfRingBufferError_Fetch(CARingBufferError inError)
|
||||
{
|
||||
LogIfRingBufferError(inError, mRingBufferFetchError);
|
||||
}
|
||||
/*! For VCPlayThrough::InputDeviceIOProc. */
|
||||
void LogIfRingBufferError_Store(CARingBufferError inError)
|
||||
{
|
||||
LogIfRingBufferError(inError, mRingBufferStoreError);
|
||||
}
|
||||
|
||||
private:
|
||||
void LogIfRingBufferError(CARingBufferError inError,
|
||||
std::atomic<CARingBufferError>& outError);
|
||||
|
||||
template <typename T, typename F>
|
||||
void LogAsync(T& inMessageData, F&& inStoreMessageData);
|
||||
|
||||
// Wrapper methods used to mock out the logging for unit tests.
|
||||
void LogSync_Warning(const char* inFormat, ...) __printflike(2, 3);
|
||||
void LogSync_Error(const char* inFormat, ...) __printflike(2, 3);
|
||||
|
||||
#pragma mark Logging Thread
|
||||
|
||||
private:
|
||||
void WakeLoggingThread();
|
||||
|
||||
void LogMessages();
|
||||
void LogSync_ReleasingWaitingThreads();
|
||||
void LogSync_ReleaseWaitingThreadsSignalError();
|
||||
void LogSync_DroppedFrames();
|
||||
void LogSync_NoSamplesReady();
|
||||
void LogSync_ExceptionStoppingIOProc();
|
||||
void LogSync_UnexpectedIOStateAfterStopping();
|
||||
void LogSync_RingBufferUnavailable();
|
||||
void LogSync_RingBufferError(
|
||||
std::atomic<CARingBufferError>& ioRingBufferError,
|
||||
const char* inMethodName);
|
||||
|
||||
// The entry point of the logging thread (mLoggingThread).
|
||||
static void* __nullable LoggingThreadEntry(VCPlayThroughRTLogger* inRefCon);
|
||||
|
||||
#if VC_UnitTest
|
||||
|
||||
#pragma mark Test Helpers
|
||||
|
||||
public:
|
||||
/*!
|
||||
* @return True if the logger thread finished logging the requested messages. False if it still
|
||||
* had messages to log after 5 seconds.
|
||||
*/
|
||||
bool WaitUntilLoggerThreadIdle();
|
||||
|
||||
#endif /* VC_UnitTest */
|
||||
|
||||
private:
|
||||
// For VCPlayThrough::ReleaseThreadsWaitingForOutputToStart
|
||||
std::atomic<bool> mLogReleasingWaitingThreadsMsg { false };
|
||||
std::atomic<kern_return_t> mReleaseWaitingThreadsSignalError { KERN_SUCCESS };
|
||||
|
||||
// For VCPlayThrough::InputDeviceIOProc and VCPlayThrough::OutputDeviceIOProc
|
||||
struct {
|
||||
Float64 firstInputSampleTime;
|
||||
Float64 lastInputSampleTime;
|
||||
std::atomic<bool> shouldLogMessage { false };
|
||||
} mDroppedFrames;
|
||||
|
||||
struct {
|
||||
CARingBuffer::SampleTime lastInputSampleTime;
|
||||
CARingBuffer::SampleTime readHeadSampleTime;
|
||||
Float64 inToOutSampleOffset;
|
||||
std::atomic<bool> shouldLogMessage { false };
|
||||
} mNoSamplesReady;
|
||||
|
||||
struct {
|
||||
const char* callerName;
|
||||
bool gotLock;
|
||||
std::atomic<bool> shouldLogMessage { false };
|
||||
} mRingBufferUnavailable;
|
||||
|
||||
// For VCPlayThrough::UpdateIOProcState
|
||||
struct {
|
||||
const char* callerName;
|
||||
int ioState;
|
||||
std::atomic<bool> shouldLogMessage { false };
|
||||
} mUnexpectedIOStateAfterStopping;
|
||||
|
||||
struct {
|
||||
const char* callerName;
|
||||
OSStatus error;
|
||||
bool errorKnown; // If false, we didn't get an error code from the exception.
|
||||
std::atomic<bool> shouldLogMessage { false };
|
||||
} mExceptionStoppingIOProc;
|
||||
|
||||
// For VCPlayThrough::OutputDeviceIOProc
|
||||
std::atomic<CARingBufferError> mRingBufferStoreError { kCARingBufferError_OK };
|
||||
// For VCPlayThrough::InputDeviceIOProc.
|
||||
std::atomic<CARingBufferError> mRingBufferFetchError { kCARingBufferError_OK };
|
||||
|
||||
// Signalled to wake up the mLoggingThread when it has messages to log.
|
||||
semaphore_t mWakeUpLoggingThreadSemaphore;
|
||||
std::atomic<bool> mLoggingThreadShouldExit { false };
|
||||
// The thread that actually logs the messages.
|
||||
std::thread mLoggingThread;
|
||||
|
||||
#if VC_UnitTest
|
||||
|
||||
public:
|
||||
// Tests normally crash (abort) if LogError is called. This flag lets us test the code that
|
||||
// would otherwise call LogError.
|
||||
bool mContinueOnErrorLogged { false };
|
||||
|
||||
int mNumDebugMessagesLogged { 0 };
|
||||
int mNumWarningMessagesLogged { 0 };
|
||||
int mNumErrorMessagesLogged { 0 };
|
||||
|
||||
#endif /* VC_UnitTest */
|
||||
|
||||
};
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* VCApp__VCPlayThroughRTLogger */
|
||||
|
||||
33
app/VCTermination.h
Normal file
33
app/VCTermination.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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.
|
||||
|
||||
#ifndef VCApp__VCTermination
|
||||
#define VCApp__VCTermination
|
||||
|
||||
#import "VCAudioDeviceManager.h"
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
class VCTermination {
|
||||
public:
|
||||
// Sets up signal handlers (SIGINT, SIGTERM, SIGQUIT) and std::terminate handler
|
||||
// to restore the default audio device before exiting.
|
||||
static void SetUpTerminationCleanUp(VCAudioDeviceManager* inAudioDevices);
|
||||
|
||||
private:
|
||||
static void CleanUpAudioDevices();
|
||||
static void* __nullable ExitSignalsProc(void* __nullable ignored);
|
||||
|
||||
static sigset_t sExitSignals;
|
||||
static pthread_t sExitSignalsThread;
|
||||
static std::terminate_handler sOriginalTerminateHandler;
|
||||
static VCAudioDeviceManager* __nullable sAudioDevices;
|
||||
};
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* VCApp__VCTermination */
|
||||
69
app/VCTermination.mm
Normal file
69
app/VCTermination.mm
Normal file
@@ -0,0 +1,69 @@
|
||||
// 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.
|
||||
|
||||
#import "VCTermination.h"
|
||||
#import "VC_Utils.h"
|
||||
|
||||
#import <signal.h>
|
||||
#import <pthread.h>
|
||||
#import <exception>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
std::terminate_handler VCTermination::sOriginalTerminateHandler = std::get_terminate();
|
||||
sigset_t VCTermination::sExitSignals;
|
||||
pthread_t VCTermination::sExitSignalsThread;
|
||||
VCAudioDeviceManager* __nullable VCTermination::sAudioDevices = nullptr;
|
||||
|
||||
void VCTermination::SetUpTerminationCleanUp(VCAudioDeviceManager* inAudioDevices) {
|
||||
sAudioDevices = inAudioDevices;
|
||||
|
||||
// Block SIGINT/SIGTERM/SIGQUIT so our dedicated thread can handle them.
|
||||
sigemptyset(&sExitSignals);
|
||||
sigaddset(&sExitSignals, SIGINT);
|
||||
sigaddset(&sExitSignals, SIGTERM);
|
||||
sigaddset(&sExitSignals, SIGQUIT);
|
||||
pthread_sigmask(SIG_BLOCK, &sExitSignals, nullptr);
|
||||
|
||||
pthread_create(&sExitSignalsThread, nullptr, ExitSignalsProc, nullptr);
|
||||
|
||||
// Wrap std::terminate to clean up before crashing.
|
||||
sOriginalTerminateHandler = std::get_terminate();
|
||||
std::set_terminate([] {
|
||||
CleanUpAudioDevices();
|
||||
sOriginalTerminateHandler();
|
||||
});
|
||||
}
|
||||
|
||||
void VCTermination::CleanUpAudioDevices() {
|
||||
if (sAudioDevices && [sAudioDevices isVirtualDeviceActive]) {
|
||||
[sAudioDevices unsetVCDeviceAsOSDefault];
|
||||
}
|
||||
}
|
||||
|
||||
void* __nullable VCTermination::ExitSignalsProc(void* __nullable ignored) {
|
||||
#pragma unused (ignored)
|
||||
|
||||
int signal = -1;
|
||||
|
||||
while (signal != SIGINT && signal != SIGTERM && signal != SIGQUIT) {
|
||||
if (sigwait(&sExitSignals, &signal) != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NSLog(@"VolumeControl: Received signal %d, cleaning up...", signal);
|
||||
CleanUpAudioDevices();
|
||||
|
||||
// Re-raise with default handler to exit.
|
||||
pthread_sigmask(SIG_UNBLOCK, &sExitSignals, nullptr);
|
||||
raise(signal);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
119
app/VCVirtualDevice.cpp
Normal file
119
app/VCVirtualDevice.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VCVirtualDevice.cpp
|
||||
// VCApp
|
||||
//
|
||||
// Copyright © 2016-2019 Kyle Neideck
|
||||
// Copyright © 2017 Andrew Tonner
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "VCVirtualDevice.h"
|
||||
|
||||
// Local Includes
|
||||
#include "VC_Types.h"
|
||||
#include "VC_Utils.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAHALAudioSystemObject.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
VCVirtualDevice::VCVirtualDevice()
|
||||
:
|
||||
VCAudioDevice(CFSTR(kVCDeviceUID))
|
||||
{
|
||||
if(GetObjectID() == kAudioObjectUnknown)
|
||||
{
|
||||
LogError("VCVirtualDevice::VCVirtualDevice: Error getting VCDevice ID");
|
||||
Throw(CAException(kAudioHardwareIllegalOperationError));
|
||||
}
|
||||
};
|
||||
|
||||
VCVirtualDevice::~VCVirtualDevice()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma mark Systemwide Default Device
|
||||
|
||||
void VCVirtualDevice::SetAsOSDefault()
|
||||
{
|
||||
DebugMsg("VCVirtualDevice::SetAsOSDefault: Setting the system's default audio device "
|
||||
"to VCDevice");
|
||||
|
||||
CAHALAudioSystemObject audioSystem;
|
||||
|
||||
AudioDeviceID defaultDevice = audioSystem.GetDefaultAudioDevice(false, false);
|
||||
AudioDeviceID systemDefaultDevice = audioSystem.GetDefaultAudioDevice(false, true);
|
||||
|
||||
if(systemDefaultDevice == defaultDevice)
|
||||
{
|
||||
// The default system device is the same as the default device, so change both of them.
|
||||
audioSystem.SetDefaultAudioDevice(false, true, GetObjectID());
|
||||
}
|
||||
|
||||
audioSystem.SetDefaultAudioDevice(false, false, GetObjectID());
|
||||
}
|
||||
|
||||
void VCVirtualDevice::UnsetAsOSDefault(AudioDeviceID inOutputDeviceID)
|
||||
{
|
||||
CAHALAudioSystemObject audioSystem;
|
||||
|
||||
bool vcDeviceIsDefault =
|
||||
(audioSystem.GetDefaultAudioDevice(false, false) == GetObjectID());
|
||||
|
||||
if(vcDeviceIsDefault)
|
||||
{
|
||||
DebugMsg("VCVirtualDevice::UnsetAsOSDefault: Setting the system's default output "
|
||||
"device back to device %d", inOutputDeviceID);
|
||||
|
||||
audioSystem.SetDefaultAudioDevice(false, false, inOutputDeviceID);
|
||||
}
|
||||
|
||||
bool vcDeviceIsSystemDefault =
|
||||
(audioSystem.GetDefaultAudioDevice(false, true) == GetObjectID());
|
||||
|
||||
if(vcDeviceIsSystemDefault)
|
||||
{
|
||||
DebugMsg("VCVirtualDevice::UnsetAsOSDefault: Setting the system's default system "
|
||||
"output device back to device %d", inOutputDeviceID);
|
||||
|
||||
audioSystem.SetDefaultAudioDevice(false, true, inOutputDeviceID);
|
||||
}
|
||||
}
|
||||
|
||||
void VCVirtualDevice::SetHidden(bool inHidden)
|
||||
{
|
||||
AudioObjectPropertyAddress addr = {
|
||||
kAudioDeviceCustomPropertyVCHidden,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
CFBooleanRef value = inHidden ? kCFBooleanTrue : kCFBooleanFalse;
|
||||
OSStatus err = AudioObjectSetPropertyData(GetObjectID(), &addr, 0, nullptr, sizeof(CFBooleanRef), &value);
|
||||
|
||||
if (err != kAudioHardwareNoError) {
|
||||
LogError("VCVirtualDevice::SetHidden: Failed (%d)", err);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
85
app/VCVirtualDevice.h
Normal file
85
app/VCVirtualDevice.h
Normal file
@@ -0,0 +1,85 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VCVirtualDevice.h
|
||||
// VCApp
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
//
|
||||
// The interface to VCDevice, the main virtual device published by VCDriver.
|
||||
//
|
||||
// VCDevice is the device that appears as "Background Music" in programs that list the output
|
||||
// devices, e.g. System Preferences. It receives the system's audio, processes it and sends it to
|
||||
// VCApp by publishing an input stream. VCApp then plays the audio on the user's real output
|
||||
// device.
|
||||
//
|
||||
// See VCDriver/VCDriver/VC_Device.h.
|
||||
//
|
||||
|
||||
#ifndef VCApp__VCVirtualDevice
|
||||
#define VCApp__VCVirtualDevice
|
||||
|
||||
// Superclass Includes
|
||||
#include "VCAudioDevice.h"
|
||||
|
||||
// Local Includes
|
||||
#include "VC_Types.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CACFString.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
class VCVirtualDevice
|
||||
:
|
||||
public VCAudioDevice
|
||||
{
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
public:
|
||||
/*!
|
||||
@throws CAException If VCDevice is not found or the HAL returns an error when queried for
|
||||
VCDevice's current Audio Object ID.
|
||||
*/
|
||||
VCVirtualDevice();
|
||||
virtual ~VCVirtualDevice();
|
||||
|
||||
#pragma mark Systemwide Default Device
|
||||
|
||||
public:
|
||||
/*!
|
||||
Set VCDevice as the default audio device for all processes.
|
||||
|
||||
@throws CAException If the HAL responds with an error.
|
||||
*/
|
||||
void SetAsOSDefault();
|
||||
/*!
|
||||
Replace VCDevice as the default device with the output device.
|
||||
|
||||
@throws CAException If the HAL responds with an error.
|
||||
*/
|
||||
void UnsetAsOSDefault(AudioDeviceID inOutputDeviceID);
|
||||
|
||||
// Show or hide the virtual device in system device lists.
|
||||
void SetHidden(bool inHidden);
|
||||
|
||||
};
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* VCApp__VCVirtualDevice */
|
||||
169
app/main.mm
Normal file
169
app/main.mm
Normal file
@@ -0,0 +1,169 @@
|
||||
// VolumeControl
|
||||
//
|
||||
// Provides software volume control for audio devices that lack hardware volume
|
||||
// (e.g. HDMI outputs). Also works as a universal volume control for all devices.
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <AVFoundation/AVCaptureDevice.h>
|
||||
|
||||
#import "VCAudioDeviceManager.h"
|
||||
#import "VCTermination.h"
|
||||
|
||||
|
||||
// Minimal app delegate — handles termination cleanup.
|
||||
@interface VCAppDelegate : NSObject <NSApplicationDelegate>
|
||||
@property (nonatomic) VCAudioDeviceManager* audioDevices;
|
||||
@end
|
||||
|
||||
@implementation VCAppDelegate
|
||||
- (void) applicationWillTerminate:(NSNotification*)note {
|
||||
#pragma unused (note)
|
||||
if ([self.audioDevices isVirtualDeviceActive]) {
|
||||
[self.audioDevices unsetVCDeviceAsOSDefault];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
// Menu bar controller — speaker icon with scroll-to-adjust volume.
|
||||
@interface VCMenuBar : NSObject
|
||||
@property (nonatomic) NSStatusItem* statusItem;
|
||||
@property (nonatomic) VCAudioDeviceManager* audioDevices;
|
||||
@property (nonatomic) id scrollMonitor;
|
||||
@end
|
||||
|
||||
@implementation VCMenuBar
|
||||
|
||||
- (void) setupWithAudioDevices:(VCAudioDeviceManager*)devices {
|
||||
self.audioDevices = devices;
|
||||
self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
|
||||
|
||||
[self updateIcon];
|
||||
|
||||
NSMenu* menu = [[NSMenu alloc] init];
|
||||
|
||||
NSMenuItem* label = [[NSMenuItem alloc] initWithTitle:@"VolumeControl" action:nil keyEquivalent:@""];
|
||||
[label setEnabled:NO];
|
||||
[menu addItem:label];
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
[menu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
|
||||
|
||||
self.statusItem.menu = menu;
|
||||
|
||||
// Scroll on status bar icon to adjust volume.
|
||||
self.scrollMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskScrollWheel
|
||||
handler:^NSEvent*(NSEvent* event) {
|
||||
// Only respond if the mouse is over our status item.
|
||||
NSRect frame = self.statusItem.button.window.frame;
|
||||
NSPoint mouse = [NSEvent mouseLocation];
|
||||
if (!NSPointInRect(mouse, frame)) {
|
||||
return event;
|
||||
}
|
||||
|
||||
float delta = event.scrollingDeltaY;
|
||||
if (event.hasPreciseScrollingDeltas) {
|
||||
delta *= 0.002f; // Trackpad: fine-grained
|
||||
} else {
|
||||
delta *= 0.02f; // Mouse wheel: coarser steps
|
||||
}
|
||||
|
||||
float vol = [self.audioDevices volume] + delta;
|
||||
[self.audioDevices setVolume:vol];
|
||||
[self updateIcon];
|
||||
|
||||
return nil; // Consume the event.
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
if (self.scrollMonitor) {
|
||||
[NSEvent removeMonitor:self.scrollMonitor];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) updateIcon {
|
||||
float vol = [self.audioDevices volume];
|
||||
BOOL muted = [self.audioDevices isMuted];
|
||||
|
||||
NSString* symbolName;
|
||||
if (muted || vol < 0.01f) {
|
||||
symbolName = @"speaker.fill";
|
||||
} else if (vol < 0.33f) {
|
||||
symbolName = @"speaker.wave.1.fill";
|
||||
} else if (vol < 0.66f) {
|
||||
symbolName = @"speaker.wave.2.fill";
|
||||
} else {
|
||||
symbolName = @"speaker.wave.3.fill";
|
||||
}
|
||||
|
||||
NSImage* icon = [NSImage imageWithSystemSymbolName:symbolName
|
||||
accessibilityDescription:@"VolumeControl"];
|
||||
[icon setTemplate:YES];
|
||||
self.statusItem.button.image = icon;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
#pragma unused (argc, argv)
|
||||
|
||||
@autoreleasepool {
|
||||
NSApplication* app = [NSApplication sharedApplication];
|
||||
[app setActivationPolicy:NSApplicationActivationPolicyAccessory];
|
||||
|
||||
NSLog(@"VolumeControl: Starting...");
|
||||
|
||||
VCAudioDeviceManager* audioDevices = [VCAudioDeviceManager new];
|
||||
|
||||
if (!audioDevices) {
|
||||
NSLog(@"VolumeControl: Could not find the virtual audio device driver.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
VCTermination::SetUpTerminationCleanUp(audioDevices);
|
||||
|
||||
// App delegate for clean shutdown.
|
||||
VCAppDelegate* delegate = [[VCAppDelegate alloc] init];
|
||||
delegate.audioDevices = audioDevices;
|
||||
[app setDelegate:delegate];
|
||||
|
||||
// Menu bar icon with scroll volume control.
|
||||
VCMenuBar* menuBar = [[VCMenuBar alloc] init];
|
||||
[menuBar setupWithAudioDevices:audioDevices];
|
||||
|
||||
// Update icon when volume changes externally (keyboard keys, system slider).
|
||||
audioDevices.onVolumeChanged = ^{
|
||||
[menuBar updateIcon];
|
||||
};
|
||||
|
||||
// Request microphone permission. Block until granted.
|
||||
if (@available(macOS 10.14, *)) {
|
||||
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
|
||||
__block BOOL granted = NO;
|
||||
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio
|
||||
completionHandler:^(BOOL g) {
|
||||
granted = g;
|
||||
dispatch_semaphore_signal(sem);
|
||||
}];
|
||||
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
if (!granted) {
|
||||
NSLog(@"VolumeControl: Microphone permission denied.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan devices and activate.
|
||||
[audioDevices evaluateAndActivate];
|
||||
[menuBar updateIcon];
|
||||
|
||||
NSLog(@"VolumeControl: Running.");
|
||||
|
||||
[app run];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
driver/DeviceIcon.icns
Normal file
BIN
driver/DeviceIcon.icns
Normal file
Binary file not shown.
40
driver/Info.plist
Normal file
40
driver/Info.plist
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>VolumeControl</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.volumecontrol.Driver</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>VolumeControl</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.4.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFPlugInFactories</key>
|
||||
<dict>
|
||||
<key>C957AD43-DACA-4A40-8850-3BA8CE28FAF9</key>
|
||||
<string>VC_Create</string>
|
||||
</dict>
|
||||
<key>CFPlugInTypes</key>
|
||||
<dict>
|
||||
<key>443ABAB8-E7B3-491A-B985-BEB9187030DB</key>
|
||||
<array>
|
||||
<string>C957AD43-DACA-4A40-8850-3BA8CE28FAF9</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016-2024 Background Music contributors</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
317
driver/PublicUtility/CAAtomic.h
Normal file
317
driver/PublicUtility/CAAtomic.h
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
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 <windows.h>
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_InterlockedOr)
|
||||
#pragma intrinsic(_InterlockedAnd)
|
||||
#else
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#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__
|
||||
242
driver/PublicUtility/CAAtomicStack.h
Normal file
242
driver/PublicUtility/CAAtomicStack.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
File: CAAtomicStack.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 __CAAtomicStack_h__
|
||||
#define __CAAtomicStack_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <libkern/OSAtomic.h>
|
||||
#else
|
||||
#include <CAAtomic.h>
|
||||
#endif
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
// linked list LIFO or FIFO (pop_all_reversed) stack, elements are pushed and popped atomically
|
||||
// class T must implement T *& next().
|
||||
template <class T>
|
||||
class TAtomicStack {
|
||||
public:
|
||||
TAtomicStack() : mHead(NULL) { }
|
||||
|
||||
// non-atomic routines, for use when initializing/deinitializing, operate NON-atomically
|
||||
void push_NA(T *item)
|
||||
{
|
||||
item->next() = mHead;
|
||||
mHead = item;
|
||||
}
|
||||
|
||||
T * pop_NA()
|
||||
{
|
||||
T *result = mHead;
|
||||
if (result)
|
||||
mHead = result->next();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool empty() const { return mHead == NULL; }
|
||||
|
||||
T * head() { return mHead; }
|
||||
|
||||
// atomic routines
|
||||
void push_atomic(T *item)
|
||||
{
|
||||
T *head_;
|
||||
do {
|
||||
head_ = mHead;
|
||||
item->next() = head_;
|
||||
} while (!compare_and_swap(head_, item, &mHead));
|
||||
}
|
||||
|
||||
void push_multiple_atomic(T *item)
|
||||
// pushes entire linked list headed by item
|
||||
{
|
||||
T *head_, *p = item, *tail;
|
||||
// find the last one -- when done, it will be linked to head
|
||||
do {
|
||||
tail = p;
|
||||
p = p->next();
|
||||
} while (p);
|
||||
do {
|
||||
head_ = mHead;
|
||||
tail->next() = head_;
|
||||
} while (!compare_and_swap(head_, item, &mHead));
|
||||
}
|
||||
|
||||
T * pop_atomic_single_reader()
|
||||
// this may only be used when only one thread may potentially pop from the stack.
|
||||
// if multiple threads may pop, this suffers from the ABA problem.
|
||||
// <rdar://problem/4606346> TAtomicStack suffers from the ABA problem
|
||||
{
|
||||
T *result;
|
||||
do {
|
||||
if ((result = mHead) == NULL)
|
||||
break;
|
||||
} while (!compare_and_swap(result, result->next(), &mHead));
|
||||
return result;
|
||||
}
|
||||
|
||||
T * pop_atomic()
|
||||
// This is inefficient for large linked lists.
|
||||
// prefer pop_all() to a series of calls to pop_atomic.
|
||||
// push_multiple_atomic has to traverse the entire list.
|
||||
{
|
||||
T *result = pop_all();
|
||||
if (result) {
|
||||
T *next = result->next();
|
||||
if (next)
|
||||
// push all the remaining items back onto the stack
|
||||
push_multiple_atomic(next);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
T * pop_all()
|
||||
{
|
||||
T *result;
|
||||
do {
|
||||
if ((result = mHead) == NULL)
|
||||
break;
|
||||
} while (!compare_and_swap(result, NULL, &mHead));
|
||||
return result;
|
||||
}
|
||||
|
||||
T* pop_all_reversed()
|
||||
{
|
||||
TAtomicStack<T> reversed;
|
||||
T *p = pop_all(), *next;
|
||||
while (p != NULL) {
|
||||
next = p->next();
|
||||
reversed.push_NA(p);
|
||||
p = next;
|
||||
}
|
||||
return reversed.mHead;
|
||||
}
|
||||
|
||||
static bool compare_and_swap(T *oldvalue, T *newvalue, T **pvalue)
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#if TARGET_OS_MAC
|
||||
#if __LP64__
|
||||
return ::OSAtomicCompareAndSwap64Barrier(int64_t(oldvalue), int64_t(newvalue), (int64_t *)pvalue);
|
||||
#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||
return ::OSAtomicCompareAndSwap32Barrier(int32_t(oldvalue), int32_t(newvalue), (int32_t *)pvalue);
|
||||
#else
|
||||
return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue);
|
||||
#endif
|
||||
#else
|
||||
//return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue);
|
||||
return CAAtomicCompareAndSwap32Barrier(SInt32(oldvalue), SInt32(newvalue), (SInt32*)pvalue);
|
||||
#endif
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
protected:
|
||||
T * mHead;
|
||||
};
|
||||
|
||||
#if ((MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) && !TARGET_OS_WIN32)
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
class CAAtomicStack {
|
||||
public:
|
||||
CAAtomicStack(size_t nextPtrOffset) : mNextPtrOffset(nextPtrOffset) {
|
||||
/*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/
|
||||
mHead.opaque1 = 0; mHead.opaque2 = 0;
|
||||
}
|
||||
// a subset of the above
|
||||
void push_atomic(void *p) { OSAtomicEnqueue(&mHead, p, mNextPtrOffset); }
|
||||
void push_NA(void *p) { push_atomic(p); }
|
||||
|
||||
void * pop_atomic() { return OSAtomicDequeue(&mHead, mNextPtrOffset); }
|
||||
void * pop_atomic_single_reader() { return pop_atomic(); }
|
||||
void * pop_NA() { return pop_atomic(); }
|
||||
|
||||
private:
|
||||
OSQueueHead mHead;
|
||||
size_t mNextPtrOffset;
|
||||
};
|
||||
|
||||
// a more efficient subset of TAtomicStack using OSQueue.
|
||||
template <class T>
|
||||
class TAtomicStack2 {
|
||||
public:
|
||||
TAtomicStack2() {
|
||||
/*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/
|
||||
mHead.opaque1 = 0; mHead.opaque2 = 0;
|
||||
mNextPtrOffset = -1;
|
||||
}
|
||||
void push_atomic(T *item) {
|
||||
if (mNextPtrOffset < 0) {
|
||||
T **pnext = &item->next(); // hack around offsetof not working with C++
|
||||
mNextPtrOffset = (Byte *)pnext - (Byte *)item;
|
||||
}
|
||||
OSAtomicEnqueue(&mHead, item, mNextPtrOffset);
|
||||
}
|
||||
void push_NA(T *item) { push_atomic(item); }
|
||||
|
||||
T * pop_atomic() { return (T *)OSAtomicDequeue(&mHead, mNextPtrOffset); }
|
||||
T * pop_atomic_single_reader() { return pop_atomic(); }
|
||||
T * pop_NA() { return pop_atomic(); }
|
||||
|
||||
// caution: do not try to implement pop_all_reversed here. the writer could add new elements
|
||||
// while the reader is trying to pop old ones!
|
||||
|
||||
private:
|
||||
OSQueueHead mHead;
|
||||
ssize_t mNextPtrOffset;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#define TAtomicStack2 TAtomicStack
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED && !TARGET_OS_WIN32
|
||||
|
||||
#endif // __CAAtomicStack_h__
|
||||
508
driver/PublicUtility/CAAutoDisposer.h
Normal file
508
driver/PublicUtility/CAAutoDisposer.h
Normal file
@@ -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 <stdlib.h> // for malloc
|
||||
#include <new> // for bad_alloc
|
||||
#include <string.h> // 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 <typename T>
|
||||
struct CAPtrRef
|
||||
{
|
||||
T* ptr_;
|
||||
|
||||
explicit CAPtrRef(T* ptr) : ptr_(ptr) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CAAutoFree
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
|
||||
CAAutoFree() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoFree(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoFree(CAAutoFree<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoFree(CAAutoFree<T>& 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<T*>(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<T*>(clear ? CA_calloc(numItems, sizeof(T)) : CA_malloc(numItems * sizeof(T)));
|
||||
}
|
||||
|
||||
void allocBytes(size_t numBytes, bool clear = false)
|
||||
{
|
||||
free();
|
||||
ptr_ = static_cast<T*>(clear ? CA_calloc(1, numBytes) : CA_malloc(numBytes));
|
||||
}
|
||||
|
||||
void reallocBytes(size_t numBytes)
|
||||
{
|
||||
ptr_ = static_cast<T*>(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<T*>(CA_realloc(ptr_, numItems * sizeof(T)));
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoFree& operator=(CAAutoFree<U>& 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 <typename U>
|
||||
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<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoFree& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoFree<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CAAutoDelete
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
CAAutoDelete() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoDelete(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoDelete(CAAutoDelete<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoDelete(CAAutoDelete<T>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
~CAAutoDelete() { free(); }
|
||||
|
||||
template <typename U>
|
||||
CAAutoDelete& operator=(CAAutoDelete<U>& 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 <typename U>
|
||||
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<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoDelete& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoFree<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CAAutoArrayDelete
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
CAAutoArrayDelete() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoArrayDelete(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoArrayDelete(CAAutoArrayDelete<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoArrayDelete(CAAutoArrayDelete<T>& 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 <typename U>
|
||||
CAAutoArrayDelete& operator=(CAAutoArrayDelete<U>& 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 <typename U>
|
||||
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<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoArrayDelete& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoArrayDelete<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// convenience function
|
||||
template <typename T>
|
||||
void free(CAAutoFree<T>& p)
|
||||
{
|
||||
p.free();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
// example program showing ownership transfer
|
||||
|
||||
CAAutoFree<char> source()
|
||||
{
|
||||
// source allocates and returns ownership to the caller.
|
||||
const char* str = "this is a test";
|
||||
size_t size = strlen(str) + 1;
|
||||
CAAutoFree<char> captr(size, false);
|
||||
strlcpy(captr(), str, size);
|
||||
printf("source %08X %08X '%s'\n", &captr, captr(), captr());
|
||||
return captr;
|
||||
}
|
||||
|
||||
void user(CAAutoFree<char> 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<char> 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<char> 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
|
||||
206
driver/PublicUtility/CABitOperations.h
Normal file
206
driver/PublicUtility/CABitOperations.h
Normal file
@@ -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 <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#else
|
||||
// #include <MacTypes.h>
|
||||
#include "CFBase.h"
|
||||
#endif
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
// 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
|
||||
|
||||
821
driver/PublicUtility/CACFArray.cpp
Normal file
821
driver/PublicUtility/CACFArray.cpp
Normal file
@@ -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<CFBooleanRef>(theValue));
|
||||
theAnswer = true;
|
||||
}
|
||||
else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID()))
|
||||
{
|
||||
SInt32 theNumericValue = 0;
|
||||
CFNumberGetValue(static_cast<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(theValue), kCFNumberSInt32Type, &outValue);
|
||||
theAnswer = true;
|
||||
}
|
||||
else if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID()))
|
||||
{
|
||||
CFStringRef theString = static_cast<CFStringRef>(theValue);
|
||||
if(CFStringGetLength(theString) == 4)
|
||||
{
|
||||
char theCString[5];
|
||||
CFStringGetCString(theString, theCString, 5, kCFStringEncodingASCII);
|
||||
outValue = CFSwapInt32BigToHost(*reinterpret_cast<UInt32*>(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<CFStringRef>(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<CFArrayRef>(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<CFDictionaryRef>(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<CFDataRef>(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<CFUUIDRef>(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<CFIndex>(inIndex));
|
||||
theAnswer = outItem != NULL;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CACFArray::GetCACFString(UInt32 inIndex, CACFString& outItem) const
|
||||
{
|
||||
outItem = static_cast<CFStringRef>(NULL);
|
||||
CFTypeRef theItem = NULL;
|
||||
if(GetCFType(inIndex, theItem))
|
||||
{
|
||||
if((theItem != NULL) && (CFGetTypeID(theItem) == CFStringGetTypeID()))
|
||||
{
|
||||
outItem = static_cast<CFStringRef>(theItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CACFArray::GetCACFArray(UInt32 inIndex, CACFArray& outItem) const
|
||||
{
|
||||
outItem = static_cast<CFArrayRef>(NULL);
|
||||
CFTypeRef theItem = NULL;
|
||||
if(GetCFType(inIndex, theItem))
|
||||
{
|
||||
if((theItem != NULL) && (CFGetTypeID(theItem) == CFArrayGetTypeID()))
|
||||
{
|
||||
outItem = static_cast<CFArrayRef>(theItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CACFArray::GetCACFDictionary(UInt32 inIndex, CACFDictionary& outItem) const
|
||||
{
|
||||
outItem = static_cast<CFDictionaryRef>(NULL);
|
||||
CFTypeRef theItem = NULL;
|
||||
if(GetCFType(inIndex, theItem))
|
||||
{
|
||||
if((theItem != NULL) && (CFGetTypeID(theItem) == CFDictionaryGetTypeID()))
|
||||
{
|
||||
outItem = static_cast<CFDictionaryRef>(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<CFIndex>(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<CFIndex>(inIndex), inItem);
|
||||
theAnswer = true;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
195
driver/PublicUtility/CACFArray.h
Normal file
195
driver/PublicUtility/CACFArray.h
Normal file
@@ -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 <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#include <CoreFoundation.h>
|
||||
#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<CFIndex>(inMaxNumberItems), &kCFTypeArrayCallBacks)), mRelease(inRelease), mMutable(true) {}
|
||||
CACFArray(CFArrayRef inCFArray, bool inRelease) : mCFArray(const_cast<CFMutableArrayRef>(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<CFMutableArrayRef>(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<CFIndex>(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
|
||||
581
driver/PublicUtility/CACFDictionary.cpp
Normal file
581
driver/PublicUtility/CACFDictionary.cpp
Normal file
@@ -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<CFBooleanRef>(theValue));
|
||||
theAnswer = true;
|
||||
}
|
||||
else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID()))
|
||||
{
|
||||
SInt32 theNumericValue = 0;
|
||||
CFNumberGetValue(static_cast<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<Float32>(CFStringGetDoubleValue(static_cast<CFStringRef>(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<CFStringRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(theValue), kCFNumberSInt64Type, &theFixed64);
|
||||
outValue = static_cast<Float64>(theFixed64 >> 32);
|
||||
outValue += static_cast<Float64>(theFixed64 & 0x00000000FFFFFFFFLL) / static_cast<Float64>(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<CFNumberRef>(theValue), kCFNumberSInt32Type, &outValue);
|
||||
theAnswer = true;
|
||||
}
|
||||
else if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID()))
|
||||
{
|
||||
CFStringRef theString = static_cast<CFStringRef>(theValue);
|
||||
if(CFStringGetLength(theString) == 4)
|
||||
{
|
||||
char theCString[5];
|
||||
CFStringGetCString(theString, theCString, 5, kCFStringEncodingASCII);
|
||||
outValue = CFSwapInt32BigToHost(*reinterpret_cast<UInt32*>(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<CFStringRef>(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<CFArrayRef>(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<CFDictionaryRef>(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<CFDataRef>(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<CFURLRef>(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<CFStringRef>(NULL);
|
||||
CFTypeRef theValue = NULL;
|
||||
if(GetCFType(inKey, theValue))
|
||||
{
|
||||
if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID()))
|
||||
{
|
||||
outValue = static_cast<CFStringRef>(theValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CACFDictionary::GetCACFArray(const CFStringRef inKey, CACFArray& outValue) const
|
||||
{
|
||||
outValue = static_cast<CFArrayRef>(NULL);
|
||||
CFTypeRef theValue = NULL;
|
||||
if(GetCFType(inKey, theValue))
|
||||
{
|
||||
if((theValue != NULL) && (CFGetTypeID(theValue) == CFArrayGetTypeID()))
|
||||
{
|
||||
outValue = static_cast<CFArrayRef>(theValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CACFDictionary::GetCACFDictionary(const CFStringRef inKey, CACFDictionary& outValue) const
|
||||
{
|
||||
outValue = static_cast<CFDictionaryRef>(NULL);
|
||||
CFTypeRef theValue = NULL;
|
||||
if(GetCFType(inKey, theValue))
|
||||
{
|
||||
if((theValue != NULL) && (CFGetTypeID(theValue) == CFDictionaryGetTypeID()))
|
||||
{
|
||||
outValue = static_cast<CFDictionaryRef>(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;
|
||||
}
|
||||
176
driver/PublicUtility/CACFDictionary.h
Normal file
176
driver/PublicUtility/CACFDictionary.h
Normal file
@@ -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 <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <CoreFoundation.h>
|
||||
#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<CFMutableDictionaryRef>(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<CFMutableDictionaryRef>(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__
|
||||
83
driver/PublicUtility/CACFNumber.cpp
Normal file
83
driver/PublicUtility/CACFNumber.cpp
Normal file
@@ -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);
|
||||
}
|
||||
151
driver/PublicUtility/CACFNumber.h
Normal file
151
driver/PublicUtility/CACFNumber.h
Normal file
@@ -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 <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CFNumber.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#include <CFNumber.h>
|
||||
#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
|
||||
110
driver/PublicUtility/CACFString.cpp
Normal file
110
driver/PublicUtility/CACFString.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
File: CACFString.cpp
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 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<CFIndex>(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<UInt32>(theStringRange.length) > ioStringSize)
|
||||
{
|
||||
theStringRange.length = static_cast<CFIndex>(ioStringSize);
|
||||
}
|
||||
CFStringGetCharacters(inCFString, theStringRange, outString);
|
||||
ioStringSize = ToUInt32(theStringRange.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
outString[0] = 0;
|
||||
ioStringSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
180
driver/PublicUtility/CACFString.h
Normal file
180
driver/PublicUtility/CACFString.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
File: CACFString.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CACFString_h__)
|
||||
#define __CACFString_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#include "CADebugMacros.h"
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#include <CFString.h>
|
||||
#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) {}
|
||||
CACFString(CFStringRef inCFString, bool inWillRelease = true) : mCFString(inCFString), mWillRelease(inWillRelease) {}
|
||||
CACFString(const char* inCString, bool inWillRelease = true) : 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)); }
|
||||
|
||||
//=============================================================================
|
||||
// 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
|
||||
116
driver/PublicUtility/CADebugMacros.cpp
Normal file
116
driver/PublicUtility/CADebugMacros.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
File: CADebugMacros.cpp
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#include "CADebugMacros.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#if TARGET_API_MAC_OSX
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
|
||||
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);
|
||||
// VC edit: vprintf leaves args in an undefined state, which can cause a crash in
|
||||
// vsyslog. Also added __ASSERT_STOP. Original code commented out below.
|
||||
//#if DEBUG
|
||||
// vprintf(fmt, args);
|
||||
//#endif
|
||||
//#if TARGET_API_MAC_OSX
|
||||
// vsyslog(LOG_ERR, fmt, args);
|
||||
//#endif
|
||||
#if (DEBUG || !TARGET_API_MAC_OSX) && !CoreAudio_UseSysLog
|
||||
printf("[ERROR] ");
|
||||
vprintf(fmt, args);
|
||||
printf("\n");
|
||||
#else
|
||||
vsyslog(LOG_ERR, fmt, args);
|
||||
#endif
|
||||
#if DEBUG
|
||||
__ASSERT_STOP;
|
||||
#endif
|
||||
// VC edit end
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void LogWarning(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
// VC edit: vprintf leaves args in an undefined state, which can cause a crash in
|
||||
// vsyslog. Also added __ASSERT_STOP. Original code commented out below.
|
||||
//#if DEBUG
|
||||
// vprintf(fmt, args);
|
||||
//#endif
|
||||
//#if TARGET_API_MAC_OSX
|
||||
// vsyslog(LOG_WARNING, fmt, args);
|
||||
//#endif
|
||||
#if (DEBUG || !TARGET_API_MAC_OSX) && !CoreAudio_UseSysLog
|
||||
printf("[WARNING] ");
|
||||
vprintf(fmt, args);
|
||||
printf("\n");
|
||||
#else
|
||||
vsyslog(LOG_WARNING, fmt, args);
|
||||
#endif
|
||||
#if DEBUG
|
||||
//__ASSERT_STOP; // TODO: Add a toggle for this to the project file (under "Preprocessor Macros"). Default to off.
|
||||
#endif
|
||||
// VC edit end
|
||||
va_end(args);
|
||||
}
|
||||
583
driver/PublicUtility/CADebugMacros.h
Normal file
583
driver/PublicUtility/CADebugMacros.h
Normal file
@@ -0,0 +1,583 @@
|
||||
/*
|
||||
File: CADebugMacros.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CADebugMacros_h__)
|
||||
#define __CADebugMacros_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// 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
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
// can be used to break into debugger immediately, also see CADebugger
|
||||
#define BusError() { long* p=NULL; *p=0; }
|
||||
|
||||
// basic debugging print routines
|
||||
#if TARGET_OS_MAC && !TARGET_API_MAC_CARBON
|
||||
extern void DebugStr(const unsigned char* debuggerMsg);
|
||||
#define DebugMessage(msg) DebugStr("\p"msg)
|
||||
#define DebugMessageN1(msg, N1)
|
||||
#define DebugMessageN2(msg, N1, N2)
|
||||
#define DebugMessageN3(msg, N1, N2, N3)
|
||||
#else
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
#if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile)
|
||||
#define FlushRtn ,fflush(DebugPrintfFile)
|
||||
#else
|
||||
#define FlushRtn
|
||||
#endif
|
||||
|
||||
#if CoreAudio_ThreadStampMessages
|
||||
#include <pthread.h>
|
||||
#include "CAHostTimeBase.h"
|
||||
#if TARGET_RT_64_BIT
|
||||
#define DebugPrintfThreadIDFormat "%16p"
|
||||
#else
|
||||
#define DebugPrintfThreadIDFormat "%8p"
|
||||
#endif
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " DebugPrintfThreadIDFormat " " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), ## __VA_ARGS__) FlushRtn
|
||||
#elif CoreAudio_TimeStampMessages
|
||||
#include "CAHostTimeBase.h"
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), ## __VA_ARGS__) FlushRtn
|
||||
#else
|
||||
#define DebugMsg(inFormat, ...) DebugPrintf(inFormat, ## __VA_ARGS__) FlushRtn
|
||||
#endif
|
||||
#endif
|
||||
void DebugPrint(const char *fmt, ...); // can be used like printf
|
||||
#ifndef DEBUGPRINT
|
||||
#define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h)
|
||||
#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
|
||||
#define DebugMsg(inFormat, ...)
|
||||
#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.
|
||||
void LogError(const char *fmt, ...) __printflike(1, 2); // writes to syslog (and stderr if debugging)
|
||||
void LogWarning(const char *fmt, ...) __printflike(1, 2); // writes to syslog (and stderr if debugging)
|
||||
|
||||
#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); \
|
||||
}
|
||||
|
||||
// VC edit: Changed "unsigned int" to "int" to silence -Wsign-conversion.
|
||||
#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
|
||||
89
driver/PublicUtility/CADebugPrintf.cpp
Normal file
89
driver/PublicUtility/CADebugPrintf.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
File: CADebugPrintf.cpp
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// Self Include
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <Windows.h>
|
||||
extern "C"
|
||||
int CAWin32DebugPrintf(char* inFormat, ...)
|
||||
{
|
||||
char theMessage[1024];
|
||||
va_list theArguments;
|
||||
va_start(theArguments, inFormat);
|
||||
_vsnprintf(theMessage, 1024, inFormat, theArguments);
|
||||
va_end(theArguments);
|
||||
OutputDebugString(theMessage);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CoreAudio_UseSideFile)
|
||||
#include <unistd.h>
|
||||
FILE* sDebugPrintfSideFile = NULL;
|
||||
extern "C"
|
||||
void OpenDebugPrintfSideFile()
|
||||
{
|
||||
if(sDebugPrintfSideFile == NULL)
|
||||
{
|
||||
char theFileName[1024];
|
||||
snprintf(theFileName, sizeof(theFileName), CoreAudio_UseSideFile, getpid());
|
||||
sDebugPrintfSideFile = fopen(theFileName, "a+");
|
||||
DebugPrintfRtn(DebugPrintfFileComma "\n------------------------------\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
115
driver/PublicUtility/CADebugPrintf.h
Normal file
115
driver/PublicUtility/CADebugPrintf.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
File: CADebugPrintf.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CADebugPrintf_h__)
|
||||
#define __CADebugPrintf_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// Macros to redirect debugging output to various logging services
|
||||
//=============================================================================
|
||||
|
||||
//#define CoreAudio_UseSysLog 1
|
||||
//#define CoreAudio_UseSideFile "/CoreAudio-%d.txt"
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
extern int CAWin32DebugPrintf(char* inFormat, ...);
|
||||
#define DebugPrintfRtn CAWin32DebugPrintf
|
||||
#define DebugPrintfFile
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma
|
||||
#else
|
||||
#if CoreAudio_UseSysLog
|
||||
#include <sys/syslog.h>
|
||||
#define DebugPrintfRtn syslog
|
||||
#define DebugPrintfFile LOG_NOTICE
|
||||
#define DebugPrintfLineEnding ""
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#elif defined(CoreAudio_UseSideFile)
|
||||
#include <stdio.h>
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
void OpenDebugPrintfSideFile();
|
||||
extern FILE* sDebugPrintfSideFile;
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile ((sDebugPrintfSideFile != NULL) ? sDebugPrintfSideFile : stderr)
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile stderr
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DebugPrintf(inFormat, ...) DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DebugPrintfRtn
|
||||
#define DebugPrintfFile
|
||||
#define DebugPrintfLineEnding
|
||||
#define DebugPrintfFileComma
|
||||
#define DebugPrintf(inFormat, ...)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
103
driver/PublicUtility/CADebugger.cpp
Normal file
103
driver/PublicUtility/CADebugger.cpp
Normal file
@@ -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 <sys/sysctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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
|
||||
}
|
||||
69
driver/PublicUtility/CADebugger.h
Normal file
69
driver/PublicUtility/CADebugger.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
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 <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CADebugger
|
||||
//=============================================================================
|
||||
|
||||
#if TARGET_API_MAC_OSX
|
||||
extern bool CAIsDebuggerAttached(void);
|
||||
#endif
|
||||
extern void CADebuggerStop(void);
|
||||
|
||||
#endif
|
||||
438
driver/PublicUtility/CADispatchQueue.cpp
Normal file
438
driver/PublicUtility/CADispatchQueue.cpp
Normal file
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
File: CADispatchQueue.cpp
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
/*==================================================================================================
|
||||
CADispatchQueue.cpp
|
||||
==================================================================================================*/
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// Self Include
|
||||
#include "CADispatchQueue.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CACFString.h"
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAException.h"
|
||||
#include "CAHostTimeBase.h"
|
||||
|
||||
// System Includes
|
||||
#include <mach/mach.h>
|
||||
|
||||
// Standard Library Includes
|
||||
#include <algorithm>
|
||||
|
||||
//==================================================================================================
|
||||
// CADispatchQueue
|
||||
//==================================================================================================
|
||||
|
||||
CADispatchQueue::CADispatchQueue(const char* inName)
|
||||
:
|
||||
mDispatchQueue(NULL),
|
||||
mPortDeathList(),
|
||||
mMachPortReceiverList()
|
||||
{
|
||||
mDispatchQueue = dispatch_queue_create(inName, NULL);
|
||||
ThrowIfNULL(mDispatchQueue, CAException('what'), "CADispatchQueue::CADispatchQueue: failed to create the dispatch queue");
|
||||
}
|
||||
|
||||
CADispatchQueue::CADispatchQueue(CFStringRef inName)
|
||||
:
|
||||
mDispatchQueue(NULL),
|
||||
mPortDeathList(),
|
||||
mMachPortReceiverList()
|
||||
{
|
||||
CACFString theCFName(inName, false);
|
||||
char theName[256];
|
||||
UInt32 theSize = 256;
|
||||
theCFName.GetCString(theName, theSize);
|
||||
mDispatchQueue = dispatch_queue_create(theName, NULL);
|
||||
ThrowIfNULL(mDispatchQueue, CAException('what'), "CADispatchQueue::CADispatchQueue: failed to create the dispatch queue");
|
||||
}
|
||||
|
||||
CADispatchQueue::CADispatchQueue(CFStringRef inPattern, CFStringRef inName)
|
||||
:
|
||||
mDispatchQueue(NULL),
|
||||
mPortDeathList(),
|
||||
mMachPortReceiverList()
|
||||
{
|
||||
CACFString theCFName(CFStringCreateWithFormat(NULL, NULL, inPattern, inName), true);
|
||||
char theName[256];
|
||||
UInt32 theSize = 256;
|
||||
theCFName.GetCString(theName, theSize);
|
||||
mDispatchQueue = dispatch_queue_create(theName, NULL);
|
||||
ThrowIfNULL(mDispatchQueue, CAException('what'), "CADispatchQueue::CADispatchQueue: failed to create the dispatch queue");
|
||||
}
|
||||
|
||||
CADispatchQueue::~CADispatchQueue()
|
||||
{
|
||||
// Clean up the port death watchers if any are still around. Note that we do this explicitly to
|
||||
// be sure the source is cleaned up before the queue is released
|
||||
mPortDeathList.clear();
|
||||
Assert(mMachPortReceiverList.size() == 0, "CADispatchQueue::~CADispatchQueue: Implicitly removing the mach port receviers. It is best to explicitly call RemoveMachPortRecevier().");
|
||||
mMachPortReceiverList.clear();
|
||||
|
||||
// release the dispatch queue
|
||||
dispatch_release(mDispatchQueue);
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch(bool inDoSync, dispatch_block_t inTask) const
|
||||
{
|
||||
if(inDoSync)
|
||||
{
|
||||
// Executing a task synchronously while already on the dispatch queue will result in a deadlock
|
||||
dispatch_sync(mDispatchQueue, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_async(mDispatchQueue, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch(UInt64 inNanoseconds, dispatch_block_t inTask) const
|
||||
{
|
||||
if(inNanoseconds == 0)
|
||||
{
|
||||
dispatch_async(mDispatchQueue, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_after(dispatch_time(0, static_cast<int64_t>(CAHostTimeBase::ConvertFromNanos(inNanoseconds))), mDispatchQueue, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch(bool inDoSync, void* inTaskContext, dispatch_function_t inTask) const
|
||||
{
|
||||
if(inDoSync)
|
||||
{
|
||||
// Executing a task synchronously while already on the dispatch queue will result in a deadlock
|
||||
dispatch_sync_f(mDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_async_f(mDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch(UInt64 inNanoseconds, void* inTaskContext, dispatch_function_t inTask) const
|
||||
{
|
||||
if(inNanoseconds == 0)
|
||||
{
|
||||
dispatch_async_f(mDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_after_f(dispatch_time(0, static_cast<int64_t>(CAHostTimeBase::ConvertFromNanos(inNanoseconds))), mDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch_Global(dispatch_queue_priority_t inQueuePriority, bool inDoSync, dispatch_block_t inTask)
|
||||
{
|
||||
dispatch_queue_t theDispatchQueue = dispatch_get_global_queue(inQueuePriority, 0);
|
||||
if(inDoSync)
|
||||
{
|
||||
// Executing a task synchronously while already on the dispatch queue will result in a deadlock
|
||||
dispatch_sync(theDispatchQueue, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_async(theDispatchQueue, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch_Global(dispatch_queue_priority_t inQueuePriority, UInt64 inNanoseconds, dispatch_block_t inTask)
|
||||
{
|
||||
dispatch_queue_t theDispatchQueue = dispatch_get_global_queue(inQueuePriority, 0);
|
||||
if(inNanoseconds == 0)
|
||||
{
|
||||
dispatch_async(theDispatchQueue, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_after(dispatch_time(0, static_cast<int64_t>(CAHostTimeBase::ConvertFromNanos(inNanoseconds))), theDispatchQueue, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch_Global(dispatch_queue_priority_t inQueuePriority, bool inDoSync, void* inTaskContext, dispatch_function_t inTask)
|
||||
{
|
||||
dispatch_queue_t theDispatchQueue = dispatch_get_global_queue(inQueuePriority, 0);
|
||||
if(inDoSync)
|
||||
{
|
||||
// Executing a task synchronously while already on the dispatch queue will result in a deadlock
|
||||
dispatch_sync_f(theDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_async_f(theDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch_Global(dispatch_queue_priority_t inQueuePriority, UInt64 inNanoseconds, void* inTaskContext, dispatch_function_t inTask)
|
||||
{
|
||||
dispatch_queue_t theDispatchQueue = dispatch_get_global_queue(inQueuePriority, 0);
|
||||
if(inNanoseconds == 0)
|
||||
{
|
||||
dispatch_async_f(theDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_after_f(dispatch_time(0, static_cast<int64_t>(CAHostTimeBase::ConvertFromNanos(inNanoseconds))), theDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch_Main(bool inDoSync, dispatch_block_t inTask)
|
||||
{
|
||||
dispatch_queue_t theDispatchQueue = dispatch_get_main_queue();
|
||||
if(inDoSync)
|
||||
{
|
||||
// Executing a task synchronously while already on the dispatch queue will result in a deadlock
|
||||
dispatch_sync(theDispatchQueue, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_async(theDispatchQueue, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch_Main(UInt64 inNanoseconds, dispatch_block_t inTask)
|
||||
{
|
||||
dispatch_queue_t theDispatchQueue = dispatch_get_main_queue();
|
||||
if(inNanoseconds == 0)
|
||||
{
|
||||
dispatch_async(theDispatchQueue, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_after(dispatch_time(0, static_cast<int64_t>(CAHostTimeBase::ConvertFromNanos(inNanoseconds))), theDispatchQueue, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch_Main(bool inDoSync, void* inTaskContext, dispatch_function_t inTask)
|
||||
{
|
||||
dispatch_queue_t theDispatchQueue = dispatch_get_main_queue();
|
||||
if(inDoSync)
|
||||
{
|
||||
// Executing a task synchronously while already on the dispatch queue will result in a deadlock
|
||||
dispatch_sync_f(theDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_async_f(theDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::Dispatch_Main(UInt64 inNanoseconds, void* inTaskContext, dispatch_function_t inTask)
|
||||
{
|
||||
dispatch_queue_t theDispatchQueue = dispatch_get_main_queue();
|
||||
if(inNanoseconds == 0)
|
||||
{
|
||||
dispatch_async_f(theDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_after_f(dispatch_time(0, static_cast<int64_t>(CAHostTimeBase::ConvertFromNanos(inNanoseconds))), theDispatchQueue, inTaskContext, inTask);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::InstallMachPortDeathNotification(mach_port_t inMachPort, dispatch_block_t inNotificationTask)
|
||||
{
|
||||
ThrowIf(inMachPort == MACH_PORT_NULL, CAException('nope'), "CADispatchQueue::InstallMachPortDeathNotification: a mach port is required");
|
||||
|
||||
// look in the list to see if we've already created an event source for it
|
||||
bool wasFound = false;
|
||||
EventSourceList::iterator theIterator = mPortDeathList.begin();
|
||||
while(!wasFound && (theIterator != mPortDeathList.end()))
|
||||
{
|
||||
wasFound = theIterator->mMachPort == inMachPort;
|
||||
if(!wasFound)
|
||||
{
|
||||
++theIterator;
|
||||
}
|
||||
}
|
||||
|
||||
// create and install the event source for the port
|
||||
if(!wasFound)
|
||||
{
|
||||
// create an event source for the mach port
|
||||
dispatch_source_t theDispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, inMachPort, DISPATCH_MACH_SEND_DEAD, mDispatchQueue);
|
||||
ThrowIfNULL(theDispatchSource, CAException('what'), "CADispatchQueue::InstallMachPortDeathNotification: failed to create the mach port event source");
|
||||
|
||||
// install the event handler
|
||||
dispatch_source_set_event_handler(theDispatchSource, inNotificationTask);
|
||||
|
||||
// put the info in the list
|
||||
mPortDeathList.push_back(EventSource(theDispatchSource, inMachPort));
|
||||
|
||||
// resume the event source so that it can start handling messages and also so that the source can be released
|
||||
dispatch_resume(theDispatchSource);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::RemoveMachPortDeathNotification(mach_port_t inMachPort)
|
||||
{
|
||||
bool wasFound = false;
|
||||
EventSourceList::iterator theIterator = mPortDeathList.begin();
|
||||
while(!wasFound && (theIterator != mPortDeathList.end()))
|
||||
{
|
||||
wasFound = theIterator->mMachPort == inMachPort;
|
||||
if(!wasFound)
|
||||
{
|
||||
++theIterator;
|
||||
}
|
||||
}
|
||||
if(wasFound)
|
||||
{
|
||||
if(theIterator->mDispatchSource != NULL)
|
||||
{
|
||||
dispatch_source_cancel(theIterator->mDispatchSource);
|
||||
}
|
||||
mPortDeathList.erase(theIterator);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::InstallMachPortReceiver(mach_port_t inMachPort, dispatch_block_t inMessageTask)
|
||||
{
|
||||
ThrowIf(inMachPort == MACH_PORT_NULL, CAException('nope'), "CADispatchQueue::InstallMachPortReceiver: a mach port is required");
|
||||
|
||||
// look in the list to see if we've already created an event source for it
|
||||
bool wasFound = false;
|
||||
EventSourceList::iterator theIterator = mMachPortReceiverList.begin();
|
||||
while(!wasFound && (theIterator != mMachPortReceiverList.end()))
|
||||
{
|
||||
wasFound = theIterator->mMachPort == inMachPort;
|
||||
if(!wasFound)
|
||||
{
|
||||
++theIterator;
|
||||
}
|
||||
}
|
||||
|
||||
// create and install the event source for the port
|
||||
if(!wasFound)
|
||||
{
|
||||
// create an event source for the mach port
|
||||
dispatch_source_t theDispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, inMachPort, 0, mDispatchQueue);
|
||||
ThrowIfNULL(theDispatchSource, CAException('what'), "CADispatchQueue::InstallMachPortReceiver: failed to create the mach port event source");
|
||||
|
||||
// install an event handler that maps the mach messages to the MIG server function
|
||||
dispatch_source_set_event_handler(theDispatchSource, inMessageTask);
|
||||
|
||||
// put the info in the list
|
||||
mMachPortReceiverList.push_back(EventSource(theDispatchSource, inMachPort));
|
||||
|
||||
// resume the event source so that it can start handling messages and also so that the source can be released
|
||||
dispatch_resume(theDispatchSource);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::RemoveMachPortReceiver(mach_port_t inMachPort, dispatch_block_t inCompletionTask)
|
||||
{
|
||||
bool wasFound = false;
|
||||
EventSourceList::iterator theIterator = mMachPortReceiverList.begin();
|
||||
while(!wasFound && (theIterator != mMachPortReceiverList.end()))
|
||||
{
|
||||
wasFound = theIterator->mMachPort == inMachPort;
|
||||
if(!wasFound)
|
||||
{
|
||||
++theIterator;
|
||||
}
|
||||
}
|
||||
if(wasFound)
|
||||
{
|
||||
if(theIterator->mDispatchSource != NULL)
|
||||
{
|
||||
// Set the cancel handler to the completion block. Note that the mach port cannot be freed
|
||||
// before the completion block runs due to a race condition. See the note in the comments
|
||||
// dispatch_source_set_cancel_handler in <dispatch/source.h>.
|
||||
if(inCompletionTask != 0)
|
||||
{
|
||||
dispatch_source_set_cancel_handler(theIterator->mDispatchSource, inCompletionTask);
|
||||
}
|
||||
|
||||
dispatch_source_cancel(theIterator->mDispatchSource);
|
||||
}
|
||||
mMachPortReceiverList.erase(theIterator);
|
||||
}
|
||||
}
|
||||
|
||||
void CADispatchQueue::RemoveMachPortReceiver(mach_port_t inMachPort, bool inDestroySendRight, bool inDestroyReceiveRight)
|
||||
{
|
||||
RemoveMachPortReceiver(inMachPort, ^{
|
||||
if(inDestroySendRight)
|
||||
{
|
||||
kern_return_t theError = mach_port_deallocate(mach_task_self(), inMachPort);
|
||||
AssertNoKernelError(theError, "CADispatchQueue::RemoveMachPortReceiver: deallocating the send right failed");
|
||||
}
|
||||
if(inDestroyReceiveRight)
|
||||
{
|
||||
kern_return_t theError = mach_port_mod_refs(mach_task_self(), inMachPort, MACH_PORT_RIGHT_RECEIVE, -1);
|
||||
AssertNoKernelError(theError, "CADispatchQueue::RemoveMachPortReceiver: deallocating the receive right failed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CADispatchQueue& CADispatchQueue::GetGlobalSerialQueue()
|
||||
{
|
||||
dispatch_once_f(&sGlobalSerialQueueInitialized, NULL, InitializeGlobalSerialQueue);
|
||||
ThrowIfNULL(sGlobalSerialQueue, CAException('nope'), "CADispatchQueue::GetGlobalSerialQueue: there is no global serial queue");
|
||||
return *sGlobalSerialQueue;
|
||||
}
|
||||
|
||||
void CADispatchQueue::InitializeGlobalSerialQueue(void*)
|
||||
{
|
||||
try
|
||||
{
|
||||
sGlobalSerialQueue = new CADispatchQueue("com.apple.audio.CADispatchQueue.SerialQueue");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
sGlobalSerialQueue = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CADispatchQueue* CADispatchQueue::sGlobalSerialQueue = NULL;
|
||||
dispatch_once_t CADispatchQueue::sGlobalSerialQueueInitialized = 0;
|
||||
235
driver/PublicUtility/CADispatchQueue.h
Normal file
235
driver/PublicUtility/CADispatchQueue.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
File: CADispatchQueue.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
/*==================================================================================================
|
||||
CADispatchQueue.h
|
||||
==================================================================================================*/
|
||||
#if !defined(__CADispatchQueue_h__)
|
||||
#define __CADispatchQueue_h__
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// System Includes
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
// Standard Library Includes
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
/*==================================================================================================
|
||||
CADispatchQueue
|
||||
|
||||
This class provides a wrapper for a libdispatch dispatch queue and several kinds of event
|
||||
sources such as MIG servers, port death notifications and other mach port related support. Being
|
||||
a libdispatch client, the unit of work is represented as either a function pointer and context
|
||||
pointer pair or as a Block.
|
||||
|
||||
One thing to keep in mind when using a Block-based construct is that you get a copy of the
|
||||
pointer but you do not get a copy of the memory that the pointer is pointing at. The net effect
|
||||
is that if you have a task that frees the memory that is referenced by a subsequent task,
|
||||
this second task would crash when dereferencing the pointer. This means that every task
|
||||
needs to include some code to validate any pointers it is using before dereferencing them.
|
||||
|
||||
A common example of this problem comes up with C++ objects. Suppose you have an instance method
|
||||
that creates a Block that calls other instance methods or accesses the object's fields. Suppose
|
||||
further that the Block is submitted to a dispatch queue for execution. If the object gets
|
||||
deallocated before the Block can run, the Block will crash. Thus, the Block needs to validate
|
||||
that the "this" pointer is still valid when it executes.
|
||||
|
||||
Another place where this comes up often is when attempting to implment a function by dispatching
|
||||
the work asynchronously. Any arguments to the function that point to the stack will be invalid.
|
||||
This is particularly troublesome inside of a MIG function.
|
||||
|
||||
Still another common issue with using Blocks and dispatch functions with C++ is that it is vital
|
||||
that no exceptions ever leave a Block or a dispatch function. If an exception was thrown out of
|
||||
a block, the result would be undefined and probably would result in the program calling
|
||||
the terminate() function in the standard C++ library (whose default implementation is to call
|
||||
abort(3)). Given that, all Blocks and dispatch functions that might end up throwing an exception
|
||||
need to catch those exceptions.
|
||||
==================================================================================================*/
|
||||
|
||||
class CADispatchQueue
|
||||
{
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
public:
|
||||
CADispatchQueue(const char* inName);
|
||||
CADispatchQueue(CFStringRef inName);
|
||||
CADispatchQueue(CFStringRef inPattern, CFStringRef inName);
|
||||
virtual ~CADispatchQueue();
|
||||
|
||||
private:
|
||||
CADispatchQueue(const CADispatchQueue&);
|
||||
CADispatchQueue& operator=(const CADispatchQueue&);
|
||||
|
||||
#pragma mark Execution Operations
|
||||
public:
|
||||
void Dispatch(bool inDoSync, dispatch_block_t inTask) const;
|
||||
void Dispatch(UInt64 inNanoseconds, dispatch_block_t inTask) const;
|
||||
|
||||
void Dispatch(bool inDoSync, void* inTaskContext, dispatch_function_t inTask) const;
|
||||
void Dispatch(UInt64 inNanoseconds, void* inTaskContext, dispatch_function_t inTask) const;
|
||||
|
||||
static void Dispatch_Global(dispatch_queue_priority_t inQueuePriority, bool inDoSync, dispatch_block_t inTask);
|
||||
static void Dispatch_Global(dispatch_queue_priority_t inQueuePriority, UInt64 inNanoseconds, dispatch_block_t inTask);
|
||||
|
||||
static void Dispatch_Global(dispatch_queue_priority_t inQueuePriority, bool inDoSync, void* inTaskContext, dispatch_function_t inTask);
|
||||
static void Dispatch_Global(dispatch_queue_priority_t inQueuePriority, UInt64 inNanoseconds, void* inTaskContext, dispatch_function_t inTask);
|
||||
|
||||
static void Dispatch_Main(bool inDoSync, dispatch_block_t inTask);
|
||||
static void Dispatch_Main(UInt64 inNanoseconds, dispatch_block_t inTask);
|
||||
|
||||
static void Dispatch_Main(bool inDoSync, void* inTaskContext, dispatch_function_t inTask);
|
||||
static void Dispatch_Main(UInt64 inNanoseconds, void* inTaskContext, dispatch_function_t inTask);
|
||||
|
||||
#pragma mark Event Sources
|
||||
public:
|
||||
void InstallMachPortDeathNotification(mach_port_t inMachPort, dispatch_block_t inNotificationTask);
|
||||
void RemoveMachPortDeathNotification(mach_port_t inMachPort);
|
||||
|
||||
void InstallMachPortReceiver(mach_port_t inMachPort, dispatch_block_t inMessageTask);
|
||||
void RemoveMachPortReceiver(mach_port_t inMachPort, dispatch_block_t inCompletionTask);
|
||||
void RemoveMachPortReceiver(mach_port_t inMachPort, bool inDestroySendRight, bool inDestroyReceiveRight);
|
||||
|
||||
#pragma mark Implementation
|
||||
public:
|
||||
dispatch_queue_t GetDispatchQueue() const;
|
||||
|
||||
static CADispatchQueue& GetGlobalSerialQueue();
|
||||
|
||||
protected:
|
||||
static void InitializeGlobalSerialQueue(void*);
|
||||
|
||||
struct EventSource
|
||||
{
|
||||
dispatch_source_t mDispatchSource;
|
||||
mach_port_t mMachPort;
|
||||
|
||||
EventSource();
|
||||
EventSource(dispatch_source_t inDispatchSource, mach_port_t inMachPort);
|
||||
EventSource(const EventSource& inEventSource);
|
||||
EventSource& operator=(const EventSource& inEventSource);
|
||||
~EventSource();
|
||||
void Retain();
|
||||
void Release();
|
||||
};
|
||||
typedef std::vector<EventSource> EventSourceList;
|
||||
|
||||
dispatch_queue_t mDispatchQueue;
|
||||
EventSourceList mPortDeathList;
|
||||
EventSourceList mMachPortReceiverList;
|
||||
|
||||
static CADispatchQueue* sGlobalSerialQueue;
|
||||
static dispatch_once_t sGlobalSerialQueueInitialized;
|
||||
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
#pragma mark CADispatchQueue Inline Method Implementations
|
||||
//==================================================================================================
|
||||
|
||||
inline dispatch_queue_t CADispatchQueue::GetDispatchQueue() const
|
||||
{
|
||||
return mDispatchQueue;
|
||||
}
|
||||
|
||||
inline CADispatchQueue::EventSource::EventSource()
|
||||
:
|
||||
mDispatchSource(NULL),
|
||||
mMachPort(MACH_PORT_NULL)
|
||||
{
|
||||
}
|
||||
|
||||
inline CADispatchQueue::EventSource::EventSource(dispatch_source_t inDispatchSource, mach_port_t inMachPort)
|
||||
:
|
||||
mDispatchSource(inDispatchSource),
|
||||
mMachPort(inMachPort)
|
||||
{
|
||||
}
|
||||
|
||||
inline CADispatchQueue::EventSource::EventSource(const EventSource& inEventSource)
|
||||
:
|
||||
mDispatchSource(inEventSource.mDispatchSource),
|
||||
mMachPort(inEventSource.mMachPort)
|
||||
{
|
||||
Retain();
|
||||
}
|
||||
|
||||
inline CADispatchQueue::EventSource& CADispatchQueue::EventSource::operator=(const EventSource& inEventSource)
|
||||
{
|
||||
Release();
|
||||
mDispatchSource = inEventSource.mDispatchSource;
|
||||
mMachPort = inEventSource.mMachPort;
|
||||
Retain();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CADispatchQueue::EventSource::~EventSource()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
inline void CADispatchQueue::EventSource::Retain()
|
||||
{
|
||||
if(mDispatchSource != NULL)
|
||||
{
|
||||
dispatch_retain(mDispatchSource);
|
||||
}
|
||||
}
|
||||
|
||||
inline void CADispatchQueue::EventSource::Release()
|
||||
{
|
||||
if(mDispatchSource != NULL)
|
||||
{
|
||||
dispatch_release(mDispatchSource);
|
||||
mDispatchSource = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __CADispatchQueue_h__
|
||||
83
driver/PublicUtility/CAException.h
Normal file
83
driver/PublicUtility/CAException.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
File: CAException.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CAException_h__)
|
||||
#define __CAException_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#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
|
||||
99
driver/PublicUtility/CAHostTimeBase.cpp
Normal file
99
driver/PublicUtility/CAHostTimeBase.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
File: CAHostTimeBase.cpp
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 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<Float64>(sToNanosDenominator) / static_cast<Float64>(sToNanosNumerator);
|
||||
sFrequency *= 1000000000.0;
|
||||
#elif TARGET_OS_WIN32
|
||||
LARGE_INTEGER theFrequency;
|
||||
QueryPerformanceFrequency(&theFrequency);
|
||||
sMinDelta = 1;
|
||||
sToNanosNumerator = 1000000000ULL;
|
||||
sToNanosDenominator = *((UInt64*)&theFrequency);
|
||||
sFrequency = static_cast<Float64>(*((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
|
||||
}
|
||||
234
driver/PublicUtility/CAHostTimeBase.h
Normal file
234
driver/PublicUtility/CAHostTimeBase.h
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
File: CAHostTimeBase.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CAHostTimeBase_h__)
|
||||
#define __CAHostTimeBase_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <mach/mach_time.h>
|
||||
#include <pthread.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#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<SInt64>(inEndTime - inStartTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
theAnswer = static_cast<SInt64>(inStartTime - inEndTime);
|
||||
theSign = -1;
|
||||
}
|
||||
|
||||
return theSign * static_cast<SInt64>(ConvertToNanos(static_cast<UInt64>(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<UInt64>(theAnswer);
|
||||
}
|
||||
|
||||
#endif
|
||||
345
driver/PublicUtility/CAMutex.cpp
Normal file
345
driver/PublicUtility/CAMutex.cpp
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
File: CAMutex.cpp
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// Self Include
|
||||
#include "CAMutex.h"
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <errno.h>
|
||||
#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();
|
||||
}
|
||||
}
|
||||
164
driver/PublicUtility/CAMutex.h
Normal file
164
driver/PublicUtility/CAMutex.h
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
File: CAMutex.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#ifndef __CAMutex_h__
|
||||
#define __CAMutex_h__
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// System Includes
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <pthread.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#error Unsupported operating system
|
||||
#endif
|
||||
|
||||
//==================================================================================================
|
||||
// A recursive mutex.
|
||||
//==================================================================================================
|
||||
|
||||
class CAMutex
|
||||
{
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAMutex(const char* inName);
|
||||
virtual ~CAMutex();
|
||||
|
||||
// Actions
|
||||
public:
|
||||
virtual bool Lock();
|
||||
virtual void Unlock();
|
||||
virtual bool Try(bool& outWasLocked); // 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 Locker
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
Locker(CAMutex& inMutex) : mMutex(&inMutex), mNeedsRelease(false) { mNeedsRelease = mMutex->Lock(); }
|
||||
Locker(const CAMutex& inMutex) : mMutex(const_cast<CAMutex*>(&inMutex)), mNeedsRelease(false) { mNeedsRelease = mMutex->Lock(); }
|
||||
Locker(CAMutex* inMutex) : mMutex(inMutex), mNeedsRelease(false) { mNeedsRelease = (mMutex != NULL && mMutex->Lock()); }
|
||||
// in this case the mutex can be null
|
||||
~Locker() { if(mNeedsRelease) { mMutex->Unlock(); } }
|
||||
|
||||
|
||||
private:
|
||||
Locker(const Locker&);
|
||||
Locker& operator=(const Locker&);
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
CAMutex* mMutex;
|
||||
bool mNeedsRelease;
|
||||
|
||||
};
|
||||
|
||||
// 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 Tryer {
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
Tryer (CAMutex &mutex) : mMutex(mutex), mNeedsRelease(false), mHasLock(false) { mHasLock = mMutex.Try (mNeedsRelease); }
|
||||
~Tryer () { 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__
|
||||
450
driver/PublicUtility/CAPThread.cpp
Normal file
450
driver/PublicUtility/CAPThread.cpp
Normal file
@@ -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 <mach/mach.h>
|
||||
#endif
|
||||
|
||||
// Standard Library Includes
|
||||
#include <stdio.h>
|
||||
|
||||
//==================================================================================================
|
||||
// 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<integer_t>(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<UInt32>(thePolicyInfo.ts.cur_priority);
|
||||
}
|
||||
return static_cast<UInt32>(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<UInt32>(thePolicyInfo.fifo.depress_priority);
|
||||
}
|
||||
return static_cast<UInt32>(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<UInt32>(thePolicyInfo.rr.depress_priority);
|
||||
}
|
||||
return static_cast<UInt32>(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<UInt32>(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=<time constraint>, spawning pri=%d, scheduled pri=%d\n", label, this,
|
||||
(int)mSpawningThreadPriority, (mPThread != NULL) ? (int)GetScheduledPriority() : -1);
|
||||
else
|
||||
printf("CAPThread::%s %p: pri=%d%s, spawning pri=%d, scheduled pri=%d\n", label, this, (int)mPriority, mFixedPriority ? " fixed" : "",
|
||||
(int)mSpawningThreadPriority, (mPThread != NULL) ? (int)GetScheduledPriority() : -1);
|
||||
#else
|
||||
if (mTimeConstraintSet)
|
||||
{
|
||||
printf("CAPThread::%s %p: pri=<time constraint>, spawning pri=%d, scheduled pri=%d\n", label, this,
|
||||
(int)mPriority, (mThreadHandle != NULL) ? (int)GetScheduledPriority() : -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CAPThread::%s %p: pri=%d%s, spawning pri=%d, scheduled pri=%d\n", label, this, (int)mPriority, mFixedPriority ? " fixed" : "",
|
||||
(int)mPriority, (mThreadHandle != NULL) ? (int)GetScheduledPriority() : -1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
191
driver/PublicUtility/CAPThread.h
Normal file
191
driver/PublicUtility/CAPThread.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
File: CAPThread.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(__CAPThread_h__)
|
||||
#define __CAPThread_h__
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// System Includes
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#else
|
||||
#include <CFBase.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#error Unsupported operating system
|
||||
#endif
|
||||
|
||||
//==================================================================================================
|
||||
// CAPThread
|
||||
//
|
||||
// This class wraps a pthread and a Win32 thread.
|
||||
// caution: long-running fixed priority threads can make the system unresponsive
|
||||
//==================================================================================================
|
||||
|
||||
class CAPThread
|
||||
{
|
||||
|
||||
// Types
|
||||
public:
|
||||
typedef void* (*ThreadRoutine)(void* inParameter);
|
||||
|
||||
// Constants
|
||||
public:
|
||||
enum
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
kMinThreadPriority = 1,
|
||||
kMaxThreadPriority = 63,
|
||||
kDefaultThreadPriority = 31,
|
||||
kMaxThreadNameLength = 64
|
||||
#elif TARGET_OS_WIN32
|
||||
kMinThreadPriority = 1,
|
||||
kMaxThreadPriority = 31,
|
||||
kDefaultThreadPriority = THREAD_PRIORITY_NORMAL,
|
||||
kMaxThreadNameLength = 256
|
||||
#endif
|
||||
};
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPriority = kDefaultThreadPriority, bool inFixedPriority=false, bool inAutoDelete=false, const char* inThreadName = NULL);
|
||||
CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible, bool inAutoDelete=false, const char* inThreadName = NULL);
|
||||
virtual ~CAPThread();
|
||||
|
||||
// Properties
|
||||
public:
|
||||
#if TARGET_OS_MAC
|
||||
typedef pthread_t NativeThread;
|
||||
|
||||
NativeThread GetNativeThread() { return mPThread; }
|
||||
static NativeThread GetCurrentThread() { return pthread_self(); }
|
||||
static bool IsNativeThreadsEqual(NativeThread a, NativeThread b) { return (a==b); }
|
||||
|
||||
bool operator==(NativeThread b) { return pthread_equal(mPThread,b); }
|
||||
|
||||
pthread_t GetPThread() const { return mPThread; }
|
||||
bool IsCurrentThread() const { return (0 != mPThread) && (pthread_self() == mPThread); }
|
||||
bool IsRunning() const { return 0 != mPThread; }
|
||||
static UInt32 getScheduledPriority(pthread_t inThread, int inPriorityKind);
|
||||
#elif TARGET_OS_WIN32
|
||||
typedef unsigned long NativeThread;
|
||||
|
||||
NativeThread GetNativeThread() { return mThreadID; }
|
||||
static NativeThread GetCurrentThread() { return GetCurrentThreadId(); }
|
||||
static bool IsNativeThreadsEqual(NativeThread a, NativeThread b) { return (a==b); }
|
||||
|
||||
bool operator ==(NativeThread b) { return (mThreadID==b); }
|
||||
|
||||
HANDLE GetThreadHandle() const { return mThreadHandle; }
|
||||
UInt32 GetThreadID() const { return mThreadID; }
|
||||
bool IsCurrentThread() const { return (0 != mThreadID) && (GetCurrentThreadId() == mThreadID); }
|
||||
bool IsRunning() const { return 0 != mThreadID; }
|
||||
#endif
|
||||
|
||||
bool IsTimeShareThread() const { return !mTimeConstraintSet; }
|
||||
bool IsTimeConstraintThread() const { return mTimeConstraintSet; }
|
||||
|
||||
UInt32 GetPriority() const { return mPriority; }
|
||||
UInt32 GetScheduledPriority();
|
||||
static UInt32 GetScheduledPriority(NativeThread thread);
|
||||
void SetPriority(UInt32 inPriority, bool inFixedPriority=false);
|
||||
static void SetPriority(NativeThread inThread, UInt32 inPriority, bool inFixedPriority = false);
|
||||
|
||||
void GetTimeConstraints(UInt32& outPeriod, UInt32& outComputation, UInt32& outConstraint, bool& outIsPreemptible) const { outPeriod = mPeriod; outComputation = mComputation; outConstraint = mConstraint; outIsPreemptible = mIsPreemptible; }
|
||||
void SetTimeConstraints(UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible);
|
||||
void ClearTimeConstraints() { SetPriority(mPriority); }
|
||||
|
||||
bool WillAutoDelete() const { return mAutoDelete; }
|
||||
void SetAutoDelete(bool b) { mAutoDelete = b; }
|
||||
|
||||
void SetName(const char* inThreadName);
|
||||
|
||||
#if CoreAudio_Debug
|
||||
void DebugPriority(const char *label);
|
||||
#endif
|
||||
|
||||
// Actions
|
||||
public:
|
||||
virtual void Start();
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
#if TARGET_OS_MAC
|
||||
static void* Entry(CAPThread* inCAPThread);
|
||||
#elif TARGET_OS_WIN32
|
||||
static UInt32 WINAPI Entry(CAPThread* inCAPThread);
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
pthread_t mPThread;
|
||||
UInt32 mSpawningThreadPriority;
|
||||
#elif TARGET_OS_WIN32
|
||||
HANDLE mThreadHandle;
|
||||
unsigned long mThreadID;
|
||||
#endif
|
||||
ThreadRoutine mThreadRoutine;
|
||||
void* mThreadParameter;
|
||||
char mThreadName[kMaxThreadNameLength];
|
||||
UInt32 mPriority;
|
||||
UInt32 mPeriod;
|
||||
UInt32 mComputation;
|
||||
UInt32 mConstraint;
|
||||
bool mIsPreemptible;
|
||||
bool mTimeConstraintSet;
|
||||
bool mFixedPriority;
|
||||
bool mAutoDelete; // delete self when thread terminates
|
||||
};
|
||||
|
||||
#endif
|
||||
321
driver/PublicUtility/CAPropertyAddress.h
Normal file
321
driver/PublicUtility/CAPropertyAddress.h
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
File: CAPropertyAddress.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(__CAPropertyAddress_h__)
|
||||
#define __CAPropertyAddress_h__
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
|
||||
// System Includes
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
|
||||
// Standard Library Includes
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
//==================================================================================================
|
||||
// CAPropertyAddress
|
||||
//
|
||||
// CAPropertyAddress extends the AudioObjectPropertyAddress structure to C++ including constructors
|
||||
// and other utility operations. Note that there is no defined operator< or operator== because the
|
||||
// presence of wildcards for the fields make comparisons ambiguous without specifying whether or
|
||||
// not to take the wildcards into account. Consequently, if you want to use this struct in an STL
|
||||
// data structure, you'll need to specify the approriate function object explicitly in the template
|
||||
// declaration.
|
||||
//==================================================================================================
|
||||
|
||||
struct CAPropertyAddress
|
||||
:
|
||||
public AudioObjectPropertyAddress
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAPropertyAddress() : AudioObjectPropertyAddress() { mSelector = 0; mScope = kAudioObjectPropertyScopeGlobal; mElement = kAudioObjectPropertyElementMaster; }
|
||||
CAPropertyAddress(AudioObjectPropertySelector inSelector) : AudioObjectPropertyAddress() { mSelector = inSelector; mScope = kAudioObjectPropertyScopeGlobal; mElement = kAudioObjectPropertyElementMaster; }
|
||||
CAPropertyAddress(AudioObjectPropertySelector inSelector, AudioObjectPropertyScope inScope) : AudioObjectPropertyAddress() { mSelector = inSelector; mScope = inScope; mElement = kAudioObjectPropertyElementMaster; }
|
||||
CAPropertyAddress(AudioObjectPropertySelector inSelector, AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) : AudioObjectPropertyAddress() { mSelector = inSelector; mScope = inScope; mElement = inElement; }
|
||||
CAPropertyAddress(const AudioObjectPropertyAddress& inAddress) : AudioObjectPropertyAddress(inAddress){}
|
||||
CAPropertyAddress(const CAPropertyAddress& inAddress) : AudioObjectPropertyAddress(inAddress){}
|
||||
CAPropertyAddress& operator=(const AudioObjectPropertyAddress& inAddress) { AudioObjectPropertyAddress::operator=(inAddress); return *this; }
|
||||
CAPropertyAddress& operator=(const CAPropertyAddress& inAddress) { AudioObjectPropertyAddress::operator=(inAddress); return *this; }
|
||||
|
||||
// Operations
|
||||
public:
|
||||
static bool IsSameAddress(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) { return (inAddress1.mScope == inAddress2.mScope) && (inAddress1.mSelector == inAddress2.mSelector) && (inAddress1.mElement == inAddress2.mElement); }
|
||||
static bool IsLessThanAddress(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) { bool theAnswer = false; if(inAddress1.mScope != inAddress2.mScope) { theAnswer = inAddress1.mScope < inAddress2.mScope; } else if(inAddress1.mSelector != inAddress2.mSelector) { theAnswer = inAddress1.mSelector < inAddress2.mSelector; } else { theAnswer = inAddress1.mElement < inAddress2.mElement; } return theAnswer; }
|
||||
static bool IsCongruentSelector(AudioObjectPropertySelector inSelector1, AudioObjectPropertySelector inSelector2) { return (inSelector1 == inSelector2) || (inSelector1 == kAudioObjectPropertySelectorWildcard) || (inSelector2 == kAudioObjectPropertySelectorWildcard); }
|
||||
static bool IsCongruentScope(AudioObjectPropertyScope inScope1, AudioObjectPropertyScope inScope2) { return (inScope1 == inScope2) || (inScope1 == kAudioObjectPropertyScopeWildcard) || (inScope2 == kAudioObjectPropertyScopeWildcard); }
|
||||
static bool IsCongruentElement(AudioObjectPropertyElement inElement1, AudioObjectPropertyElement inElement2) { return (inElement1 == inElement2) || (inElement1 == kAudioObjectPropertyElementWildcard) || (inElement2 == kAudioObjectPropertyElementWildcard); }
|
||||
static bool IsCongruentAddress(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) { return IsCongruentScope(inAddress1.mScope, inAddress2.mScope) && IsCongruentSelector(inAddress1.mSelector, inAddress2.mSelector) && IsCongruentElement(inAddress1.mElement, inAddress2.mElement); }
|
||||
static bool IsCongruentLessThanAddress(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) { bool theAnswer = false; if(!IsCongruentScope(inAddress1.mScope, inAddress2.mScope)) { theAnswer = inAddress1.mScope < inAddress2.mScope; } else if(!IsCongruentSelector(inAddress1.mSelector, inAddress2.mSelector)) { theAnswer = inAddress1.mSelector < inAddress2.mSelector; } else if(!IsCongruentElement(inAddress1.mElement, inAddress2.mElement)) { theAnswer = inAddress1.mElement < inAddress2.mElement; } return theAnswer; }
|
||||
|
||||
// STL Helpers
|
||||
public:
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
struct EqualTo : public std::binary_function<AudioObjectPropertyAddress, AudioObjectPropertyAddress, bool>
|
||||
{
|
||||
bool operator()(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) const { return IsSameAddress(inAddress1, inAddress2); }
|
||||
};
|
||||
|
||||
struct LessThan : public std::binary_function<AudioObjectPropertyAddress, AudioObjectPropertyAddress, bool>
|
||||
{
|
||||
bool operator()(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) const { return IsLessThanAddress(inAddress1, inAddress2); }
|
||||
};
|
||||
|
||||
struct CongruentEqualTo : public std::binary_function<AudioObjectPropertyAddress, AudioObjectPropertyAddress, bool>
|
||||
{
|
||||
bool operator()(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) const { return IsCongruentAddress(inAddress1, inAddress2); }
|
||||
};
|
||||
|
||||
struct CongruentLessThan : public std::binary_function<AudioObjectPropertyAddress, AudioObjectPropertyAddress, bool>
|
||||
{
|
||||
bool operator()(const AudioObjectPropertyAddress& inAddress1, const AudioObjectPropertyAddress& inAddress2) const { return IsCongruentLessThanAddress(inAddress1, inAddress2); }
|
||||
};
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
// CAPropertyAddressList
|
||||
//
|
||||
// An auto-resizing array of CAPropertyAddress structures.
|
||||
//==================================================================================================
|
||||
|
||||
class CAPropertyAddressList
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAPropertyAddressList() : mAddressList(), mToken(NULL) {}
|
||||
explicit CAPropertyAddressList(void* inToken) : mAddressList(), mToken(inToken) {}
|
||||
explicit CAPropertyAddressList(uintptr_t inToken) : mAddressList(), mToken(reinterpret_cast<void*>(inToken)) {}
|
||||
CAPropertyAddressList(const CAPropertyAddressList& inAddressList) : mAddressList(inAddressList.mAddressList), mToken(inAddressList.mToken) {}
|
||||
CAPropertyAddressList& operator=(const CAPropertyAddressList& inAddressList) { mAddressList = inAddressList.mAddressList; mToken = inAddressList.mToken; return *this; }
|
||||
~CAPropertyAddressList() {}
|
||||
|
||||
// Operations
|
||||
public:
|
||||
void* GetToken() const { return mToken; }
|
||||
void SetToken(void* inToken) { mToken = inToken; }
|
||||
|
||||
uintptr_t GetIntToken() const { return reinterpret_cast<uintptr_t>(mToken); }
|
||||
void SetIntToken(uintptr_t inToken) { mToken = reinterpret_cast<void*>(inToken); }
|
||||
|
||||
AudioObjectID GetAudioObjectIDToken() const { return static_cast<AudioObjectID>(reinterpret_cast<uintptr_t>(mToken)); }
|
||||
|
||||
bool IsEmpty() const { return mAddressList.empty(); }
|
||||
UInt32 GetNumberItems() const { return ToUInt32(mAddressList.size()); }
|
||||
void GetItemByIndex(UInt32 inIndex, AudioObjectPropertyAddress& outAddress) const { if(inIndex < mAddressList.size()) { outAddress = mAddressList.at(inIndex); } }
|
||||
const AudioObjectPropertyAddress* GetItems() const { return &(*mAddressList.begin()); }
|
||||
AudioObjectPropertyAddress* GetItems() { return &(*mAddressList.begin()); }
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
bool HasItem(const AudioObjectPropertyAddress& inAddress) const { AddressList::const_iterator theIterator = std::find_if(mAddressList.begin(), mAddressList.end(), std::bind1st(CAPropertyAddress::CongruentEqualTo(), inAddress)); return theIterator != mAddressList.end(); }
|
||||
bool HasExactItem(const AudioObjectPropertyAddress& inAddress) const { AddressList::const_iterator theIterator = std::find_if(mAddressList.begin(), mAddressList.end(), std::bind1st(CAPropertyAddress::EqualTo(), inAddress)); return theIterator != mAddressList.end(); }
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
void AppendItem(const AudioObjectPropertyAddress& inAddress) { mAddressList.push_back(inAddress); }
|
||||
void AppendUniqueItem(const AudioObjectPropertyAddress& inAddress) { if(!HasItem(inAddress)) { mAddressList.push_back(inAddress); } }
|
||||
void AppendUniqueExactItem(const AudioObjectPropertyAddress& inAddress) { if(!HasExactItem(inAddress)) { mAddressList.push_back(inAddress); } }
|
||||
void InsertItemAtIndex(UInt32 inIndex, const AudioObjectPropertyAddress& inAddress) { if(inIndex < mAddressList.size()) { AddressList::iterator theIterator = mAddressList.begin(); std::advance(theIterator, static_cast<int>(inIndex)); mAddressList.insert(theIterator, inAddress); } else { mAddressList.push_back(inAddress); } }
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
void EraseExactItem(const AudioObjectPropertyAddress& inAddress) { AddressList::iterator theIterator = std::find_if(mAddressList.begin(), mAddressList.end(), std::bind1st(CAPropertyAddress::EqualTo(), inAddress)); if(theIterator != mAddressList.end()) { mAddressList.erase(theIterator); } }
|
||||
#pragma clang diagnostic pop
|
||||
void EraseItemAtIndex(UInt32 inIndex) { if(inIndex < mAddressList.size()) { AddressList::iterator theIterator = mAddressList.begin(); std::advance(theIterator, static_cast<int>(inIndex)); mAddressList.erase(theIterator); } }
|
||||
void EraseAllItems() { mAddressList.clear(); }
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
typedef std::vector<CAPropertyAddress> AddressList;
|
||||
|
||||
AddressList mAddressList;
|
||||
void* mToken;
|
||||
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
// CAPropertyAddressListVector
|
||||
//
|
||||
// An auto-resizing array of CAPropertyAddressList objects.
|
||||
//==================================================================================================
|
||||
|
||||
class CAPropertyAddressListVector
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAPropertyAddressListVector() : mAddressListVector() {}
|
||||
CAPropertyAddressListVector(const CAPropertyAddressListVector& inAddressListVector) : mAddressListVector(inAddressListVector.mAddressListVector) {}
|
||||
CAPropertyAddressListVector& operator=(const CAPropertyAddressListVector& inAddressListVector) { mAddressListVector = inAddressListVector.mAddressListVector; return *this; }
|
||||
~CAPropertyAddressListVector() {}
|
||||
|
||||
// Operations
|
||||
public:
|
||||
bool IsEmpty() const { return mAddressListVector.empty(); }
|
||||
bool HasAnyNonEmptyItems() const;
|
||||
bool HasAnyItemsWithAddress(const AudioObjectPropertyAddress& inAddress) const;
|
||||
bool HasAnyItemsWithExactAddress(const AudioObjectPropertyAddress& inAddress) const;
|
||||
|
||||
UInt32 GetNumberItems() const { return ToUInt32(mAddressListVector.size()); }
|
||||
const CAPropertyAddressList& GetItemByIndex(UInt32 inIndex) const { return mAddressListVector.at(inIndex); }
|
||||
CAPropertyAddressList& GetItemByIndex(UInt32 inIndex) { return mAddressListVector.at(inIndex); }
|
||||
const CAPropertyAddressList* GetItemByToken(void* inToken) const;
|
||||
CAPropertyAddressList* GetItemByToken(void* inToken);
|
||||
const CAPropertyAddressList* GetItemByIntToken(uintptr_t inToken) const;
|
||||
CAPropertyAddressList* GetItemByIntToken(uintptr_t inToken);
|
||||
|
||||
void AppendItem(const CAPropertyAddressList& inAddressList) { mAddressListVector.push_back(inAddressList); }
|
||||
void EraseAllItems() { mAddressListVector.clear(); }
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
typedef std::vector<CAPropertyAddressList> AddressListVector;
|
||||
|
||||
AddressListVector mAddressListVector;
|
||||
|
||||
};
|
||||
|
||||
inline bool CAPropertyAddressListVector::HasAnyNonEmptyItems() const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !theAnswer && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
theAnswer = !theIterator->IsEmpty();
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline bool CAPropertyAddressListVector::HasAnyItemsWithAddress(const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !theAnswer && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
theAnswer = theIterator->HasItem(inAddress);
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline bool CAPropertyAddressListVector::HasAnyItemsWithExactAddress(const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !theAnswer && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
theAnswer = theIterator->HasExactItem(inAddress);
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline const CAPropertyAddressList* CAPropertyAddressListVector::GetItemByToken(void* inToken) const
|
||||
{
|
||||
const CAPropertyAddressList* theAnswer = NULL;
|
||||
bool wasFound = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !wasFound && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
if(theIterator->GetToken() == inToken)
|
||||
{
|
||||
wasFound = true;
|
||||
theAnswer = &(*theIterator);
|
||||
}
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline CAPropertyAddressList* CAPropertyAddressListVector::GetItemByToken(void* inToken)
|
||||
{
|
||||
CAPropertyAddressList* theAnswer = NULL;
|
||||
bool wasFound = false;
|
||||
for(AddressListVector::iterator theIterator = mAddressListVector.begin(); !wasFound && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
if(theIterator->GetToken() == inToken)
|
||||
{
|
||||
wasFound = true;
|
||||
theAnswer = &(*theIterator);
|
||||
}
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline const CAPropertyAddressList* CAPropertyAddressListVector::GetItemByIntToken(uintptr_t inToken) const
|
||||
{
|
||||
const CAPropertyAddressList* theAnswer = NULL;
|
||||
bool wasFound = false;
|
||||
for(AddressListVector::const_iterator theIterator = mAddressListVector.begin(); !wasFound && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
if(theIterator->GetIntToken() == inToken)
|
||||
{
|
||||
wasFound = true;
|
||||
theAnswer = &(*theIterator);
|
||||
}
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline CAPropertyAddressList* CAPropertyAddressListVector::GetItemByIntToken(uintptr_t inToken)
|
||||
{
|
||||
CAPropertyAddressList* theAnswer = NULL;
|
||||
bool wasFound = false;
|
||||
for(AddressListVector::iterator theIterator = mAddressListVector.begin(); !wasFound && (theIterator != mAddressListVector.end()); ++theIterator)
|
||||
{
|
||||
if(theIterator->GetIntToken() == inToken)
|
||||
{
|
||||
wasFound = true;
|
||||
theAnswer = &(*theIterator);
|
||||
}
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
#endif
|
||||
319
driver/PublicUtility/CARingBuffer.cpp
Normal file
319
driver/PublicUtility/CARingBuffer.cpp
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
File: CARingBuffer.cpp
|
||||
Abstract: CARingBuffer.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 "CARingBuffer.h"
|
||||
#include "CABitOperations.h"
|
||||
#include "CAAutoDisposer.h"
|
||||
#include "CAAtomic.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
CARingBuffer::CARingBuffer() :
|
||||
mBuffers(NULL), mNumberChannels(0), mCapacityFrames(0), mCapacityBytes(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CARingBuffer::~CARingBuffer()
|
||||
{
|
||||
Deallocate();
|
||||
}
|
||||
|
||||
|
||||
void CARingBuffer::Allocate(int nChannels, UInt32 bytesPerFrame, UInt32 capacityFrames)
|
||||
{
|
||||
Deallocate();
|
||||
|
||||
capacityFrames = NextPowerOfTwo(capacityFrames);
|
||||
|
||||
mNumberChannels = nChannels;
|
||||
mBytesPerFrame = bytesPerFrame;
|
||||
mCapacityFrames = capacityFrames;
|
||||
mCapacityFramesMask = capacityFrames - 1;
|
||||
mCapacityBytes = bytesPerFrame * capacityFrames;
|
||||
|
||||
// put everything in one memory allocation, first the pointers, then the deinterleaved channels
|
||||
UInt32 allocSize = (mCapacityBytes + sizeof(Byte *)) * nChannels;
|
||||
Byte *p = (Byte *)CA_malloc(allocSize);
|
||||
memset(p, 0, allocSize);
|
||||
mBuffers = (Byte **)p;
|
||||
p += nChannels * sizeof(Byte *);
|
||||
for (int i = 0; i < nChannels; ++i) {
|
||||
mBuffers[i] = p;
|
||||
p += mCapacityBytes;
|
||||
}
|
||||
|
||||
for (UInt32 i = 0; i<kGeneralRingTimeBoundsQueueSize; ++i)
|
||||
{
|
||||
mTimeBoundsQueue[i].mStartTime = 0;
|
||||
mTimeBoundsQueue[i].mEndTime = 0;
|
||||
mTimeBoundsQueue[i].mUpdateCounter = 0;
|
||||
}
|
||||
mTimeBoundsQueuePtr = 0;
|
||||
}
|
||||
|
||||
void CARingBuffer::Deallocate()
|
||||
{
|
||||
if (mBuffers) {
|
||||
free(mBuffers);
|
||||
mBuffers = NULL;
|
||||
}
|
||||
mNumberChannels = 0;
|
||||
mCapacityBytes = 0;
|
||||
mCapacityFrames = 0;
|
||||
}
|
||||
|
||||
inline void ZeroRange(Byte **buffers, int nchannels, int offset, int nbytes)
|
||||
{
|
||||
while (--nchannels >= 0) {
|
||||
memset(*buffers + offset, 0, nbytes);
|
||||
++buffers;
|
||||
}
|
||||
}
|
||||
|
||||
inline void StoreABL(Byte **buffers, int destOffset, const AudioBufferList *abl, int srcOffset, int nbytes)
|
||||
{
|
||||
int nchannels = abl->mNumberBuffers;
|
||||
const AudioBuffer *src = abl->mBuffers;
|
||||
while (--nchannels >= 0) {
|
||||
if (srcOffset > (int)src->mDataByteSize) continue;
|
||||
memcpy(*buffers + destOffset, (Byte *)src->mData + srcOffset, std::min(nbytes, (int)src->mDataByteSize - srcOffset));
|
||||
++buffers;
|
||||
++src;
|
||||
}
|
||||
}
|
||||
|
||||
inline void FetchABL(AudioBufferList *abl, int destOffset, Byte **buffers, int srcOffset, int nbytes)
|
||||
{
|
||||
int nchannels = abl->mNumberBuffers;
|
||||
AudioBuffer *dest = abl->mBuffers;
|
||||
while (--nchannels >= 0) {
|
||||
if (destOffset > (int)dest->mDataByteSize) continue;
|
||||
memcpy((Byte *)dest->mData + destOffset, *buffers + srcOffset, std::min(nbytes, (int)dest->mDataByteSize - destOffset));
|
||||
++buffers;
|
||||
++dest;
|
||||
}
|
||||
}
|
||||
|
||||
inline void ZeroABL(AudioBufferList *abl, int destOffset, int nbytes)
|
||||
{
|
||||
int nBuffers = abl->mNumberBuffers;
|
||||
AudioBuffer *dest = abl->mBuffers;
|
||||
while (--nBuffers >= 0) {
|
||||
if (destOffset > (int)dest->mDataByteSize) continue;
|
||||
memset((Byte *)dest->mData + destOffset, 0, std::min(nbytes, (int)dest->mDataByteSize - destOffset));
|
||||
++dest;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CARingBufferError CARingBuffer::Store(const AudioBufferList *abl, UInt32 framesToWrite, SampleTime startWrite)
|
||||
{
|
||||
if (framesToWrite == 0)
|
||||
return kCARingBufferError_OK;
|
||||
|
||||
if (framesToWrite > mCapacityFrames)
|
||||
return kCARingBufferError_TooMuch; // too big!
|
||||
|
||||
SampleTime endWrite = startWrite + framesToWrite;
|
||||
|
||||
if (startWrite < EndTime()) {
|
||||
// going backwards, throw everything out
|
||||
SetTimeBounds(startWrite, startWrite);
|
||||
} else if (endWrite - StartTime() <= mCapacityFrames) {
|
||||
// the buffer has not yet wrapped and will not need to
|
||||
} else {
|
||||
// advance the start time past the region we are about to overwrite
|
||||
SampleTime newStart = endWrite - mCapacityFrames; // one buffer of time behind where we're writing
|
||||
SampleTime newEnd = std::max(newStart, EndTime());
|
||||
SetTimeBounds(newStart, newEnd);
|
||||
}
|
||||
|
||||
// write the new frames
|
||||
Byte **buffers = mBuffers;
|
||||
int nchannels = mNumberChannels;
|
||||
int offset0, offset1, nbytes;
|
||||
SampleTime curEnd = EndTime();
|
||||
|
||||
if (startWrite > curEnd) {
|
||||
// we are skipping some samples, so zero the range we are skipping
|
||||
offset0 = FrameOffset(curEnd);
|
||||
offset1 = FrameOffset(startWrite);
|
||||
if (offset0 < offset1)
|
||||
ZeroRange(buffers, nchannels, offset0, offset1 - offset0);
|
||||
else {
|
||||
ZeroRange(buffers, nchannels, offset0, mCapacityBytes - offset0);
|
||||
ZeroRange(buffers, nchannels, 0, offset1);
|
||||
}
|
||||
offset0 = offset1;
|
||||
} else {
|
||||
offset0 = FrameOffset(startWrite);
|
||||
}
|
||||
|
||||
offset1 = FrameOffset(endWrite);
|
||||
if (offset0 < offset1)
|
||||
StoreABL(buffers, offset0, abl, 0, offset1 - offset0);
|
||||
else {
|
||||
nbytes = mCapacityBytes - offset0;
|
||||
StoreABL(buffers, offset0, abl, 0, nbytes);
|
||||
StoreABL(buffers, 0, abl, nbytes, offset1);
|
||||
}
|
||||
|
||||
// now update the end time
|
||||
SetTimeBounds(StartTime(), endWrite);
|
||||
|
||||
return kCARingBufferError_OK; // success
|
||||
}
|
||||
|
||||
void CARingBuffer::SetTimeBounds(SampleTime startTime, SampleTime endTime)
|
||||
{
|
||||
UInt32 nextPtr = mTimeBoundsQueuePtr + 1;
|
||||
UInt32 index = nextPtr & kGeneralRingTimeBoundsQueueMask;
|
||||
|
||||
mTimeBoundsQueue[index].mStartTime = startTime;
|
||||
mTimeBoundsQueue[index].mEndTime = endTime;
|
||||
mTimeBoundsQueue[index].mUpdateCounter = nextPtr;
|
||||
CAAtomicCompareAndSwap32Barrier(mTimeBoundsQueuePtr, mTimeBoundsQueuePtr + 1, (SInt32*)&mTimeBoundsQueuePtr);
|
||||
}
|
||||
|
||||
CARingBufferError CARingBuffer::GetTimeBounds(SampleTime &startTime, SampleTime &endTime)
|
||||
{
|
||||
for (int i=0; i<8; ++i) // fail after a few tries.
|
||||
{
|
||||
UInt32 curPtr = mTimeBoundsQueuePtr;
|
||||
UInt32 index = curPtr & kGeneralRingTimeBoundsQueueMask;
|
||||
CARingBuffer::TimeBounds* bounds = mTimeBoundsQueue + index;
|
||||
|
||||
startTime = bounds->mStartTime;
|
||||
endTime = bounds->mEndTime;
|
||||
UInt32 newPtr = bounds->mUpdateCounter;
|
||||
|
||||
if (newPtr == curPtr)
|
||||
return kCARingBufferError_OK;
|
||||
}
|
||||
return kCARingBufferError_CPUOverload;
|
||||
}
|
||||
|
||||
CARingBufferError CARingBuffer::ClipTimeBounds(SampleTime& startRead, SampleTime& endRead)
|
||||
{
|
||||
SampleTime startTime, endTime;
|
||||
|
||||
CARingBufferError err = GetTimeBounds(startTime, endTime);
|
||||
if (err) return err;
|
||||
|
||||
if (startRead > endTime || endRead < startTime) {
|
||||
endRead = startRead;
|
||||
return kCARingBufferError_OK;
|
||||
}
|
||||
|
||||
startRead = std::max(startRead, startTime);
|
||||
endRead = std::min(endRead, endTime);
|
||||
endRead = std::max(endRead, startRead);
|
||||
|
||||
return kCARingBufferError_OK; // success
|
||||
}
|
||||
|
||||
CARingBufferError CARingBuffer::Fetch(AudioBufferList *abl, UInt32 nFrames, SampleTime startRead)
|
||||
{
|
||||
if (nFrames == 0)
|
||||
return kCARingBufferError_OK;
|
||||
|
||||
startRead = std::max(0LL, startRead);
|
||||
|
||||
SampleTime endRead = startRead + nFrames;
|
||||
|
||||
SampleTime startRead0 = startRead;
|
||||
SampleTime endRead0 = endRead;
|
||||
|
||||
CARingBufferError err = ClipTimeBounds(startRead, endRead);
|
||||
if (err) return err;
|
||||
|
||||
if (startRead == endRead) {
|
||||
ZeroABL(abl, 0, nFrames * mBytesPerFrame);
|
||||
return kCARingBufferError_OK;
|
||||
}
|
||||
|
||||
SInt32 byteSize = (SInt32)((endRead - startRead) * mBytesPerFrame);
|
||||
|
||||
SInt32 destStartByteOffset = std::max((SInt32)0, (SInt32)((startRead - startRead0) * mBytesPerFrame));
|
||||
|
||||
if (destStartByteOffset > 0) {
|
||||
ZeroABL(abl, 0, std::min((SInt32)(nFrames * mBytesPerFrame), destStartByteOffset));
|
||||
}
|
||||
|
||||
SInt32 destEndSize = std::max((SInt32)0, (SInt32)(endRead0 - endRead));
|
||||
if (destEndSize > 0) {
|
||||
ZeroABL(abl, destStartByteOffset + byteSize, destEndSize * mBytesPerFrame);
|
||||
}
|
||||
|
||||
Byte **buffers = mBuffers;
|
||||
int offset0 = FrameOffset(startRead);
|
||||
int offset1 = FrameOffset(endRead);
|
||||
int nbytes;
|
||||
|
||||
if (offset0 < offset1) {
|
||||
nbytes = offset1 - offset0;
|
||||
FetchABL(abl, destStartByteOffset, buffers, offset0, nbytes);
|
||||
} else {
|
||||
nbytes = mCapacityBytes - offset0;
|
||||
FetchABL(abl, destStartByteOffset, buffers, offset0, nbytes);
|
||||
FetchABL(abl, destStartByteOffset + nbytes, buffers, 0, offset1);
|
||||
nbytes += offset1;
|
||||
}
|
||||
|
||||
int nchannels = abl->mNumberBuffers;
|
||||
AudioBuffer *dest = abl->mBuffers;
|
||||
while (--nchannels >= 0)
|
||||
{
|
||||
dest->mDataByteSize = nbytes;
|
||||
dest++;
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
126
driver/PublicUtility/CARingBuffer.h
Normal file
126
driver/PublicUtility/CARingBuffer.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
File: CARingBuffer.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(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef CARingBuffer_Header
|
||||
#define CARingBuffer_Header
|
||||
|
||||
enum {
|
||||
kCARingBufferError_OK = 0,
|
||||
kCARingBufferError_TooMuch = 3, // fetch start time is earlier than buffer start time and fetch end time is later than buffer end time
|
||||
kCARingBufferError_CPUOverload = 4 // the reader is unable to get enough CPU cycles to capture a consistent snapshot of the time bounds
|
||||
};
|
||||
|
||||
typedef SInt32 CARingBufferError;
|
||||
|
||||
const UInt32 kGeneralRingTimeBoundsQueueSize = 32;
|
||||
const UInt32 kGeneralRingTimeBoundsQueueMask = kGeneralRingTimeBoundsQueueSize - 1;
|
||||
|
||||
class CARingBuffer {
|
||||
public:
|
||||
typedef SInt64 SampleTime;
|
||||
|
||||
CARingBuffer();
|
||||
~CARingBuffer();
|
||||
|
||||
void Allocate(int nChannels, UInt32 bytesPerFrame, UInt32 capacityFrames);
|
||||
// capacityFrames will be rounded up to a power of 2
|
||||
void Deallocate();
|
||||
|
||||
CARingBufferError Store(const AudioBufferList *abl, UInt32 nFrames, SampleTime frameNumber);
|
||||
// Copy nFrames of data into the ring buffer at the specified sample time.
|
||||
// The sample time should normally increase sequentially, though gaps
|
||||
// are filled with zeroes. A sufficiently large gap effectively empties
|
||||
// the buffer before storing the new data.
|
||||
|
||||
// If frameNumber is less than the previous frame number, the behavior is undefined.
|
||||
|
||||
// Return false for failure (buffer not large enough).
|
||||
|
||||
CARingBufferError Fetch(AudioBufferList *abl, UInt32 nFrames, SampleTime frameNumber);
|
||||
// will alter mDataByteSize of the buffers
|
||||
|
||||
CARingBufferError GetTimeBounds(SampleTime &startTime, SampleTime &endTime);
|
||||
|
||||
protected:
|
||||
|
||||
UInt32 FrameOffset(SampleTime frameNumber) { return (frameNumber & mCapacityFramesMask) * mBytesPerFrame; }
|
||||
|
||||
CARingBufferError ClipTimeBounds(SampleTime& startRead, SampleTime& endRead);
|
||||
|
||||
// these should only be called from Store.
|
||||
SampleTime StartTime() const { return mTimeBoundsQueue[mTimeBoundsQueuePtr & kGeneralRingTimeBoundsQueueMask].mStartTime; }
|
||||
SampleTime EndTime() const { return mTimeBoundsQueue[mTimeBoundsQueuePtr & kGeneralRingTimeBoundsQueueMask].mEndTime; }
|
||||
void SetTimeBounds(SampleTime startTime, SampleTime endTime);
|
||||
|
||||
protected:
|
||||
Byte ** mBuffers; // allocated in one chunk of memory
|
||||
int mNumberChannels;
|
||||
UInt32 mBytesPerFrame; // within one deinterleaved channel
|
||||
UInt32 mCapacityFrames; // per channel, must be a power of 2
|
||||
UInt32 mCapacityFramesMask;
|
||||
UInt32 mCapacityBytes; // per channel
|
||||
|
||||
// range of valid sample time in the buffer
|
||||
typedef struct {
|
||||
volatile SampleTime mStartTime;
|
||||
volatile SampleTime mEndTime;
|
||||
volatile UInt32 mUpdateCounter;
|
||||
} TimeBounds;
|
||||
|
||||
CARingBuffer::TimeBounds mTimeBoundsQueue[kGeneralRingTimeBoundsQueueSize];
|
||||
UInt32 mTimeBoundsQueuePtr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
482
driver/PublicUtility/CAVolumeCurve.cpp
Normal file
482
driver/PublicUtility/CAVolumeCurve.cpp
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
File: CAVolumeCurve.cpp
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#include "CAVolumeCurve.h"
|
||||
#include "CADebugMacros.h"
|
||||
#include <math.h>
|
||||
|
||||
//=============================================================================
|
||||
// CAVolumeCurve
|
||||
//=============================================================================
|
||||
|
||||
CAVolumeCurve::CAVolumeCurve()
|
||||
:
|
||||
mTag(0),
|
||||
mCurveMap(),
|
||||
mIsApplyingTransferFunction(true),
|
||||
mTransferFunction(kPow2Over1Curve),
|
||||
mRawToScalarExponentNumerator(2.0f),
|
||||
mRawToScalarExponentDenominator(1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
CAVolumeCurve::~CAVolumeCurve()
|
||||
{
|
||||
}
|
||||
|
||||
SInt32 CAVolumeCurve::GetMinimumRaw() const
|
||||
{
|
||||
SInt32 theAnswer = 0;
|
||||
|
||||
if(!mCurveMap.empty())
|
||||
{
|
||||
CurveMap::const_iterator theIterator = mCurveMap.begin();
|
||||
theAnswer = theIterator->first.mMinimum;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
SInt32 CAVolumeCurve::GetMaximumRaw() const
|
||||
{
|
||||
SInt32 theAnswer = 0;
|
||||
|
||||
if(!mCurveMap.empty())
|
||||
{
|
||||
CurveMap::const_iterator theIterator = mCurveMap.begin();
|
||||
std::advance(theIterator, static_cast<int>(mCurveMap.size() - 1));
|
||||
theAnswer = theIterator->first.mMaximum;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
Float32 CAVolumeCurve::GetMinimumDB() const
|
||||
{
|
||||
Float32 theAnswer = 0;
|
||||
|
||||
if(!mCurveMap.empty())
|
||||
{
|
||||
CurveMap::const_iterator theIterator = mCurveMap.begin();
|
||||
theAnswer = theIterator->second.mMinimum;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
Float32 CAVolumeCurve::GetMaximumDB() const
|
||||
{
|
||||
Float32 theAnswer = 0;
|
||||
|
||||
if(!mCurveMap.empty())
|
||||
{
|
||||
CurveMap::const_iterator theIterator = mCurveMap.begin();
|
||||
std::advance(theIterator, static_cast<int>(mCurveMap.size() - 1));
|
||||
theAnswer = theIterator->second.mMaximum;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CAVolumeCurve::SetTransferFunction(UInt32 inTransferFunction)
|
||||
{
|
||||
mTransferFunction = inTransferFunction;
|
||||
|
||||
// figure out the co-efficients
|
||||
switch(inTransferFunction)
|
||||
{
|
||||
case kLinearCurve:
|
||||
mIsApplyingTransferFunction = false;
|
||||
mRawToScalarExponentNumerator = 1.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow1Over3Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 1.0f;
|
||||
mRawToScalarExponentDenominator = 3.0f;
|
||||
break;
|
||||
|
||||
case kPow1Over2Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 1.0f;
|
||||
mRawToScalarExponentDenominator = 2.0f;
|
||||
break;
|
||||
|
||||
case kPow3Over4Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 3.0f;
|
||||
mRawToScalarExponentDenominator = 4.0f;
|
||||
break;
|
||||
|
||||
case kPow3Over2Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 3.0f;
|
||||
mRawToScalarExponentDenominator = 2.0f;
|
||||
break;
|
||||
|
||||
case kPow2Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 2.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow3Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 3.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow4Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 4.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow5Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 5.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow6Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 6.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow7Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 7.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow8Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 8.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow9Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 9.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow10Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 10.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow11Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 11.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
case kPow12Over1Curve:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 12.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
|
||||
default:
|
||||
mIsApplyingTransferFunction = true;
|
||||
mRawToScalarExponentNumerator = 2.0f;
|
||||
mRawToScalarExponentDenominator = 1.0f;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void CAVolumeCurve::AddRange(SInt32 inMinRaw, SInt32 inMaxRaw, Float32 inMinDB, Float32 inMaxDB)
|
||||
{
|
||||
CARawPoint theRaw(inMinRaw, inMaxRaw);
|
||||
CADBPoint theDB(inMinDB, inMaxDB);
|
||||
|
||||
bool isOverlapped = false;
|
||||
bool isDone = false;
|
||||
CurveMap::iterator theIterator = mCurveMap.begin();
|
||||
while((theIterator != mCurveMap.end()) && !isOverlapped && !isDone)
|
||||
{
|
||||
isOverlapped = CARawPoint::Overlap(theRaw, theIterator->first);
|
||||
isDone = theRaw >= theIterator->first;
|
||||
|
||||
if(!isOverlapped && !isDone)
|
||||
{
|
||||
std::advance(theIterator, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(!isOverlapped)
|
||||
{
|
||||
mCurveMap.insert(CurveMap::value_type(theRaw, theDB));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugMessage("CAVolumeCurve::AddRange: new point overlaps");
|
||||
}
|
||||
}
|
||||
|
||||
void CAVolumeCurve::ResetRange()
|
||||
{
|
||||
mCurveMap.clear();
|
||||
}
|
||||
|
||||
bool CAVolumeCurve::CheckForContinuity() const
|
||||
{
|
||||
bool theAnswer = true;
|
||||
|
||||
CurveMap::const_iterator theIterator = mCurveMap.begin();
|
||||
if(theIterator != mCurveMap.end())
|
||||
{
|
||||
SInt32 theRaw = theIterator->first.mMinimum;
|
||||
Float32 theDB = theIterator->second.mMinimum;
|
||||
do
|
||||
{
|
||||
SInt32 theRawMin = theIterator->first.mMinimum;
|
||||
SInt32 theRawMax = theIterator->first.mMaximum;
|
||||
SInt32 theRawRange = theRawMax - theRawMin;
|
||||
|
||||
Float32 theDBMin = theIterator->second.mMinimum;
|
||||
Float32 theDBMax = theIterator->second.mMaximum;
|
||||
Float32 theDBRange = theDBMax - theDBMin;
|
||||
|
||||
theAnswer = theRaw == theRawMin;
|
||||
theAnswer = theAnswer && (theDB == theDBMin);
|
||||
|
||||
theRaw += theRawRange;
|
||||
theDB += theDBRange;
|
||||
|
||||
std::advance(theIterator, 1);
|
||||
}
|
||||
while((theIterator != mCurveMap.end()) && theAnswer);
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
SInt32 CAVolumeCurve::ConvertDBToRaw(Float32 inDB) const
|
||||
{
|
||||
// clamp the value to the dB range
|
||||
Float32 theOverallDBMin = GetMinimumDB();
|
||||
Float32 theOverallDBMax = GetMaximumDB();
|
||||
|
||||
if(inDB < theOverallDBMin) inDB = theOverallDBMin;
|
||||
if(inDB > theOverallDBMax) inDB = theOverallDBMax;
|
||||
|
||||
// get the first entry in the curve map;
|
||||
CurveMap::const_iterator theIterator = mCurveMap.begin();
|
||||
|
||||
// initialize the answer to the minimum raw of the first item in the curve map
|
||||
SInt32 theAnswer = theIterator->first.mMinimum;
|
||||
|
||||
// iterate through the curve map until we run out of dB
|
||||
bool isDone = false;
|
||||
while(!isDone && (theIterator != mCurveMap.end()))
|
||||
{
|
||||
SInt32 theRawMin = theIterator->first.mMinimum;
|
||||
SInt32 theRawMax = theIterator->first.mMaximum;
|
||||
SInt32 theRawRange = theRawMax - theRawMin;
|
||||
|
||||
Float32 theDBMin = theIterator->second.mMinimum;
|
||||
Float32 theDBMax = theIterator->second.mMaximum;
|
||||
Float32 theDBRange = theDBMax - theDBMin;
|
||||
|
||||
Float32 theDBPerRaw = theDBRange / static_cast<Float32>(theRawRange);
|
||||
|
||||
// figure out how many steps we are into this entry in the curve map
|
||||
if(inDB > theDBMax)
|
||||
{
|
||||
// we're past the end of this one, so add in the whole range for this entry
|
||||
theAnswer += theRawRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's somewhere within the current entry
|
||||
// figure out how many steps it is
|
||||
Float32 theNumberRawSteps = inDB - theDBMin;
|
||||
theNumberRawSteps /= theDBPerRaw;
|
||||
|
||||
// only move in whole steps
|
||||
theNumberRawSteps = roundf(theNumberRawSteps);
|
||||
|
||||
// add this many steps to the answer
|
||||
theAnswer += static_cast<SInt32>(theNumberRawSteps);
|
||||
|
||||
// mark that we are done
|
||||
isDone = true;
|
||||
}
|
||||
|
||||
// go to the next entry in the curve map
|
||||
std::advance(theIterator, 1);
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
Float32 CAVolumeCurve::ConvertRawToDB(SInt32 inRaw) const
|
||||
{
|
||||
Float32 theAnswer = 0;
|
||||
|
||||
// clamp the raw value
|
||||
SInt32 theOverallRawMin = GetMinimumRaw();
|
||||
SInt32 theOverallRawMax = GetMaximumRaw();
|
||||
|
||||
if(inRaw < theOverallRawMin) inRaw = theOverallRawMin;
|
||||
if(inRaw > theOverallRawMax) inRaw = theOverallRawMax;
|
||||
|
||||
// figure out how many raw steps need to be taken from the first one
|
||||
SInt32 theNumberRawSteps = inRaw - theOverallRawMin;
|
||||
|
||||
// get the first item in the curve map
|
||||
CurveMap::const_iterator theIterator = mCurveMap.begin();
|
||||
|
||||
// initialize the answer to the minimum dB of the first item in the curve map
|
||||
theAnswer = theIterator->second.mMinimum;
|
||||
|
||||
// iterate through the curve map until we run out of steps
|
||||
while((theNumberRawSteps > 0) && (theIterator != mCurveMap.end()))
|
||||
{
|
||||
// compute some values
|
||||
SInt32 theRawMin = theIterator->first.mMinimum;
|
||||
SInt32 theRawMax = theIterator->first.mMaximum;
|
||||
SInt32 theRawRange = theRawMax - theRawMin;
|
||||
|
||||
Float32 theDBMin = theIterator->second.mMinimum;
|
||||
Float32 theDBMax = theIterator->second.mMaximum;
|
||||
Float32 theDBRange = theDBMax - theDBMin;
|
||||
|
||||
Float32 theDBPerRaw = theDBRange / static_cast<Float32>(theRawRange);
|
||||
|
||||
// there might be more steps than the current map entry accounts for
|
||||
SInt32 theRawStepsToAdd = std::min(theRawRange, theNumberRawSteps);
|
||||
|
||||
// add this many steps worth of db to the answer;
|
||||
theAnswer += theRawStepsToAdd * theDBPerRaw;
|
||||
|
||||
// figure out how many steps are left
|
||||
theNumberRawSteps -= theRawStepsToAdd;
|
||||
|
||||
// go to the next map entry
|
||||
std::advance(theIterator, 1);
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
Float32 CAVolumeCurve::ConvertRawToScalar(SInt32 inRaw) const
|
||||
{
|
||||
// get some important values
|
||||
Float32 theDBMin = GetMinimumDB();
|
||||
Float32 theDBMax = GetMaximumDB();
|
||||
Float32 theDBRange = theDBMax - theDBMin;
|
||||
SInt32 theRawMin = GetMinimumRaw();
|
||||
SInt32 theRawMax = GetMaximumRaw();
|
||||
SInt32 theRawRange = theRawMax - theRawMin;
|
||||
|
||||
// range the raw value
|
||||
if(inRaw < theRawMin) inRaw = theRawMin;
|
||||
if(inRaw > theRawMax) inRaw = theRawMax;
|
||||
|
||||
// calculate the distance in the range inRaw is
|
||||
Float32 theAnswer = static_cast<Float32>(inRaw - theRawMin) / static_cast<Float32>(theRawRange);
|
||||
|
||||
// only apply a curve to the scalar values if the dB range is greater than 30
|
||||
if(mIsApplyingTransferFunction && (theDBRange > 30.0f))
|
||||
{
|
||||
theAnswer = powf(theAnswer, mRawToScalarExponentNumerator / mRawToScalarExponentDenominator);
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
Float32 CAVolumeCurve::ConvertDBToScalar(Float32 inDB) const
|
||||
{
|
||||
SInt32 theRawValue = ConvertDBToRaw(inDB);
|
||||
Float32 theAnswer = ConvertRawToScalar(theRawValue);
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
SInt32 CAVolumeCurve::ConvertScalarToRaw(Float32 inScalar) const
|
||||
{
|
||||
// range the scalar value
|
||||
inScalar = std::min(1.0f, std::max(0.0f, inScalar));
|
||||
|
||||
// get some important values
|
||||
Float32 theDBMin = GetMinimumDB();
|
||||
Float32 theDBMax = GetMaximumDB();
|
||||
Float32 theDBRange = theDBMax - theDBMin;
|
||||
SInt32 theRawMin = GetMinimumRaw();
|
||||
SInt32 theRawMax = GetMaximumRaw();
|
||||
SInt32 theRawRange = theRawMax - theRawMin;
|
||||
|
||||
// have to undo the curve if the dB range is greater than 30
|
||||
if(mIsApplyingTransferFunction && (theDBRange > 30.0f))
|
||||
{
|
||||
inScalar = powf(inScalar, mRawToScalarExponentDenominator / mRawToScalarExponentNumerator);
|
||||
}
|
||||
|
||||
// now we can figure out how many raw steps this is
|
||||
Float32 theNumberRawSteps = inScalar * static_cast<Float32>(theRawRange);
|
||||
theNumberRawSteps = roundf(theNumberRawSteps);
|
||||
|
||||
// the answer is the minimum raw value plus the number of raw steps
|
||||
SInt32 theAnswer = theRawMin + static_cast<SInt32>(theNumberRawSteps);
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
Float32 CAVolumeCurve::ConvertScalarToDB(Float32 inScalar) const
|
||||
{
|
||||
SInt32 theRawValue = ConvertScalarToRaw(inScalar);
|
||||
Float32 theAnswer = ConvertRawToDB(theRawValue);
|
||||
return theAnswer;
|
||||
}
|
||||
178
driver/PublicUtility/CAVolumeCurve.h
Normal file
178
driver/PublicUtility/CAVolumeCurve.h
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
File: CAVolumeCurve.h
|
||||
Abstract: Part of CoreAudio Utility Classes
|
||||
Version: 1.0.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) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
#if !defined(__CAVolumeCurve_h__)
|
||||
#define __CAVolumeCurve_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
#include <map>
|
||||
|
||||
//=============================================================================
|
||||
// Types
|
||||
//=============================================================================
|
||||
|
||||
struct CARawPoint
|
||||
{
|
||||
SInt32 mMinimum;
|
||||
SInt32 mMaximum;
|
||||
|
||||
CARawPoint() : mMinimum(0), mMaximum(0) {}
|
||||
CARawPoint(const CARawPoint& inPoint) : mMinimum(inPoint.mMinimum), mMaximum(inPoint.mMaximum) {}
|
||||
CARawPoint(SInt32 inMinimum, SInt32 inMaximum) : mMinimum(inMinimum), mMaximum(inMaximum) {}
|
||||
CARawPoint& operator=(const CARawPoint& inPoint) { mMinimum = inPoint.mMinimum; mMaximum = inPoint.mMaximum; return *this; }
|
||||
|
||||
static bool Overlap(const CARawPoint& x, const CARawPoint& y) { return (x.mMinimum < y.mMaximum) && (x.mMaximum > y.mMinimum); }
|
||||
};
|
||||
|
||||
inline bool operator<(const CARawPoint& x, const CARawPoint& y) { return x.mMinimum < y.mMinimum; }
|
||||
inline bool operator==(const CARawPoint& x, const CARawPoint& y) { return (x.mMinimum == y.mMinimum) && (x.mMaximum == y.mMaximum); }
|
||||
inline bool operator!=(const CARawPoint& x, const CARawPoint& y) { return !(x == y); }
|
||||
inline bool operator<=(const CARawPoint& x, const CARawPoint& y) { return (x < y) || (x == y); }
|
||||
inline bool operator>=(const CARawPoint& x, const CARawPoint& y) { return !(x < y); }
|
||||
inline bool operator>(const CARawPoint& x, const CARawPoint& y) { return !((x < y) || (x == y)); }
|
||||
|
||||
struct CADBPoint
|
||||
{
|
||||
Float32 mMinimum;
|
||||
Float32 mMaximum;
|
||||
|
||||
CADBPoint() : mMinimum(0), mMaximum(0) {}
|
||||
CADBPoint(const CADBPoint& inPoint) : mMinimum(inPoint.mMinimum), mMaximum(inPoint.mMaximum) {}
|
||||
CADBPoint(Float32 inMinimum, Float32 inMaximum) : mMinimum(inMinimum), mMaximum(inMaximum) {}
|
||||
CADBPoint& operator=(const CADBPoint& inPoint) { mMinimum = inPoint.mMinimum; mMaximum = inPoint.mMaximum; return *this; }
|
||||
|
||||
static bool Overlap(const CADBPoint& x, const CADBPoint& y) { return (x.mMinimum < y.mMaximum) && (x.mMaximum >= y.mMinimum); }
|
||||
};
|
||||
|
||||
inline bool operator<(const CADBPoint& x, const CADBPoint& y) { return x.mMinimum < y.mMinimum; }
|
||||
inline bool operator==(const CADBPoint& x, const CADBPoint& y) { return (x.mMinimum == y.mMinimum) && (x.mMaximum == y.mMaximum); }
|
||||
inline bool operator!=(const CADBPoint& x, const CADBPoint& y) { return !(x == y); }
|
||||
inline bool operator<=(const CADBPoint& x, const CADBPoint& y) { return (x < y) || (x == y); }
|
||||
inline bool operator>=(const CADBPoint& x, const CADBPoint& y) { return !(x < y); }
|
||||
inline bool operator>(const CADBPoint& x, const CADBPoint& y) { return !((x < y) || (x == y)); }
|
||||
|
||||
//=============================================================================
|
||||
// CAVolumeCurve
|
||||
//=============================================================================
|
||||
|
||||
class CAVolumeCurve
|
||||
{
|
||||
|
||||
// Constants
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kLinearCurve = 0,
|
||||
kPow1Over3Curve = 1,
|
||||
kPow1Over2Curve = 2,
|
||||
kPow3Over4Curve = 3,
|
||||
kPow3Over2Curve = 4,
|
||||
kPow2Over1Curve = 5,
|
||||
kPow3Over1Curve = 6,
|
||||
kPow4Over1Curve = 7,
|
||||
kPow5Over1Curve = 8,
|
||||
kPow6Over1Curve = 9,
|
||||
kPow7Over1Curve = 10,
|
||||
kPow8Over1Curve = 11,
|
||||
kPow9Over1Curve = 12,
|
||||
kPow10Over1Curve = 13,
|
||||
kPow11Over1Curve = 14,
|
||||
kPow12Over1Curve = 15
|
||||
};
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAVolumeCurve();
|
||||
virtual ~CAVolumeCurve();
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
UInt32 GetTag() const { return mTag; }
|
||||
void SetTag(UInt32 inTag) { mTag = inTag; }
|
||||
SInt32 GetMinimumRaw() const;
|
||||
SInt32 GetMaximumRaw() const;
|
||||
Float32 GetMinimumDB() const;
|
||||
Float32 GetMaximumDB() const;
|
||||
|
||||
void SetIsApplyingTransferFunction(bool inIsApplyingTransferFunction) { mIsApplyingTransferFunction = inIsApplyingTransferFunction; }
|
||||
UInt32 GetTransferFunction() const { return mTransferFunction; }
|
||||
void SetTransferFunction(UInt32 inTransferFunction);
|
||||
|
||||
// Operations
|
||||
public:
|
||||
void AddRange(SInt32 mMinRaw, SInt32 mMaxRaw, Float32 inMinDB, Float32 inMaxDB);
|
||||
void ResetRange();
|
||||
bool CheckForContinuity() const;
|
||||
|
||||
SInt32 ConvertDBToRaw(Float32 inDB) const;
|
||||
Float32 ConvertRawToDB(SInt32 inRaw) const;
|
||||
Float32 ConvertRawToScalar(SInt32 inRaw) const;
|
||||
Float32 ConvertDBToScalar(Float32 inDB) const;
|
||||
SInt32 ConvertScalarToRaw(Float32 inScalar) const;
|
||||
Float32 ConvertScalarToDB(Float32 inScalar) const;
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
typedef std::map<CARawPoint, CADBPoint> CurveMap;
|
||||
|
||||
UInt32 mTag;
|
||||
CurveMap mCurveMap;
|
||||
bool mIsApplyingTransferFunction;
|
||||
UInt32 mTransferFunction;
|
||||
Float32 mRawToScalarExponentNumerator;
|
||||
Float32 mRawToScalarExponentDenominator;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
410
driver/VC_AbstractDevice.cpp
Normal file
410
driver/VC_AbstractDevice.cpp
Normal file
@@ -0,0 +1,410 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VC_AbstractDevice.cpp
|
||||
// VCDriver
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "VC_AbstractDevice.h"
|
||||
|
||||
// Local Includes
|
||||
#include "VC_Utils.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CAException.h"
|
||||
#include "CADebugMacros.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
VC_AbstractDevice::VC_AbstractDevice(AudioObjectID inObjectID, AudioObjectID inOwnerObjectID)
|
||||
:
|
||||
VC_Object(inObjectID, kAudioDeviceClassID, kAudioObjectClassID, inOwnerObjectID)
|
||||
{
|
||||
}
|
||||
|
||||
VC_AbstractDevice::~VC_AbstractDevice()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma mark Property Operations
|
||||
|
||||
bool VC_AbstractDevice::HasProperty(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyName:
|
||||
case kAudioObjectPropertyManufacturer:
|
||||
case kAudioDevicePropertyDeviceUID:
|
||||
case kAudioDevicePropertyModelUID:
|
||||
case kAudioDevicePropertyTransportType:
|
||||
case kAudioDevicePropertyRelatedDevices:
|
||||
case kAudioDevicePropertyClockDomain:
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
case kAudioDevicePropertyDeviceIsRunning:
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultDevice:
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
|
||||
case kAudioDevicePropertyLatency:
|
||||
case kAudioDevicePropertyStreams:
|
||||
case kAudioObjectPropertyControlList:
|
||||
case kAudioDevicePropertySafetyOffset:
|
||||
case kAudioDevicePropertyNominalSampleRate:
|
||||
case kAudioDevicePropertyAvailableNominalSampleRates:
|
||||
case kAudioDevicePropertyIsHidden:
|
||||
case kAudioDevicePropertyZeroTimeStampPeriod:
|
||||
theAnswer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Object::HasProperty(inObjectID, inClientPID, inAddress);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
bool VC_AbstractDevice::IsPropertySettable(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
bool theAnswer = false;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyName:
|
||||
case kAudioObjectPropertyManufacturer:
|
||||
case kAudioDevicePropertyDeviceUID:
|
||||
case kAudioDevicePropertyModelUID:
|
||||
case kAudioDevicePropertyTransportType:
|
||||
case kAudioDevicePropertyRelatedDevices:
|
||||
case kAudioDevicePropertyClockDomain:
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
case kAudioDevicePropertyDeviceIsRunning:
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultDevice:
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
|
||||
case kAudioDevicePropertyLatency:
|
||||
case kAudioDevicePropertyStreams:
|
||||
case kAudioObjectPropertyControlList:
|
||||
case kAudioDevicePropertySafetyOffset:
|
||||
case kAudioDevicePropertyNominalSampleRate:
|
||||
case kAudioDevicePropertyAvailableNominalSampleRates:
|
||||
case kAudioDevicePropertyIsHidden:
|
||||
case kAudioDevicePropertyZeroTimeStampPeriod:
|
||||
theAnswer = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Object::IsPropertySettable(inObjectID, inClientPID, inAddress);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
UInt32 VC_AbstractDevice::GetPropertyDataSize(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* __nullable inQualifierData) const
|
||||
{
|
||||
UInt32 theAnswer = 0;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyName:
|
||||
theAnswer = sizeof(CFStringRef);
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyManufacturer:
|
||||
theAnswer = sizeof(CFStringRef);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceUID:
|
||||
theAnswer = sizeof(CFStringRef);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyModelUID:
|
||||
theAnswer = sizeof(CFStringRef);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyTransportType:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyRelatedDevices:
|
||||
theAnswer = sizeof(AudioObjectID);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyClockDomain:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultDevice:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
theAnswer = sizeof(AudioClassID);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceIsRunning:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyLatency:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyStreams:
|
||||
theAnswer = 0;
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyControlList:
|
||||
theAnswer = 0;
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertySafetyOffset:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyNominalSampleRate:
|
||||
theAnswer = sizeof(Float64);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyAvailableNominalSampleRates:
|
||||
theAnswer = 0;
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyIsHidden:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyZeroTimeStampPeriod:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Object::GetPropertyDataSize(inObjectID,
|
||||
inClientPID,
|
||||
inAddress,
|
||||
inQualifierDataSize,
|
||||
inQualifierData);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void VC_AbstractDevice::GetPropertyData(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* __nullable inQualifierData,
|
||||
UInt32 inDataSize,
|
||||
UInt32& outDataSize,
|
||||
void* outData) const
|
||||
{
|
||||
UInt32 theNumberItemsToFetch;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyName:
|
||||
case kAudioObjectPropertyManufacturer:
|
||||
case kAudioDevicePropertyDeviceUID:
|
||||
case kAudioDevicePropertyModelUID:
|
||||
case kAudioDevicePropertyDeviceIsRunning:
|
||||
case kAudioDevicePropertyZeroTimeStampPeriod:
|
||||
case kAudioDevicePropertyNominalSampleRate:
|
||||
case kAudioDevicePropertyAvailableNominalSampleRates:
|
||||
// Should be unreachable. Reaching this point would mean a concrete device has delegated
|
||||
// a required property that can't be handled by this class or its parent, VC_Object.
|
||||
//
|
||||
// See VC_Device for info about these properties.
|
||||
//
|
||||
// TODO: Write a test that checks all required properties for each subclass.
|
||||
VCAssert(false,
|
||||
"VC_AbstractDevice::GetPropertyData: Property %u not handled in subclass",
|
||||
inAddress.mSelector);
|
||||
// Throw in release builds.
|
||||
Throw(CAException(kAudioHardwareIllegalOperationError));
|
||||
|
||||
case kAudioDevicePropertyTransportType:
|
||||
// This value represents how the device is attached to the system. This can be
|
||||
// any 32 bit integer, but common values for this property are defined in
|
||||
// <CoreAudio/AudioHardwareBase.h>.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyTransportType for the device");
|
||||
// Default to virtual device.
|
||||
*reinterpret_cast<UInt32*>(outData) = kAudioDeviceTransportTypeVirtual;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyRelatedDevices:
|
||||
// The related devices property identifies device objects that are very closely
|
||||
// related. Generally, this is for relating devices that are packaged together
|
||||
// in the hardware such as when the input side and the output side of a piece
|
||||
// of hardware can be clocked separately and therefore need to be represented
|
||||
// as separate AudioDevice objects. In such case, both devices would report
|
||||
// that they are related to each other. Note that at minimum, a device is
|
||||
// related to itself, so this list will always be at least one item long.
|
||||
|
||||
// Calculate the number of items that have been requested. Note that this
|
||||
// number is allowed to be smaller than the actual size of the list. In such
|
||||
// case, only that number of items will be returned
|
||||
theNumberItemsToFetch = inDataSize / sizeof(AudioObjectID);
|
||||
|
||||
// Default to only have the one device.
|
||||
if(theNumberItemsToFetch > 1)
|
||||
{
|
||||
theNumberItemsToFetch = 1;
|
||||
}
|
||||
|
||||
// Write the devices' object IDs into the return value.
|
||||
if(theNumberItemsToFetch > 0)
|
||||
{
|
||||
reinterpret_cast<AudioObjectID*>(outData)[0] = GetObjectID();
|
||||
}
|
||||
|
||||
// Report how much we wrote.
|
||||
outDataSize = theNumberItemsToFetch * sizeof(AudioObjectID);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyClockDomain:
|
||||
// This property allows the device to declare what other devices it is
|
||||
// synchronized with in hardware. The way it works is that if two devices have
|
||||
// the same value for this property and the value is not zero, then the two
|
||||
// devices are synchronized in hardware. Note that a device that either can't
|
||||
// be synchronized with others or doesn't know should return 0 for this
|
||||
// property.
|
||||
//
|
||||
// Default to 0.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyClockDomain for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 0;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
// Default to alive.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyDeviceIsAlive for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 1;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultDevice:
|
||||
// This property returns whether or not the device wants to be able to be the
|
||||
// default device for content. This is the device that iTunes and QuickTime
|
||||
// will use to play their content on and FaceTime will use as it's microphone.
|
||||
// Nearly all devices should allow for this.
|
||||
//
|
||||
// Default to true.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyDeviceCanBeDefaultDevice for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 1;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
|
||||
// This property returns whether or not the device wants to be the system
|
||||
// default device. This is the device that is used to play interface sounds and
|
||||
// other incidental or UI-related sounds on. Most devices should allow this
|
||||
// although devices with lots of latency may not want to.
|
||||
//
|
||||
// Default to true.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyDeviceCanBeDefaultSystemDevice for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 1;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyLatency:
|
||||
// This property returns the presentation latency of the device. Default to 0.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyLatency for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 0;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyStreams:
|
||||
// Default to not having any streams.
|
||||
outDataSize = 0;
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyControlList:
|
||||
// Default to not having any controls.
|
||||
outDataSize = 0;
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertySafetyOffset:
|
||||
// This property returns the how close to now the HAL can read and write. Default to 0.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertySafetyOffset for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 0;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
case kAudioDevicePropertyIsHidden:
|
||||
// This returns whether or not the device is visible to clients. Default to not hidden.
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_AbstractDevice::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioDevicePropertyIsHidden for the device");
|
||||
*reinterpret_cast<UInt32*>(outData) = 0;
|
||||
outDataSize = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
default:
|
||||
VC_Object::GetPropertyData(inObjectID,
|
||||
inClientPID,
|
||||
inAddress,
|
||||
inQualifierDataSize,
|
||||
inQualifierData,
|
||||
inDataSize,
|
||||
outDataSize,
|
||||
outData);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
111
driver/VC_AbstractDevice.h
Normal file
111
driver/VC_AbstractDevice.h
Normal file
@@ -0,0 +1,111 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VC_AbstractDevice.h
|
||||
// VCDriver
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
//
|
||||
|
||||
#ifndef VC_Driver__VC_AbstractDevice
|
||||
#define VC_Driver__VC_AbstractDevice
|
||||
|
||||
// SuperClass Includes
|
||||
#include "VC_Object.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
class VC_AbstractDevice
|
||||
:
|
||||
public VC_Object
|
||||
{
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
protected:
|
||||
VC_AbstractDevice(AudioObjectID inObjectID,
|
||||
AudioObjectID inOwnerObjectID);
|
||||
virtual ~VC_AbstractDevice();
|
||||
|
||||
#pragma mark Property Operations
|
||||
|
||||
public:
|
||||
virtual bool HasProperty(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const;
|
||||
virtual bool IsPropertySettable(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const;
|
||||
virtual UInt32 GetPropertyDataSize(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* __nullable inQualifierData) const;
|
||||
virtual void GetPropertyData(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* __nullable inQualifierData,
|
||||
UInt32 inDataSize,
|
||||
UInt32& outDataSize,
|
||||
void* outData) const;
|
||||
|
||||
#pragma mark IO Operations
|
||||
|
||||
public:
|
||||
virtual void StartIO(UInt32 inClientID) = 0;
|
||||
virtual void StopIO(UInt32 inClientID) = 0;
|
||||
|
||||
virtual void GetZeroTimeStamp(Float64& outSampleTime,
|
||||
UInt64& outHostTime,
|
||||
UInt64& outSeed) = 0;
|
||||
|
||||
virtual void WillDoIOOperation(UInt32 inOperationID,
|
||||
bool& outWillDo,
|
||||
bool& outWillDoInPlace) const = 0;
|
||||
virtual void BeginIOOperation(UInt32 inOperationID,
|
||||
UInt32 inIOBufferFrameSize,
|
||||
const AudioServerPlugInIOCycleInfo& inIOCycleInfo,
|
||||
UInt32 inClientID) = 0;
|
||||
virtual void DoIOOperation(AudioObjectID inStreamObjectID,
|
||||
UInt32 inClientID, UInt32 inOperationID,
|
||||
UInt32 inIOBufferFrameSize,
|
||||
const AudioServerPlugInIOCycleInfo& inIOCycleInfo,
|
||||
void* ioMainBuffer,
|
||||
void* __nullable ioSecondaryBuffer) = 0;
|
||||
virtual void EndIOOperation(UInt32 inOperationID,
|
||||
UInt32 inIOBufferFrameSize,
|
||||
const AudioServerPlugInIOCycleInfo& inIOCycleInfo,
|
||||
UInt32 inClientID) = 0;
|
||||
|
||||
#pragma mark Implementation
|
||||
|
||||
public:
|
||||
virtual CFStringRef CopyDeviceUID() const = 0;
|
||||
virtual void AddClient(const AudioServerPlugInClientInfo* inClientInfo) = 0;
|
||||
virtual void RemoveClient(const AudioServerPlugInClientInfo* inClientInfo) = 0;
|
||||
virtual void PerformConfigChange(UInt64 inChangeAction,
|
||||
void* __nullable inChangeInfo) = 0;
|
||||
virtual void AbortConfigChange(UInt64 inChangeAction,
|
||||
void* __nullable inChangeInfo) = 0;
|
||||
|
||||
};
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* VC_Driver__VC_AbstractDevice */
|
||||
|
||||
182
driver/VC_Control.cpp
Normal file
182
driver/VC_Control.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VC_Control.cpp
|
||||
// VCDriver
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "VC_Control.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAException.h"
|
||||
|
||||
// System Includes
|
||||
#include <CoreAudio/AudioHardwareBase.h>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
VC_Control::VC_Control(AudioObjectID inObjectID,
|
||||
AudioClassID inClassID,
|
||||
AudioClassID inBaseClassID,
|
||||
AudioObjectID inOwnerObjectID,
|
||||
AudioObjectPropertyScope inScope,
|
||||
AudioObjectPropertyElement inElement)
|
||||
:
|
||||
VC_Object(inObjectID, inClassID, inBaseClassID, inOwnerObjectID),
|
||||
mScope(inScope),
|
||||
mElement(inElement)
|
||||
{
|
||||
}
|
||||
|
||||
bool VC_Control::HasProperty(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
CheckObjectID(inObjectID);
|
||||
|
||||
bool theAnswer = false;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioControlPropertyScope:
|
||||
case kAudioControlPropertyElement:
|
||||
theAnswer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Object::HasProperty(inObjectID, inClientPID, inAddress);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
bool VC_Control::IsPropertySettable(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
CheckObjectID(inObjectID);
|
||||
|
||||
bool theAnswer = false;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioControlPropertyScope:
|
||||
case kAudioControlPropertyElement:
|
||||
theAnswer = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Object::IsPropertySettable(inObjectID, inClientPID, inAddress);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
UInt32 VC_Control::GetPropertyDataSize(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData) const
|
||||
{
|
||||
CheckObjectID(inObjectID);
|
||||
|
||||
UInt32 theAnswer = 0;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioControlPropertyScope:
|
||||
theAnswer = sizeof(AudioObjectPropertyScope);
|
||||
break;
|
||||
|
||||
case kAudioControlPropertyElement:
|
||||
theAnswer = sizeof(AudioObjectPropertyElement);
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Object::GetPropertyDataSize(inObjectID,
|
||||
inClientPID,
|
||||
inAddress,
|
||||
inQualifierDataSize,
|
||||
inQualifierData);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void VC_Control::GetPropertyData(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData,
|
||||
UInt32 inDataSize,
|
||||
UInt32& outDataSize,
|
||||
void* outData) const
|
||||
{
|
||||
CheckObjectID(inObjectID);
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioControlPropertyScope:
|
||||
// This property returns the scope that the control is attached to.
|
||||
ThrowIf(inDataSize < sizeof(AudioObjectPropertyScope),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_Control::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioControlPropertyScope for the control");
|
||||
*reinterpret_cast<AudioObjectPropertyScope*>(outData) = mScope;
|
||||
outDataSize = sizeof(AudioObjectPropertyScope);
|
||||
break;
|
||||
|
||||
case kAudioControlPropertyElement:
|
||||
// This property returns the element that the control is attached to.
|
||||
ThrowIf(inDataSize < sizeof(AudioObjectPropertyElement),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_Control::GetPropertyData: not enough space for the return value of "
|
||||
"kAudioControlPropertyElement for the control");
|
||||
*reinterpret_cast<AudioObjectPropertyElement*>(outData) = mElement;
|
||||
outDataSize = sizeof(AudioObjectPropertyElement);
|
||||
break;
|
||||
|
||||
default:
|
||||
VC_Object::GetPropertyData(inObjectID,
|
||||
inClientPID,
|
||||
inAddress,
|
||||
inQualifierDataSize,
|
||||
inQualifierData,
|
||||
inDataSize,
|
||||
outDataSize,
|
||||
outData);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void VC_Control::CheckObjectID(AudioObjectID inObjectID) const
|
||||
{
|
||||
ThrowIf(inObjectID == kAudioObjectUnknown || inObjectID != GetObjectID(),
|
||||
CAException(kAudioHardwareBadObjectError),
|
||||
"VC_Control::CheckObjectID: wrong audio object ID for the control");
|
||||
}
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
87
driver/VC_Control.h
Normal file
87
driver/VC_Control.h
Normal file
@@ -0,0 +1,87 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VC_Control.h
|
||||
// VCDriver
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
//
|
||||
// An AudioObject that represents a user-controllable aspect of a device or stream, such as volume
|
||||
// or balance.
|
||||
//
|
||||
|
||||
#ifndef VCDriver__VC_Control
|
||||
#define VCDriver__VC_Control
|
||||
|
||||
// Superclass Includes
|
||||
#include "VC_Object.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
class VC_Control
|
||||
:
|
||||
public VC_Object
|
||||
{
|
||||
|
||||
protected:
|
||||
VC_Control(AudioObjectID inObjectID,
|
||||
AudioClassID inClassID,
|
||||
AudioClassID inBaseClassID,
|
||||
AudioObjectID inOwnerObjectID,
|
||||
AudioObjectPropertyScope inScope =
|
||||
kAudioObjectPropertyScopeOutput,
|
||||
AudioObjectPropertyElement inElement =
|
||||
kAudioObjectPropertyElementMaster);
|
||||
|
||||
#pragma mark Property Operations
|
||||
|
||||
public:
|
||||
virtual bool HasProperty(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const;
|
||||
virtual bool IsPropertySettable(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const;
|
||||
virtual UInt32 GetPropertyDataSize(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData) const;
|
||||
virtual void GetPropertyData(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData,
|
||||
UInt32 inDataSize,
|
||||
UInt32& outDataSize,
|
||||
void* outData) const;
|
||||
|
||||
#pragma mark Implementation
|
||||
|
||||
protected:
|
||||
void CheckObjectID(AudioObjectID inObjectID) const;
|
||||
|
||||
protected:
|
||||
const AudioObjectPropertyScope mScope;
|
||||
const AudioObjectPropertyElement mElement;
|
||||
|
||||
};
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* VCDriver__VC_Control */
|
||||
|
||||
1363
driver/VC_Device.cpp
Normal file
1363
driver/VC_Device.cpp
Normal file
File diff suppressed because it is too large
Load Diff
240
driver/VC_Device.h
Normal file
240
driver/VC_Device.h
Normal file
@@ -0,0 +1,240 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VC_Device.h
|
||||
// VCDriver
|
||||
//
|
||||
// Copyright © 2016, 2017, 2019 Kyle Neideck
|
||||
// Copyright © 2019 Gordon Childs
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_Device.h from Apple's SimpleAudioDriver Plug-In sample code.
|
||||
// https://developer.apple.com/library/mac/samplecode/AudioDriverExamples
|
||||
//
|
||||
|
||||
#ifndef VCDriver__VC_Device
|
||||
#define VCDriver__VC_Device
|
||||
|
||||
// SuperClass Includes
|
||||
#include "VC_AbstractDevice.h"
|
||||
|
||||
// Local Includes
|
||||
#include "VC_Types.h"
|
||||
#include "VC_Stream.h"
|
||||
#include "VC_VolumeControl.h"
|
||||
#include "VC_MuteControl.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CAMutex.h"
|
||||
#include "CAVolumeCurve.h"
|
||||
#include "CARingBuffer.h"
|
||||
|
||||
// System Includes
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <pthread.h>
|
||||
#include <atomic>
|
||||
|
||||
|
||||
class VC_Device
|
||||
:
|
||||
public VC_AbstractDevice
|
||||
{
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
public:
|
||||
static VC_Device& GetInstance();
|
||||
|
||||
private:
|
||||
static void StaticInitializer();
|
||||
|
||||
protected:
|
||||
VC_Device(AudioObjectID inObjectID,
|
||||
const CFStringRef __nonnull inDeviceName,
|
||||
const CFStringRef __nonnull inDeviceUID,
|
||||
const CFStringRef __nonnull inDeviceModelUID,
|
||||
AudioObjectID inInputStreamID,
|
||||
AudioObjectID inOutputStreamID,
|
||||
AudioObjectID inOutputVolumeControlID,
|
||||
AudioObjectID inOutputMuteControlID);
|
||||
virtual ~VC_Device();
|
||||
|
||||
virtual void Activate();
|
||||
virtual void Deactivate();
|
||||
|
||||
private:
|
||||
void InitLoopback();
|
||||
|
||||
#pragma mark Property Operations
|
||||
|
||||
public:
|
||||
virtual bool HasProperty(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress) const;
|
||||
virtual bool IsPropertySettable(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress) const;
|
||||
virtual UInt32 GetPropertyDataSize(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* __nullable inQualifierData) const;
|
||||
virtual void GetPropertyData(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* __nullable inQualifierData, UInt32 inDataSize, UInt32& outDataSize, void* __nonnull outData) const;
|
||||
virtual void SetPropertyData(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* __nullable inQualifierData, UInt32 inDataSize, const void* __nonnull inData);
|
||||
|
||||
#pragma mark Device Property Operations
|
||||
|
||||
private:
|
||||
bool Device_HasProperty(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress) const;
|
||||
bool Device_IsPropertySettable(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress) const;
|
||||
UInt32 Device_GetPropertyDataSize(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* __nullable inQualifierData) const;
|
||||
void Device_GetPropertyData(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* __nullable inQualifierData, UInt32 inDataSize, UInt32& outDataSize, void* __nonnull outData) const;
|
||||
void Device_SetPropertyData(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* __nullable inQualifierData, UInt32 inDataSize, const void* __nonnull inData);
|
||||
|
||||
#pragma mark IO Operations
|
||||
|
||||
public:
|
||||
void StartIO(UInt32 inClientID);
|
||||
void StopIO(UInt32 inClientID);
|
||||
|
||||
void GetZeroTimeStamp(Float64& outSampleTime, UInt64& outHostTime, UInt64& outSeed);
|
||||
|
||||
void WillDoIOOperation(UInt32 inOperationID, bool& outWillDo, bool& outWillDoInPlace) const;
|
||||
void BeginIOOperation(UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo& inIOCycleInfo, UInt32 inClientID);
|
||||
void DoIOOperation(AudioObjectID inStreamObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo& inIOCycleInfo, void* __nonnull ioMainBuffer, void* __nullable ioSecondaryBuffer);
|
||||
void EndIOOperation(UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo& inIOCycleInfo, UInt32 inClientID);
|
||||
|
||||
private:
|
||||
void ReadInputData(UInt32 inIOBufferFrameSize, Float64 inSampleTime, void* __nonnull outBuffer);
|
||||
void WriteOutputData(UInt32 inIOBufferFrameSize, Float64 inSampleTime, const void* __nonnull inBuffer);
|
||||
|
||||
#pragma mark Accessors
|
||||
|
||||
public:
|
||||
Float64 GetSampleRate() const;
|
||||
void RequestSampleRate(Float64 inRequestedSampleRate);
|
||||
|
||||
private:
|
||||
/*!
|
||||
@return The Audio Object that has the ID inObjectID and belongs to this device.
|
||||
@throws CAException if there is no such Audio Object.
|
||||
*/
|
||||
const VC_Object& GetOwnedObjectByID(AudioObjectID inObjectID) const;
|
||||
VC_Object& GetOwnedObjectByID(AudioObjectID inObjectID);
|
||||
|
||||
/*! @return The number of Audio Objects belonging to this device, e.g. streams and controls. */
|
||||
UInt32 GetNumberOfSubObjects() const;
|
||||
/*! @return The number of Audio Objects with output scope belonging to this device. */
|
||||
UInt32 GetNumberOfOutputSubObjects() const;
|
||||
/*!
|
||||
@return The number of control Audio Objects with output scope belonging to this device, e.g.
|
||||
output volume and mute controls.
|
||||
*/
|
||||
UInt32 GetNumberOfOutputControls() const;
|
||||
/*!
|
||||
Set the device's sample rate.
|
||||
|
||||
Private because (after initialisation) this can only be called after asking the host to stop IO
|
||||
for the device. See VC_Device::PerformConfigChange and
|
||||
RequestDeviceConfigurationChange in AudioServerPlugIn.h.
|
||||
|
||||
@param inNewSampleRate The sample rate.
|
||||
@param force If true, set the sample rate on the device even if it's currently set to
|
||||
inNewSampleRate.
|
||||
@throws CAException if inNewSampleRate < 1 or if applying the sample rate to one of the streams
|
||||
fails.
|
||||
*/
|
||||
void SetSampleRate(Float64 inNewSampleRate, bool force = false);
|
||||
|
||||
/*! @return True if inObjectID is the ID of one of this device's streams. */
|
||||
inline bool IsStreamID(AudioObjectID inObjectID) const noexcept;
|
||||
|
||||
#pragma mark Hardware Accessors
|
||||
|
||||
private:
|
||||
void _HW_Open();
|
||||
void _HW_Close();
|
||||
kern_return_t _HW_StartIO();
|
||||
void _HW_StopIO();
|
||||
Float64 _HW_GetSampleRate() const;
|
||||
kern_return_t _HW_SetSampleRate(Float64 inNewSampleRate);
|
||||
UInt32 _HW_GetRingBufferFrameSize() const;
|
||||
|
||||
#pragma mark Implementation
|
||||
|
||||
public:
|
||||
CFStringRef __nonnull CopyDeviceUID() const { return mDeviceUID; }
|
||||
void AddClient(const AudioServerPlugInClientInfo* __nonnull inClientInfo);
|
||||
void RemoveClient(const AudioServerPlugInClientInfo* __nonnull inClientInfo);
|
||||
/*!
|
||||
Apply a change requested with VC_PlugIn::Host_RequestDeviceConfigurationChange. See
|
||||
PerformDeviceConfigurationChange in AudioServerPlugIn.h.
|
||||
*/
|
||||
void PerformConfigChange(UInt64 inChangeAction, void* __nullable inChangeInfo);
|
||||
/*! Cancel a change requested with VC_PlugIn::Host_RequestDeviceConfigurationChange. */
|
||||
void AbortConfigChange(UInt64 inChangeAction, void* __nullable inChangeInfo);
|
||||
|
||||
private:
|
||||
static pthread_once_t sStaticInitializer;
|
||||
static VC_Device* __nonnull sInstance;
|
||||
|
||||
#define kDeviceName "Volume Control"
|
||||
#define kDeviceManufacturerName "VolumeControl"
|
||||
|
||||
const CFStringRef __nonnull mDeviceName;
|
||||
const CFStringRef __nonnull mDeviceUID;
|
||||
const CFStringRef __nonnull mDeviceModelUID;
|
||||
|
||||
bool mIsHidden;
|
||||
|
||||
enum
|
||||
{
|
||||
// The number of global/output sub-objects varies because the controls can be disabled.
|
||||
kNumberOfInputSubObjects = 1,
|
||||
|
||||
kNumberOfStreams = 2,
|
||||
kNumberOfInputStreams = 1,
|
||||
kNumberOfOutputStreams = 1
|
||||
};
|
||||
|
||||
CAMutex mStateMutex;
|
||||
CAMutex mIOMutex;
|
||||
|
||||
const Float64 kSampleRateDefault = 44100.0;
|
||||
// Before we can change sample rate, the host has to stop the device. The new sample rate is
|
||||
// stored here while it does.
|
||||
Float64 mPendingSampleRate = kSampleRateDefault;
|
||||
|
||||
#define kLoopbackRingBufferFrameSize 16384
|
||||
Float64 mLoopbackSampleRate;
|
||||
CARingBuffer mLoopbackRingBuffer;
|
||||
|
||||
// TODO: a comment explaining why we need a clock for loopback-only mode
|
||||
struct {
|
||||
Float64 hostTicksPerFrame = 0.0;
|
||||
UInt64 numberTimeStamps = 0;
|
||||
UInt64 anchorHostTime = 0;
|
||||
} mLoopbackTime;
|
||||
|
||||
VC_Stream mInputStream;
|
||||
VC_Stream mOutputStream;
|
||||
|
||||
enum class ChangeAction : UInt64
|
||||
{
|
||||
SetSampleRate
|
||||
};
|
||||
|
||||
VC_VolumeControl mVolumeControl;
|
||||
VC_MuteControl mMuteControl;
|
||||
|
||||
// Simple IO client counter to replace mClients-based tracking.
|
||||
std::atomic<UInt32> mIOClientCount{0};
|
||||
|
||||
};
|
||||
|
||||
#endif /* VCDriver__VC_Device */
|
||||
225
driver/VC_MuteControl.cpp
Normal file
225
driver/VC_MuteControl.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VC_MuteControl.cpp
|
||||
// VCDriver
|
||||
//
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "VC_MuteControl.h"
|
||||
|
||||
// Local Includes
|
||||
#include "VC_PlugIn.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAException.h"
|
||||
#include "CADispatchQueue.h"
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
VC_MuteControl::VC_MuteControl(AudioObjectID inObjectID,
|
||||
AudioObjectID inOwnerObjectID,
|
||||
AudioObjectPropertyScope inScope,
|
||||
AudioObjectPropertyElement inElement)
|
||||
:
|
||||
VC_Control(inObjectID,
|
||||
kAudioMuteControlClassID,
|
||||
kAudioBooleanControlClassID,
|
||||
inOwnerObjectID,
|
||||
inScope,
|
||||
inElement),
|
||||
mMutex("Mute Control"),
|
||||
mMuted(false)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma mark Property Operations
|
||||
|
||||
bool VC_MuteControl::HasProperty(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
CheckObjectID(inObjectID);
|
||||
|
||||
bool theAnswer = false;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioBooleanControlPropertyValue:
|
||||
theAnswer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Control::HasProperty(inObjectID, inClientPID, inAddress);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
bool VC_MuteControl::IsPropertySettable(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
CheckObjectID(inObjectID);
|
||||
|
||||
bool theAnswer = false;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioBooleanControlPropertyValue:
|
||||
theAnswer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Control::IsPropertySettable(inObjectID, inClientPID, inAddress);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
UInt32 VC_MuteControl::GetPropertyDataSize(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData) const
|
||||
{
|
||||
CheckObjectID(inObjectID);
|
||||
|
||||
UInt32 theAnswer = 0;
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioBooleanControlPropertyValue:
|
||||
theAnswer = sizeof(UInt32);
|
||||
break;
|
||||
|
||||
default:
|
||||
theAnswer = VC_Control::GetPropertyDataSize(inObjectID,
|
||||
inClientPID,
|
||||
inAddress,
|
||||
inQualifierDataSize,
|
||||
inQualifierData);
|
||||
break;
|
||||
};
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void VC_MuteControl::GetPropertyData(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData,
|
||||
UInt32 inDataSize,
|
||||
UInt32& outDataSize,
|
||||
void* outData) const
|
||||
{
|
||||
CheckObjectID(inObjectID);
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioBooleanControlPropertyValue:
|
||||
// This returns the mute value of the control.
|
||||
{
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_MuteControl::GetPropertyData: not enough space for the return value "
|
||||
"of kAudioBooleanControlPropertyValue for the mute control");
|
||||
|
||||
CAMutex::Locker theLocker(mMutex);
|
||||
|
||||
// Non-zero for true, which means audio is being muted.
|
||||
*reinterpret_cast<UInt32*>(outData) = mMuted ? 1 : 0;
|
||||
outDataSize = sizeof(UInt32);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
VC_Control::GetPropertyData(inObjectID,
|
||||
inClientPID,
|
||||
inAddress,
|
||||
inQualifierDataSize,
|
||||
inQualifierData,
|
||||
inDataSize,
|
||||
outDataSize,
|
||||
outData);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void VC_MuteControl::SetPropertyData(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData,
|
||||
UInt32 inDataSize,
|
||||
const void* inData)
|
||||
{
|
||||
CheckObjectID(inObjectID);
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioBooleanControlPropertyValue:
|
||||
{
|
||||
ThrowIf(inDataSize < sizeof(UInt32),
|
||||
CAException(kAudioHardwareBadPropertySizeError),
|
||||
"VC_MuteControl::SetPropertyData: wrong size for the data for "
|
||||
"kAudioBooleanControlPropertyValue");
|
||||
|
||||
CAMutex::Locker theLocker(mMutex);
|
||||
|
||||
// Non-zero for true, meaning audio will be muted.
|
||||
bool theNewMuted = (*reinterpret_cast<const UInt32*>(inData) != 0);
|
||||
|
||||
if(mMuted != theNewMuted)
|
||||
{
|
||||
mMuted = theNewMuted;
|
||||
|
||||
// Send notifications.
|
||||
CADispatchQueue::GetGlobalSerialQueue().Dispatch(false, ^{
|
||||
AudioObjectPropertyAddress theChangedProperty[1];
|
||||
theChangedProperty[0] = {
|
||||
kAudioBooleanControlPropertyValue, mScope, mElement
|
||||
};
|
||||
|
||||
VC_PlugIn::Host_PropertiesChanged(inObjectID, 1, theChangedProperty);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
VC_Control::SetPropertyData(inObjectID,
|
||||
inClientPID,
|
||||
inAddress,
|
||||
inQualifierDataSize,
|
||||
inQualifierData,
|
||||
inDataSize,
|
||||
inData);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
98
driver/VC_MuteControl.h
Normal file
98
driver/VC_MuteControl.h
Normal file
@@ -0,0 +1,98 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VC_MuteControl.h
|
||||
// VCDriver
|
||||
//
|
||||
// Copyright © 2017 Kyle Neideck
|
||||
//
|
||||
|
||||
#ifndef VCDriver__VC_MuteControl
|
||||
#define VCDriver__VC_MuteControl
|
||||
|
||||
// Superclass Includes
|
||||
#include "VC_Control.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CAMutex.h"
|
||||
|
||||
// System Includes
|
||||
#include <MacTypes.h>
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
|
||||
|
||||
#pragma clang assume_nonnull begin
|
||||
|
||||
class VC_MuteControl
|
||||
:
|
||||
public VC_Control
|
||||
{
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
public:
|
||||
VC_MuteControl(AudioObjectID inObjectID,
|
||||
AudioObjectID inOwnerObjectID,
|
||||
AudioObjectPropertyScope inScope =
|
||||
kAudioObjectPropertyScopeOutput,
|
||||
AudioObjectPropertyElement inElement =
|
||||
kAudioObjectPropertyElementMaster);
|
||||
|
||||
#pragma mark Property Operations
|
||||
|
||||
bool HasProperty(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const;
|
||||
|
||||
bool IsPropertySettable(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress) const;
|
||||
|
||||
UInt32 GetPropertyDataSize(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData) const;
|
||||
|
||||
void GetPropertyData(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData,
|
||||
UInt32 inDataSize,
|
||||
UInt32& outDataSize,
|
||||
void* outData) const;
|
||||
|
||||
void SetPropertyData(AudioObjectID inObjectID,
|
||||
pid_t inClientPID,
|
||||
const AudioObjectPropertyAddress& inAddress,
|
||||
UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData,
|
||||
UInt32 inDataSize,
|
||||
const void* inData);
|
||||
|
||||
#pragma mark Implementation
|
||||
|
||||
private:
|
||||
CAMutex mMutex;
|
||||
bool mMuted;
|
||||
|
||||
};
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
#endif /* VCDriver__VC_MuteControl */
|
||||
|
||||
184
driver/VC_Object.cpp
Normal file
184
driver/VC_Object.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
// This file is part of Background Music.
|
||||
//
|
||||
// Background Music is free software: you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// Background Music is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Background Music. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//
|
||||
// VC_Object.cpp
|
||||
// VCDriver
|
||||
//
|
||||
// Copyright © 2016 Kyle Neideck
|
||||
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_Object.cpp from Apple's SimpleAudioDriver Plug-In sample code.
|
||||
// https://developer.apple.com/library/mac/samplecode/AudioDriverExamples
|
||||
//
|
||||
// Similarly to VC_Object.h, this file hasn't been changed much from SA_Object.cpp, except to
|
||||
// remove the SA_ObjectMap class.
|
||||
//
|
||||
|
||||
// Self Include
|
||||
#include "VC_Object.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAException.h"
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
#pragma mark -
|
||||
#pragma mark VC_Object
|
||||
//==================================================================================================
|
||||
|
||||
#pragma mark Construction/Destruction
|
||||
|
||||
VC_Object::VC_Object(AudioObjectID inObjectID, AudioClassID inClassID, AudioClassID inBaseClassID, AudioObjectID inOwnerObjectID)
|
||||
:
|
||||
mObjectID(inObjectID),
|
||||
mClassID(inClassID),
|
||||
mBaseClassID(inBaseClassID),
|
||||
mOwnerObjectID(inOwnerObjectID),
|
||||
mIsActive(false)
|
||||
{
|
||||
}
|
||||
|
||||
void VC_Object::Activate()
|
||||
{
|
||||
mIsActive = true;
|
||||
}
|
||||
|
||||
void VC_Object::Deactivate()
|
||||
{
|
||||
mIsActive = false;
|
||||
}
|
||||
|
||||
VC_Object::~VC_Object()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma mark Property Operations
|
||||
|
||||
bool VC_Object::HasProperty(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
#pragma unused(inObjectID, inClientPID)
|
||||
|
||||
bool theAnswer = false;
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyBaseClass:
|
||||
case kAudioObjectPropertyClass:
|
||||
case kAudioObjectPropertyOwner:
|
||||
case kAudioObjectPropertyOwnedObjects:
|
||||
theAnswer = true;
|
||||
break;
|
||||
};
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
bool VC_Object::IsPropertySettable(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress) const
|
||||
{
|
||||
#pragma unused(inObjectID, inClientPID)
|
||||
|
||||
bool theAnswer = false;
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyBaseClass:
|
||||
case kAudioObjectPropertyClass:
|
||||
case kAudioObjectPropertyOwner:
|
||||
case kAudioObjectPropertyOwnedObjects:
|
||||
theAnswer = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
Throw(CAException(kAudioHardwareUnknownPropertyError));
|
||||
};
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
UInt32 VC_Object::GetPropertyDataSize(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData) const
|
||||
{
|
||||
#pragma unused(inObjectID, inClientPID, inQualifierDataSize, inQualifierData)
|
||||
|
||||
UInt32 theAnswer = 0;
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyBaseClass:
|
||||
case kAudioObjectPropertyClass:
|
||||
theAnswer = sizeof(AudioClassID);
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyOwner:
|
||||
theAnswer = sizeof(AudioObjectID);
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyOwnedObjects:
|
||||
theAnswer = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
Throw(CAException(kAudioHardwareUnknownPropertyError));
|
||||
};
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void VC_Object::GetPropertyData(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, UInt32& outDataSize, void* outData) const
|
||||
{
|
||||
#pragma unused(inObjectID, inClientPID, inQualifierDataSize, inQualifierData)
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
case kAudioObjectPropertyBaseClass:
|
||||
// This is the AudioClassID of the base class of this object. This is an invariant.
|
||||
ThrowIf(inDataSize < sizeof(AudioClassID), CAException(kAudioHardwareBadPropertySizeError), "VC_Object::GetPropertyData: not enough space for the return value of kAudioObjectPropertyBaseClass");
|
||||
*reinterpret_cast<AudioClassID*>(outData) = mBaseClassID;
|
||||
outDataSize = sizeof(AudioClassID);
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyClass:
|
||||
// This is the AudioClassID of the class of this object. This is an invariant.
|
||||
ThrowIf(inDataSize < sizeof(AudioClassID), CAException(kAudioHardwareBadPropertySizeError), "VC_Object::GetPropertyData: not enough space for the return value of kAudioObjectPropertyClass");
|
||||
*reinterpret_cast<AudioClassID*>(outData) = mClassID;
|
||||
outDataSize = sizeof(AudioClassID);
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyOwner:
|
||||
// The AudioObjectID of the object that owns this object. This is an invariant.
|
||||
ThrowIf(inDataSize < sizeof(AudioObjectID), CAException(kAudioHardwareBadPropertySizeError), "VC_Object::GetPropertyData: not enough space for the return value of kAudioObjectPropertyOwner");
|
||||
*reinterpret_cast<AudioClassID*>(outData) = mOwnerObjectID;
|
||||
outDataSize = sizeof(AudioObjectID);
|
||||
break;
|
||||
|
||||
case kAudioObjectPropertyOwnedObjects:
|
||||
// This is an array of AudioObjectIDs for the objects owned by this object. By default,
|
||||
// objects don't own any other objects. This is an invariant by default, but an object
|
||||
// that can contain other objects will likely need to do some synchronization to access
|
||||
// this property.
|
||||
outDataSize = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
Throw(CAException(kAudioHardwareUnknownPropertyError));
|
||||
};
|
||||
}
|
||||
|
||||
void VC_Object::SetPropertyData(AudioObjectID inObjectID, pid_t inClientPID, const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData)
|
||||
{
|
||||
#pragma unused(inObjectID, inClientPID, inQualifierDataSize, inQualifierData, inDataSize, inData)
|
||||
|
||||
switch(inAddress.mSelector)
|
||||
{
|
||||
default:
|
||||
Throw(CAException(kAudioHardwareUnknownPropertyError));
|
||||
};
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user