1 /* 2 Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 See LICENSE.txt for this sample’s licensing information 4 5 Abstract: 6 Part of Core Audio AUBase Classes 7 */ 8 9 #ifndef __ComponentBase_h__ 10 #define __ComponentBase_h__ 11 12 #include <new> 13 #include "CADebugMacros.h" 14 #include "CAXException.h" 15 16 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) 17 #include <CoreAudio/CoreAudioTypes.h> 18 #include <AudioUnit/AudioUnit.h> 19 20 #if !CA_USE_AUDIO_PLUGIN_ONLY 21 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Components.h> 22 23 #if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) 24 #define AudioComponentInstance ComponentInstance 25 #define AudioComponentDescription ComponentDescription 26 #define AudioComponent Component 27 #endif 28 Handle CMgr_GetComponentInstanceStorage(ComponentInstance aComponentInstance); 29 void CMgr_SetComponentInstanceStorage(ComponentInstance aComponentInstance, Handle theStorage); 30 #endif 31 32 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 33 typedef Float32 AudioUnitParameterValue; 34 #endif 35 #if COREAUDIOTYPES_VERSION < 1051 36 typedef Float32 AudioUnitSampleType; 37 #endif 38 39 #if !TARGET_OS_WIN32 40 #include <pthread.h> 41 #endif 42 43 #if TARGET_OS_WIN32 44 #include "CAGuard.h" 45 #endif 46 #else 47 #include "CoreAudioTypes.h" 48 #if !CA_USE_AUDIO_PLUGIN_ONLY 49 #include "ComponentManagerDependenciesWin.h" 50 #endif 51 #include "AudioUnit.h" 52 #include "CAGuard.h" 53 #endif 54 55 #ifndef COMPONENT_THROW 56 #if VERBOSE_COMPONENT_THROW 57 #define COMPONENT_THROW(throw_err) \ 58 do { DebugMessage(#throw_err); throw static_cast<OSStatus>(throw_err); } while (0) 59 #else 60 #define COMPONENT_THROW(throw_err) \ 61 throw static_cast<OSStatus>(throw_err) 62 #endif 63 #endif 64 65 #define COMPONENT_CATCH \ 66 catch (const CAXException &ex) { result = ex.mError; } \ 67 catch (std::bad_alloc &) { result = kAudio_MemFullError; } \ 68 catch (OSStatus catch_err) { result = catch_err; } \ 69 catch (OSErr catch_err) { result = catch_err; } \ 70 catch (...) { result = -1; } 71 72 /*! @class ComponentBase */ 73 class ComponentBase { 74 public: 75 // classic MacErrors 76 enum { noErr = 0}; 77 78 /*! @ctor ComponentBase */ 79 ComponentBase(AudioComponentInstance inInstance); 80 81 /*! @dtor ~ComponentBase */ 82 virtual ~ComponentBase(); 83 84 /*! @method PostConstructor */ 85 virtual void PostConstructor(); 86 87 /*! @method PreDestructor */ 88 virtual void PreDestructor(); 89 90 #if !CA_USE_AUDIO_PLUGIN_ONLY 91 /*! @method Version */ 92 virtual OSStatus Version(); 93 94 /*! @method ComponentEntryDispatch */ 95 static OSStatus ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This); 96 97 /*! GetSelectorForCanDo */ 98 static SInt16 GetSelectorForCanDo(ComponentParameters *params); 99 #endif 100 101 /*! @method GetComponentInstance */ GetComponentInstance()102 AudioComponentInstance GetComponentInstance() const { return mComponentInstance; } 103 104 /*! @method GetComponentDescription */ 105 AudioComponentDescription GetComponentDescription() const; 106 107 // This global variable is so that new instances know how they were instantiated: via the Component Manager, 108 // or as AudioComponents. It's ugly, but preferable to altering the constructor of every class in the hierarchy. 109 // It's safe because construction is protected by ComponentInitLocker. 110 enum EInstanceType { kComponentMgrInstance, kAudioComponentInstance }; 111 static EInstanceType sNewInstanceType; 112 113 /*! @method IsPluginObject */ IsPluginObject()114 bool IsPluginObject () const { return mInstanceType == kAudioComponentInstance; } 115 /*! @method IsCMgrObject */ IsCMgrObject()116 bool IsCMgrObject () const { return mInstanceType == kComponentMgrInstance; } 117 118 /*! @method AP_Open */ 119 static OSStatus AP_Open(void *self, AudioUnit compInstance); 120 121 /*! @method AP_Close */ 122 static OSStatus AP_Close(void *self); 123 124 protected: 125 /*! @var mComponentInstance */ 126 AudioComponentInstance mComponentInstance; 127 EInstanceType mInstanceType; 128 }; 129 130 class ComponentInitLocker 131 { 132 #if TARGET_OS_MAC 133 public: ComponentInitLocker()134 ComponentInitLocker() 135 { 136 pthread_once(&sOnce, InitComponentInitLocker); 137 pthread_mutex_lock(&sComponentOpenMutex); 138 mPreviousNewInstanceType = ComponentBase::sNewInstanceType; 139 } ~ComponentInitLocker()140 ~ComponentInitLocker() 141 { 142 ComponentBase::sNewInstanceType = mPreviousNewInstanceType; 143 pthread_mutex_unlock(&sComponentOpenMutex); 144 } 145 146 // There are situations (11844772) where we need to be able to release the lock early. 147 class Unlocker { 148 public: Unlocker()149 Unlocker() 150 { 151 pthread_mutex_unlock(&sComponentOpenMutex); 152 } ~Unlocker()153 ~Unlocker() 154 { 155 pthread_mutex_lock(&sComponentOpenMutex); 156 } 157 }; 158 159 private: 160 static pthread_mutex_t sComponentOpenMutex; 161 static pthread_once_t sOnce; 162 static void InitComponentInitLocker(); 163 164 #elif TARGET_OS_WIN32 165 public: 166 bool sNeedsUnlocking; 167 ComponentInitLocker() { sNeedsUnlocking = sComponentOpenGuard.Lock(); } 168 ~ComponentInitLocker() { if(sNeedsUnlocking) { sComponentOpenGuard.Unlock(); } } 169 private: 170 static CAGuard sComponentOpenGuard; 171 #endif 172 173 private: 174 ComponentBase::EInstanceType mPreviousNewInstanceType; 175 }; 176 177 /*! @class AudioComponentPlugInInstance */ 178 struct AudioComponentPlugInInstance { 179 AudioComponentPlugInInterface mPlugInInterface; 180 void * (*mConstruct)(void *memory, AudioComponentInstance ci); 181 void (*mDestruct)(void *memory); 182 void * mPad[2]; // pad to a 16-byte boundary (in either 32 or 64 bit mode) 183 UInt32 mInstanceStorage; // the ACI implementation object is constructed into this memory 184 // this member is just a placeholder. it is aligned to a 16byte boundary 185 }; 186 187 /*! @class APFactory */ 188 template <class APMethodLookup, class Implementor> 189 class APFactory { 190 public: Construct(void * memory,AudioComponentInstance compInstance)191 static void *Construct(void *memory, AudioComponentInstance compInstance) 192 { 193 return new(memory) Implementor(compInstance); 194 } 195 Destruct(void * memory)196 static void Destruct(void *memory) 197 { 198 ((Implementor *)memory)->~Implementor(); 199 } 200 201 // This is the AudioComponentFactoryFunction. It returns an AudioComponentPlugInInstance. 202 // The actual implementation object is not created until Open(). Factory(const AudioComponentDescription *)203 static AudioComponentPlugInInterface *Factory(const AudioComponentDescription * /* inDesc */) 204 { 205 AudioComponentPlugInInstance *acpi = 206 (AudioComponentPlugInInstance *)malloc( offsetof(AudioComponentPlugInInstance, mInstanceStorage) + sizeof(Implementor) ); 207 acpi->mPlugInInterface.Open = ComponentBase::AP_Open; 208 acpi->mPlugInInterface.Close = ComponentBase::AP_Close; 209 acpi->mPlugInInterface.Lookup = APMethodLookup::Lookup; 210 acpi->mPlugInInterface.reserved = NULL; 211 acpi->mConstruct = Construct; 212 acpi->mDestruct = Destruct; 213 acpi->mPad[0] = NULL; 214 acpi->mPad[1] = NULL; 215 return (AudioComponentPlugInInterface*)acpi; 216 } 217 218 // This is for runtime registration (not for plug-ins loaded from bundles). 219 static AudioComponent Register(UInt32 type, UInt32 subtype, UInt32 manuf, CFStringRef name, UInt32 vers, UInt32 flags=0) 220 { 221 AudioComponentDescription desc = { type, subtype, manuf, flags, 0 }; 222 return AudioComponentRegister(&desc, name, vers, Factory); 223 } 224 }; 225 226 #if !CA_USE_AUDIO_PLUGIN_ONLY 227 /*! @class ComponentEntryPoint 228 * @discussion This is only used for a component manager version 229 */ 230 template <class Class> 231 class ComponentEntryPoint { 232 public: 233 /*! @method Dispatch */ Dispatch(ComponentParameters * params,Class * obj)234 static OSStatus Dispatch(ComponentParameters *params, Class *obj) 235 { 236 OSStatus result = noErr; 237 238 try { 239 if (params->what == kComponentOpenSelect) { 240 // solve a host of initialization thread safety issues. 241 ComponentInitLocker lock; 242 243 ComponentBase::sNewInstanceType = ComponentBase::kComponentMgrInstance; 244 ComponentInstance ci = (ComponentInstance)(params->params[0]); 245 Class *This = new Class((AudioComponentInstance)ci); 246 This->PostConstructor(); // allows base class to do additional initialization 247 // once the derived class is fully constructed 248 249 CMgr_SetComponentInstanceStorage(ci, (Handle)This); 250 } else 251 result = Class::ComponentEntryDispatch(params, obj); 252 } 253 COMPONENT_CATCH 254 255 return result; 256 } 257 258 /*! @method Register */ Register(OSType compType,OSType subType,OSType manufacturer)259 static Component Register(OSType compType, OSType subType, OSType manufacturer) 260 { 261 ComponentDescription description = {compType, subType, manufacturer, 0, 0}; 262 Component component = RegisterComponent(&description, (ComponentRoutineUPP) Dispatch, registerComponentGlobal, NULL, NULL, NULL); 263 if (component != NULL) { 264 SetDefaultComponent(component, defaultComponentAnyFlagsAnyManufacturerAnySubType); 265 } 266 return component; 267 } 268 }; 269 270 // NOTE: The Carbon Component Manager is deprecated in Mountain Lion (10.8). 271 // This macro should not be used with new audio components. 272 // It is only for backwards compatibility with Lion and Snow Leopard. 273 // This macro registers both an Audio Component plugin and a Carbon Component Manager version. 274 #define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \ 275 extern "C" __attribute__((visibility("default"))) OSStatus Class##Entry(ComponentParameters *params, Class *obj); \ 276 extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \ 277 return ComponentEntryPoint<Class>::Dispatch(params, obj); \ 278 } \ 279 extern "C" __attribute__((visibility("default"))) void * Class##Factory(const AudioComponentDescription *inDesc); \ 280 extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \ 281 return FactoryType<Class>::Factory(inDesc); \ 282 } 283 // the only component we still support are the carbon based view components 284 // you should be using this macro now to exclusively register those types 285 #define VIEW_COMPONENT_ENTRY(Class) \ 286 extern "C" __attribute__((visibility("default"))) OSStatus Class##Entry(ComponentParameters *params, Class *obj); \ 287 extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \ 288 return ComponentEntryPoint<Class>::Dispatch(params, obj); \ 289 } 290 291 /*! @class ComponentRegistrar */ 292 template <class Class, OSType Type, OSType Subtype, OSType Manufacturer> 293 class ComponentRegistrar { 294 public: 295 /*! @ctor ComponentRegistrar */ ComponentRegistrar()296 ComponentRegistrar() { ComponentEntryPoint<Class>::Register(Type, Subtype, Manufacturer); } 297 }; 298 299 #define COMPONENT_REGISTER(Class,Type,Subtype,Manufacturer) \ 300 static ComponentRegistrar<Class, Type, Subtype, Manufacturer> gRegistrar##Class 301 #else 302 #define COMPONENT_ENTRY(Class) 303 #define COMPONENT_REGISTER(Class) 304 // This macro is used to generate the Entry Point for a given Audio Component. 305 // You should be using this macro now. 306 #define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \ 307 extern "C" __attribute__((visibility("default"))) void * Class##Factory(const AudioComponentDescription *inDesc); \ 308 extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \ 309 return FactoryType<Class>::Factory(inDesc); \ 310 } 311 312 #endif // !CA_USE_AUDIO_PLUGIN_ONLY 313 314 315 #endif // __ComponentBase_h__ 316