1 /*
2      File: ComponentBase.h
3  Abstract: Part of CoreAudio Utility Classes
4   Version: 1.1
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) 2014 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 
184 	// There are situations (11844772) where we need to be able to release the lock early.
185 	class Unlocker {
186 	public:
Unlocker()187 		Unlocker()
188 		{
189 			pthread_mutex_unlock(&sComponentOpenMutex);
190 		}
~Unlocker()191 		~Unlocker()
192 		{
193 			pthread_mutex_lock(&sComponentOpenMutex);
194 		}
195 	};
196 
197 private:
198 	static pthread_mutex_t sComponentOpenMutex;
199 	static pthread_once_t sOnce;
200 	static void InitComponentInitLocker();
201 
202 #elif TARGET_OS_WIN32
203 public:
204 	bool sNeedsUnlocking;
205 	ComponentInitLocker() { sNeedsUnlocking = sComponentOpenGuard.Lock(); }
206 	~ComponentInitLocker() { if(sNeedsUnlocking) { sComponentOpenGuard.Unlock(); } }
207 private:
208 	static CAGuard	sComponentOpenGuard;
209 #endif
210 
211 private:
212 	ComponentBase::EInstanceType	mPreviousNewInstanceType;
213 };
214 
215 /*! @class AudioComponentPlugInInstance */
216 struct AudioComponentPlugInInstance {
217 	AudioComponentPlugInInterface		mPlugInInterface;
218 	void *								(*mConstruct)(void *memory, AudioComponentInstance ci);
219 	void								(*mDestruct)(void *memory);
220 	void *								mPad[2];				// pad to a 16-byte boundary (in either 32 or 64 bit mode)
221 	UInt32								mInstanceStorage;		// the ACI implementation object is constructed into this memory
222 																// this member is just a placeholder. it is aligned to a 16byte boundary
223 };
224 
225 /*! @class APFactory */
226 template <class APMethodLookup, class Implementor>
227 class APFactory {
228 public:
Construct(void * memory,AudioComponentInstance compInstance)229 	static void *Construct(void *memory, AudioComponentInstance compInstance)
230 	{
231 		return new(memory) Implementor(compInstance);
232 	}
233 
Destruct(void * memory)234 	static void Destruct(void *memory)
235 	{
236 		((Implementor *)memory)->~Implementor();
237 	}
238 
239 	// This is the AudioComponentFactoryFunction. It returns an AudioComponentPlugInInstance.
240 	// The actual implementation object is not created until Open().
Factory(const AudioComponentDescription *)241 	static AudioComponentPlugInInterface *Factory(const AudioComponentDescription * /* inDesc */)
242 	{
243 		AudioComponentPlugInInstance *acpi =
244 				(AudioComponentPlugInInstance *)malloc( offsetof(AudioComponentPlugInInstance, mInstanceStorage) + sizeof(Implementor) );
245 		acpi->mPlugInInterface.Open = ComponentBase::AP_Open;
246 		acpi->mPlugInInterface.Close = ComponentBase::AP_Close;
247 		acpi->mPlugInInterface.Lookup = APMethodLookup::Lookup;
248 		acpi->mPlugInInterface.reserved = NULL;
249 		acpi->mConstruct = Construct;
250 		acpi->mDestruct = Destruct;
251 		acpi->mPad[0] = NULL;
252 		acpi->mPad[1] = NULL;
253 		return (AudioComponentPlugInInterface*)acpi;
254 	}
255 
256 	// This is for runtime registration (not for plug-ins loaded from bundles).
257 	static AudioComponent Register(UInt32 type, UInt32 subtype, UInt32 manuf, CFStringRef name, UInt32 vers, UInt32 flags=0)
258 	{
259 		AudioComponentDescription desc = { type, subtype, manuf, flags, 0 };
260 		return AudioComponentRegister(&desc, name, vers, Factory);
261 	}
262 };
263 
264 #if !CA_USE_AUDIO_PLUGIN_ONLY
265 /*! @class ComponentEntryPoint
266  *	@discussion This is only used for a component manager version
267 */
268 template <class Class>
269 class ComponentEntryPoint {
270 public:
271 	/*! @method Dispatch */
Dispatch(ComponentParameters * params,Class * obj)272 	static OSStatus Dispatch(ComponentParameters *params, Class *obj)
273 	{
274 		OSStatus result = noErr;
275 
276 		try {
277 			if (params->what == kComponentOpenSelect) {
278 				// solve a host of initialization thread safety issues.
279 				ComponentInitLocker lock;
280 
281 				ComponentBase::sNewInstanceType = ComponentBase::kComponentMgrInstance;
282 				ComponentInstance ci = (ComponentInstance)(params->params[0]);
283 				Class *This = new Class((AudioComponentInstance)ci);
284 				This->PostConstructor();	// allows base class to do additional initialization
285 											// once the derived class is fully constructed
286 
287 				CMgr_SetComponentInstanceStorage(ci, (Handle)This);
288 			} else
289 				result = Class::ComponentEntryDispatch(params, obj);
290 		}
291 		COMPONENT_CATCH
292 
293 		return result;
294 	}
295 
296 	/*! @method Register */
Register(OSType compType,OSType subType,OSType manufacturer)297 	static Component Register(OSType compType, OSType subType, OSType manufacturer)
298 	{
299 		ComponentDescription	description = {compType, subType, manufacturer, 0, 0};
300 		Component	component = RegisterComponent(&description, (ComponentRoutineUPP) Dispatch, registerComponentGlobal, NULL, NULL, NULL);
301 		if (component != NULL) {
302 			SetDefaultComponent(component, defaultComponentAnyFlagsAnyManufacturerAnySubType);
303 		}
304 		return component;
305 	}
306 };
307 
308 // NOTE: Component Mgr is deprecated in ML.
309 // this macro should not be used with new audio components
310 // it is only for backwards compatibility with Lion and SL.
311 // this macro registers both a plugin and a component mgr version.
312 #define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \
313     extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \
314     extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \
315         return ComponentEntryPoint<Class>::Dispatch(params, obj); \
316     } \
317     extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \
318     extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \
319         return FactoryType<Class>::Factory(inDesc); \
320     }
321     // the only component we still support are the carbon based view components
322     // you should be using this macro now to exclusively register those types
323 #define VIEW_COMPONENT_ENTRY(Class) \
324     extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \
325     extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \
326         return ComponentEntryPoint<Class>::Dispatch(params, obj); \
327     }
328 
329 	/*! @class ComponentRegistrar */
330 template <class Class, OSType Type, OSType Subtype, OSType Manufacturer>
331 class ComponentRegistrar {
332 public:
333 	/*! @ctor ComponentRegistrar */
ComponentRegistrar()334 	ComponentRegistrar() { ComponentEntryPoint<Class>::Register(Type, Subtype, Manufacturer); }
335 };
336 
337 #define	COMPONENT_REGISTER(Class,Type,Subtype,Manufacturer) \
338 	static ComponentRegistrar<Class, Type, Subtype, Manufacturer>	gRegistrar##Class
339 #else
340 #define COMPONENT_ENTRY(Class)
341 #define COMPONENT_REGISTER(Class)
342 // this macro is used to generate the Entry Point for a given Audio Plugin
343 // you should be using this macro now with audio components
344 #define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \
345     extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \
346     extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \
347         return FactoryType<Class>::Factory(inDesc); \
348     }
349 
350 #endif // !CA_USE_AUDIO_PLUGIN_ONLY
351 
352 
353 #endif // __ComponentBase_h__
354