1 /* 2 File: ComponentBase.h 3 Abstract: Part of CoreAudio Utility Classes 4 Version: 1.01 5 6 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 7 Inc. ("Apple") in consideration of your agreement to the following 8 terms, and your use, installation, modification or redistribution of 9 this Apple software constitutes acceptance of these terms. If you do 10 not agree with these terms, please do not use, install, modify or 11 redistribute this Apple software. 12 13 In consideration of your agreement to abide by the following terms, and 14 subject to these terms, Apple grants you a personal, non-exclusive 15 license, under Apple's copyrights in this original Apple software (the 16 "Apple Software"), to use, reproduce, modify and redistribute the Apple 17 Software, with or without modifications, in source and/or binary forms; 18 provided that if you redistribute the Apple Software in its entirety and 19 without modifications, you must retain this notice and the following 20 text and disclaimers in all such redistributions of the Apple Software. 21 Neither the name, trademarks, service marks or logos of Apple Inc. may 22 be used to endorse or promote products derived from the Apple Software 23 without specific prior written permission from Apple. Except as 24 expressly stated in this notice, no other rights or licenses, express or 25 implied, are granted by Apple herein, including but not limited to any 26 patent rights that may be infringed by your derivative works or by other 27 works in which the Apple Software may be incorporated. 28 29 The Apple Software is provided by Apple on an "AS IS" basis. APPLE 30 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 31 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 32 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 33 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 34 35 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 36 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 37 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 39 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 40 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 41 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 42 POSSIBILITY OF SUCH DAMAGE. 43 44 Copyright (C) 2012 Apple Inc. All Rights Reserved. 45 46 */ 47 #ifndef __ComponentBase_h__ 48 #define __ComponentBase_h__ 49 50 #include <new> 51 #include "CADebugMacros.h" 52 #include "CAXException.h" 53 54 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) 55 #include <CoreAudio/CoreAudioTypes.h> 56 #include <AudioUnit/AudioUnit.h> 57 58 #if !CA_USE_AUDIO_PLUGIN_ONLY 59 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Components.h> 60 61 #if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) 62 #define AudioComponentInstance ComponentInstance 63 #define AudioComponentDescription ComponentDescription 64 #define AudioComponent Component 65 #endif 66 Handle CMgr_GetComponentInstanceStorage(ComponentInstance aComponentInstance); 67 void CMgr_SetComponentInstanceStorage(ComponentInstance aComponentInstance, Handle theStorage); 68 #endif 69 70 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 71 typedef Float32 AudioUnitParameterValue; 72 #endif 73 #if COREAUDIOTYPES_VERSION < 1051 74 typedef Float32 AudioUnitSampleType; 75 #endif 76 77 #if !TARGET_OS_WIN32 78 #include <pthread.h> 79 #endif 80 81 #if TARGET_OS_WIN32 82 #include "CAGuard.h" 83 #endif 84 #else 85 #include "CoreAudioTypes.h" 86 #if !CA_USE_AUDIO_PLUGIN_ONLY 87 #include "ComponentManagerDependenciesWin.h" 88 #endif 89 #include "AudioUnit.h" 90 #include "CAGuard.h" 91 #endif 92 93 #ifndef COMPONENT_THROW 94 #if VERBOSE_COMPONENT_THROW 95 #define COMPONENT_THROW(throw_err) \ 96 do { DebugMessage(#throw_err); throw static_cast<OSStatus>(throw_err); } while (0) 97 #else 98 #define COMPONENT_THROW(throw_err) \ 99 throw static_cast<OSStatus>(throw_err) 100 #endif 101 #endif 102 103 #define COMPONENT_CATCH \ 104 catch (const CAXException &ex) { result = ex.mError; } \ 105 catch (std::bad_alloc &) { result = kAudio_MemFullError; } \ 106 catch (OSStatus catch_err) { result = catch_err; } \ 107 catch (OSErr catch_err) { result = catch_err; } \ 108 catch (...) { result = -1; } 109 110 /*! @class ComponentBase */ 111 class ComponentBase { 112 public: 113 // classic MacErrors 114 enum { noErr = 0}; 115 116 /*! @ctor ComponentBase */ 117 ComponentBase(AudioComponentInstance inInstance); 118 119 /*! @dtor ~ComponentBase */ 120 virtual ~ComponentBase(); 121 122 /*! @method PostConstructor */ 123 virtual void PostConstructor(); 124 125 /*! @method PreDestructor */ 126 virtual void PreDestructor(); 127 128 #if !CA_USE_AUDIO_PLUGIN_ONLY 129 /*! @method Version */ 130 virtual OSStatus Version(); 131 132 /*! @method ComponentEntryDispatch */ 133 static OSStatus ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This); 134 135 /*! GetSelectorForCanDo */ 136 static SInt16 GetSelectorForCanDo(ComponentParameters *params); 137 #endif 138 139 /*! @method GetComponentInstance */ GetComponentInstance()140 AudioComponentInstance GetComponentInstance() const { return mComponentInstance; } 141 142 /*! @method GetComponentDescription */ 143 AudioComponentDescription GetComponentDescription() const; 144 145 // This global variable is so that new instances know how they were instantiated: via the Component Manager, 146 // or as AudioComponents. It's ugly, but preferable to altering the constructor of every class in the hierarchy. 147 // It's safe because construction is protected by ComponentInitLocker. 148 enum EInstanceType { kComponentMgrInstance, kAudioComponentInstance }; 149 static EInstanceType sNewInstanceType; 150 151 /*! @method IsPluginObject */ IsPluginObject()152 bool IsPluginObject () const { return mInstanceType == kAudioComponentInstance; } 153 /*! @method IsCMgrObject */ IsCMgrObject()154 bool IsCMgrObject () const { return mInstanceType == kComponentMgrInstance; } 155 156 /*! @method AP_Open */ 157 static OSStatus AP_Open(void *self, AudioUnit compInstance); 158 159 /*! @method AP_Close */ 160 static OSStatus AP_Close(void *self); 161 162 protected: 163 /*! @var mComponentInstance */ 164 AudioComponentInstance mComponentInstance; 165 EInstanceType mInstanceType; 166 }; 167 168 class ComponentInitLocker 169 { 170 #if TARGET_OS_MAC 171 public: ComponentInitLocker()172 ComponentInitLocker() 173 { 174 pthread_once(&sOnce, InitComponentInitLocker); 175 pthread_mutex_lock(&sComponentOpenMutex); 176 mPreviousNewInstanceType = ComponentBase::sNewInstanceType; 177 } ~ComponentInitLocker()178 ~ComponentInitLocker() 179 { 180 ComponentBase::sNewInstanceType = mPreviousNewInstanceType; 181 pthread_mutex_unlock(&sComponentOpenMutex); 182 } 183 private: 184 static pthread_mutex_t sComponentOpenMutex; 185 static pthread_once_t sOnce; 186 static void InitComponentInitLocker(); 187 188 #elif TARGET_OS_WIN32 189 public: 190 bool sNeedsUnlocking; 191 ComponentInitLocker() { sNeedsUnlocking = sComponentOpenGuard.Lock(); } 192 ~ComponentInitLocker() { if(sNeedsUnlocking) { sComponentOpenGuard.Unlock(); } } 193 private: 194 static CAGuard sComponentOpenGuard; 195 #endif 196 197 private: 198 ComponentBase::EInstanceType mPreviousNewInstanceType; 199 }; 200 201 /*! @class AudioComponentPlugInInstance */ 202 struct AudioComponentPlugInInstance { 203 AudioComponentPlugInInterface mPlugInInterface; 204 void * (*mConstruct)(void *memory, AudioComponentInstance ci); 205 void (*mDestruct)(void *memory); 206 void * mPad[2]; // pad to a 16-byte boundary (in either 32 or 64 bit mode) 207 UInt32 mInstanceStorage; // the ACI implementation object is constructed into this memory 208 // this member is just a placeholder. it is aligned to a 16byte boundary 209 }; 210 211 /*! @class APFactory */ 212 template <class APMethodLookup, class Implementor> 213 class APFactory { 214 public: Construct(void * memory,AudioComponentInstance compInstance)215 static void *Construct(void *memory, AudioComponentInstance compInstance) 216 { 217 return new(memory) Implementor(compInstance); 218 } 219 Destruct(void * memory)220 static void Destruct(void *memory) 221 { 222 ((Implementor *)memory)->~Implementor(); 223 } 224 225 // This is the AudioComponentFactoryFunction. It returns an AudioComponentPlugInInstance. 226 // The actual implementation object is not created until Open(). Factory(const AudioComponentDescription * inDesc)227 static AudioComponentPlugInInterface *Factory(const AudioComponentDescription *inDesc) 228 { 229 AudioComponentPlugInInstance *acpi = 230 (AudioComponentPlugInInstance *)malloc( offsetof(AudioComponentPlugInInstance, mInstanceStorage) + sizeof(Implementor) ); 231 acpi->mPlugInInterface.Open = ComponentBase::AP_Open; 232 acpi->mPlugInInterface.Close = ComponentBase::AP_Close; 233 acpi->mPlugInInterface.Lookup = APMethodLookup::Lookup; 234 acpi->mPlugInInterface.reserved = NULL; 235 acpi->mConstruct = Construct; 236 acpi->mDestruct = Destruct; 237 acpi->mPad[0] = NULL; 238 acpi->mPad[1] = NULL; 239 return (AudioComponentPlugInInterface*)acpi; 240 } 241 242 // This is for runtime registration (not for plug-ins loaded from bundles). 243 static AudioComponent Register(UInt32 type, UInt32 subtype, UInt32 manuf, CFStringRef name, UInt32 vers, UInt32 flags=0) 244 { 245 AudioComponentDescription desc = { type, subtype, manuf, flags, 0 }; 246 return AudioComponentRegister(&desc, name, vers, Factory); 247 } 248 }; 249 250 #if !CA_USE_AUDIO_PLUGIN_ONLY 251 /*! @class ComponentEntryPoint 252 * @discussion This is only used for a component manager version 253 */ 254 template <class Class> 255 class ComponentEntryPoint { 256 public: 257 /*! @method Dispatch */ Dispatch(ComponentParameters * params,Class * obj)258 static OSStatus Dispatch(ComponentParameters *params, Class *obj) 259 { 260 OSStatus result = noErr; 261 262 try { 263 if (params->what == kComponentOpenSelect) { 264 // solve a host of initialization thread safety issues. 265 ComponentInitLocker lock; 266 267 ComponentBase::sNewInstanceType = ComponentBase::kComponentMgrInstance; 268 ComponentInstance ci = (ComponentInstance)(params->params[0]); 269 Class *This = new Class((AudioComponentInstance)ci); 270 This->PostConstructor(); // allows base class to do additional initialization 271 // once the derived class is fully constructed 272 273 CMgr_SetComponentInstanceStorage(ci, (Handle)This); 274 } else 275 result = Class::ComponentEntryDispatch(params, obj); 276 } 277 COMPONENT_CATCH 278 279 return result; 280 } 281 282 /*! @method Register */ Register(OSType compType,OSType subType,OSType manufacturer)283 static Component Register(OSType compType, OSType subType, OSType manufacturer) 284 { 285 ComponentDescription description = {compType, subType, manufacturer, 0, 0}; 286 Component component = RegisterComponent(&description, (ComponentRoutineUPP) Dispatch, registerComponentGlobal, NULL, NULL, NULL); 287 if (component != NULL) { 288 SetDefaultComponent(component, defaultComponentAnyFlagsAnyManufacturerAnySubType); 289 } 290 return component; 291 } 292 }; 293 294 // these are the macros that are used to generate the Entry Points for a given Audio Plugin 295 #if CA_USE_AUDIO_PLUGIN_ONLY 296 #define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \ 297 extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \ 298 extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \ 299 return FactoryType<Class>::Factory(inDesc); \ 300 } 301 #else 302 // you should be using this macros as it registers both 303 // a plugin and a component mgr version. this can and should be used 304 // with new and existing audio components (backwards compatible to SL) 305 #define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \ 306 extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \ 307 extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \ 308 return ComponentEntryPoint<Class>::Dispatch(params, obj); \ 309 } \ 310 extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \ 311 extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \ 312 return FactoryType<Class>::Factory(inDesc); \ 313 } 314 // the only component we still support are the carbon based view components 315 // you should be using this macro now to exclusively register those types 316 #define VIEW_COMPONENT_ENTRY(Class) \ 317 extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \ 318 extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \ 319 return ComponentEntryPoint<Class>::Dispatch(params, obj); \ 320 } 321 #endif 322 323 /*! @class ComponentRegistrar */ 324 template <class Class, OSType Type, OSType Subtype, OSType Manufacturer> 325 class ComponentRegistrar { 326 public: 327 /*! @ctor ComponentRegistrar */ ComponentRegistrar()328 ComponentRegistrar() { ComponentEntryPoint<Class>::Register(Type, Subtype, Manufacturer); } 329 }; 330 331 #define COMPONENT_REGISTER(Class,Type,Subtype,Manufacturer) \ 332 static ComponentRegistrar<Class, Type, Subtype, Manufacturer> gRegistrar##Class 333 #else 334 #define COMPONENT_ENTRY(Class) 335 #define COMPONENT_REGISTER(Class) 336 #define AUDIOCOMPONENT_ENTRY(FactoryType, Class) 337 #endif // !CA_USE_AUDIO_PLUGIN_ONLY 338 339 340 #endif // __ComponentBase_h__ 341