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