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