1 /*
2      File: CAAudioUnit.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 __CAAudioUnit_h__
48 #define __CAAudioUnit_h__
49 
50 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
51 	#include <CoreAudio/CoreAudioTypes.h>
52 	#include <AudioUnit/AudioUnit.h>
53 	#include <AudioToolbox/AUGraph.h>
54 	#include <AudioUnit/MusicDevice.h>
55 #else
56 	#include <ConditionalMacros.h>
57 	#include <CoreAudioTypes.h>
58 	#include <AudioUnit.h>
59 	#include <MusicDevice.h>
60 	#include <AUGraph.h>
61 	#include <MusicDevice.h>
62 #endif
63 
64 #include <vector>
65 #include "CAStreamBasicDescription.h"
66 #include "CAComponent.h"
67 #include "CAAudioChannelLayout.h"
68 
69 // defined below
70 class CAAUChanHelper;
71 
72 // These constructors will NOT throw exceptions - so "check" after creation if AU IsValid()
73 // The destructor will NOT automatically close the AU down
74 // This state should be managed by the Caller
75 // once closed, the unit represented by this object is no longer valid
76 // it is up to the user of this object to ensure its validity is in sync
77 // if it is removed from a graph
78 
79 // methods that can significantly change the state of the AU (like its format) are
80 // NOT const whereas those that don't change the externally related state of the AU are not const
81 
82 class CAAudioUnit {
83 	enum {
84 		paramErr = -50,
85 		badComponentSelector = (long)0x80008002
86 	};
87 public:
88 	typedef std::vector<AudioChannelLayoutTag> 	ChannelTagVector;
89 	typedef ChannelTagVector::iterator 			ChannelTagVectorIter;
90 
91 public:
CAAudioUnit()92 							CAAudioUnit ()
93 								: mDataPtr(0) {}
94 
95 							CAAudioUnit (const AudioUnit& inUnit);
96 
97 							CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit);
98 
CAAudioUnit(const CAAudioUnit & y)99 							CAAudioUnit (const CAAudioUnit& y)
100 								: mDataPtr(0) { *this = y; }
101 
102 	static OSStatus			Open (const CAComponent& inComp, CAAudioUnit &outUnit);
103 
104 							~CAAudioUnit ();
105 
106 	void					Close ();
107 
108 
109 	CAAudioUnit&			operator= (const CAAudioUnit& y);
110 
111 	bool					operator== (const CAAudioUnit& y) const;
112 
113 	bool					operator== (const AudioUnit& y) const;
114 
115 #pragma mark __State Management
116 	bool					IsValid () const;
117 
118 	AudioUnit				AU() const;
AudioUnit()119 	operator AudioUnit () const { return AU(); }
120 
Comp()121 	const CAComponent&		Comp() const { return mComp; }
122 
Desc()123 	const CAComponentDescription& Desc() const { return mComp.Desc(); }
124 
FromAUGraph()125 	bool					FromAUGraph () const { return GetAUNode() != 0 && GetAUNode() != kCAAU_DoNotKnowIfAUNode; }
126 
127 	AUNode					GetAUNode () const;
AUNode()128 	operator AUNode () const { return GetAUNode(); }
129 
130 #pragma mark __API Wrapper
Initialize()131 	OSStatus				Initialize() const {
132 								return AudioUnitInitialize(AU());
133 							}
Uninitialize()134 	OSStatus				Uninitialize() const {
135 								return AudioUnitUninitialize(AU());
136 							}
GetPropertyInfo(AudioUnitPropertyID propID,AudioUnitScope scope,AudioUnitElement element,UInt32 * outDataSize,Boolean * outWritable)137 	OSStatus				GetPropertyInfo(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element,
138 											UInt32 *outDataSize, Boolean *outWritable) const
139 							{
140 								return AudioUnitGetPropertyInfo(AU(), propID, scope, element, outDataSize, outWritable);
141 							}
GetProperty(AudioUnitPropertyID propID,AudioUnitScope scope,AudioUnitElement element,void * outData,UInt32 * ioDataSize)142 	OSStatus				GetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element,
143 											void *outData, UInt32 *ioDataSize) const
144 							{
145 								return AudioUnitGetProperty(AU(), propID, scope, element, outData, ioDataSize);
146 							}
SetProperty(AudioUnitPropertyID propID,AudioUnitScope scope,AudioUnitElement element,const void * inData,UInt32 inDataSize)147 	OSStatus				SetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element,
148 											const void *inData, UInt32 inDataSize)
149 							{
150 								return AudioUnitSetProperty(AU(), propID, scope, element, inData, inDataSize);
151 							}
152 	OSStatus				SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
153 											Float32 value, UInt32 bufferOffsetFrames=0);
154 
155 	OSStatus				GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
156 											Float32 &outValue) const;
157 
158 	OSStatus				Render (AudioUnitRenderActionFlags 				* ioActionFlags,
159 												const AudioTimeStamp 		* inTimeStamp,
160 												UInt32						inOutputBusNumber,
161 												UInt32						inNumberFrames,
162 												AudioBufferList				* ioData);
163 
164 	OSStatus				Process (AudioUnitRenderActionFlags 			& ioActionFlags,
165 												const AudioTimeStamp 		& inTimeStamp,
166 												UInt32						inNumberFrames,
167 												AudioBufferList				& ioData);
168 
169 	OSStatus				ProcessMultiple (AudioUnitRenderActionFlags 	& ioActionFlags,
170 												const AudioTimeStamp		& inTimeStamp,
171 												UInt32						inNumberFrames,
172 												UInt32						inNumberInputBufferLists,
173 												const AudioBufferList **	inInputBufferLists,
174 												UInt32						inNumberOutputBufferLists,
175 												AudioBufferList **			ioOutputBufferLists);
176 
177 
Reset(AudioUnitScope scope,AudioUnitElement element)178 	OSStatus				Reset (AudioUnitScope scope, AudioUnitElement element)
179 							{
180 								return AudioUnitReset (AU(), scope, element);
181 							}
GlobalReset()182 	OSStatus				GlobalReset ()
183 							{
184 								return AudioUnitReset (AU(), kAudioUnitScope_Global, 0);
185 							}
186 
AddRenderNotify(AURenderCallback inProc,void * inProcRefCon)187 	OSStatus				AddRenderNotify (AURenderCallback   inProc, void *inProcRefCon)
188 							{
189 								return AudioUnitAddRenderNotify (AU(), inProc, inProcRefCon);
190 							}
191 
RemoveRenderNotify(AURenderCallback inProc,void * inProcRefCon)192 	OSStatus				RemoveRenderNotify (AURenderCallback   inProc, void *inProcRefCon)
193 							{
194 								return AudioUnitRemoveRenderNotify (AU(), inProc, inProcRefCon);
195 							}
196 
AddPropertyListener(AudioUnitPropertyID inID,AudioUnitPropertyListenerProc inProc,void * inProcRefCon)197 	OSStatus				AddPropertyListener (AudioUnitPropertyID				inID,
198 													AudioUnitPropertyListenerProc	inProc,
199 													void *							inProcRefCon)
200 							{
201 								return AudioUnitAddPropertyListener (AU(), inID, inProc, inProcRefCon);
202 							}
203 
204 	OSStatus				RemovePropertyListener (AudioUnitPropertyID				inID,
205 													AudioUnitPropertyListenerProc	inProc,
206 													void *							inProcUserData);
207 
208 	OSStatus				MIDIEvent (UInt32					inStatus,
209 										UInt32					inData1,
210 										UInt32					inData2,
211 										UInt32					inOffsetSampleFrame);
212 
213 								// uses the default VoiceForGroup value - this is the normal case
StartNote(MusicDeviceGroupID inGroupID,NoteInstanceID * outNoteInstanceID,UInt32 inOffsetSampleFrame,const MusicDeviceNoteParams * inParams)214 	OSStatus				StartNote (MusicDeviceGroupID		inGroupID,
215 									NoteInstanceID *			outNoteInstanceID,
216 									UInt32						inOffsetSampleFrame,
217 									const MusicDeviceNoteParams * inParams)
218 							{
219 								return StartNote (kMusicNoteEvent_UseGroupInstrument,
220 													inGroupID, outNoteInstanceID,
221 													inOffsetSampleFrame, inParams);
222 							}
223 
224 	OSStatus				StartNote (MusicDeviceInstrumentID	inInstrument,
225 									MusicDeviceGroupID			inGroupID,
226 									NoteInstanceID *			outNoteInstanceID,
227 									UInt32						inOffsetSampleFrame,
228 									const MusicDeviceNoteParams * inParams);
229 
230 	OSStatus				StopNote (MusicDeviceGroupID		inGroupID,
231 									NoteInstanceID				inNoteInstanceID,
232 									UInt32						inOffsetSampleFrame);
233 
234 #pragma mark __Format Utilities
235 		// typically you ask this about an AU
236 		// These Questions are asking about Input and Output...
237 
238 		// These ones just say whether an AU can do a single combination of channels
239 		// and is fine if the AU has a single output (and if an input, a single input)
CanDo(int inChannelsInOut)240 	bool					CanDo (int inChannelsInOut) const
241 							{
242 								return CanDo (inChannelsInOut, inChannelsInOut);
243 							}
244 
245 	bool					CanDo (		int 				inChannelsIn,
246 										int 				inChannelsOut) const;
247 
248 		// This version does a more thorough test for ANY AU with ANY ins/outs
249 		// you pass in the channel helper (for the current element count on that scope)
250 
251 	bool					CanDo (		const CAAUChanHelper		&input,
252 										const CAAUChanHelper		&output) const;
253 
254 	bool					SupportsNumChannels () const;
255 
256 	bool					HasChannelLayouts (AudioUnitScope 		inScope,
257 											AudioUnitElement 		inEl) const;
258 
259     int                                     GetChannelInfo (AUChannelInfo** chaninfo, UInt32& cnt);
260 	OSStatus				GetChannelLayoutTags (AudioUnitScope 	inScope,
261 									AudioUnitElement 				inEl,
262 									ChannelTagVector				&outChannelVector) const;
263 
264 	bool					HasChannelLayout (AudioUnitScope 		inScope,
265 											AudioUnitElement 		inEl) const;
266 
267 	OSStatus				GetChannelLayout (AudioUnitScope 		inScope,
268 											AudioUnitElement 		inEl,
269 											CAAudioChannelLayout	&outLayout) const;
270 
271 	OSStatus				SetChannelLayout (AudioUnitScope 		inScope,
272 											AudioUnitElement 		inEl,
273 											const CAAudioChannelLayout	&inLayout);
274 
275 	OSStatus				SetChannelLayout (AudioUnitScope 		inScope,
276 											AudioUnitElement 		inEl,
277 											const AudioChannelLayout		&inLayout,
278 											UInt32					inSize);
279 
280 	OSStatus				ClearChannelLayout (AudioUnitScope		inScope,
281 											AudioUnitElement		inEl);
282 
283 	OSStatus				GetFormat (AudioUnitScope					inScope,
284 											AudioUnitElement			inEl,
285 											AudioStreamBasicDescription	&outFormat) const;
286 	// if an AudioChannelLayout is either required or set, this call can fail
287 	// and the SetChannelLayout call should be used to set the format
288 	OSStatus				SetFormat (AudioUnitScope							inScope,
289 											AudioUnitElement					inEl,
290 											const AudioStreamBasicDescription	&inFormat);
291 
292 	OSStatus				GetSampleRate (AudioUnitScope		inScope,
293 											AudioUnitElement	inEl,
294 											Float64				&outRate) const;
295 	OSStatus				SetSampleRate (AudioUnitScope		inScope,
296 											AudioUnitElement	inEl,
297 											Float64				inRate);
298 
299 	// this sets the sample rate on all in/out buses of the AU
300 	OSStatus				SetSampleRate (Float64				inSampleRate);
301 
302 	OSStatus				NumberChannels (AudioUnitScope		inScope,
303 											AudioUnitElement	inEl,
304 											UInt32				&outChans) const;
305 
GetNumberChannels(AudioUnitScope inScope,AudioUnitElement inEl,UInt32 & outChans)306 	OSStatus				GetNumberChannels (AudioUnitScope	inScope,
307 											AudioUnitElement	inEl,
308 											UInt32				&outChans) const
309 							{
310 								return NumberChannels (inScope, inEl, outChans);
311 							}
312 
313 	OSStatus				SetNumberChannels (AudioUnitScope	inScope,
314 											AudioUnitElement	inEl,
315 											UInt32				inChans);
316 
317 	OSStatus				IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const;
318 
319 	OSStatus				GetElementCount (AudioUnitScope 	inScope, UInt32 &outCount) const;
320 
321 	OSStatus				SetElementCount (AudioUnitScope		inScope, UInt32 inCount);
322 
323 		// value of -1 for outTotalNumChannels indicates no restriction on num channels
324 		// for ex. the Matrix Mixer satisfies this (its in/out element count is writable, and can be set to
325 		// any number of channels.
326 		// outTotalNumChannels is only valid if method returns true...
HasDynamicInputs(SInt32 & outTotalNumChannels)327 	bool					HasDynamicInputs (SInt32 &outTotalNumChannels) const
328 							{
329 								return HasDynamicScope (kAudioUnitScope_Input, outTotalNumChannels);
330 							}
331 
HasDynamicOutputs(SInt32 & outTotalNumChannels)332 	bool					HasDynamicOutputs (SInt32 &outTotalNumChannels) const
333 							{
334 								return HasDynamicScope (kAudioUnitScope_Output, outTotalNumChannels);
335 							}
336 
337 		// here, if the in (or out) elements are dynamic, then you supply the number of elements
338 		// you want on in (or out) scope, and the number of channels on each consecutive element
ConfigureDynamicInput(UInt32 inNumElements,UInt32 * inChannelsPerElement,Float64 inSampleRate)339 	OSStatus				ConfigureDynamicInput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate)
340 							{
341 								return ConfigureDynamicScope (kAudioUnitScope_Input, inNumElements, inChannelsPerElement, inSampleRate);
342 							}
343 
ConfigureDynamicOutput(UInt32 inNumElements,UInt32 * inChannelsPerElement,Float64 inSampleRate)344 	OSStatus				ConfigureDynamicOutput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate)
345 							{
346 								return ConfigureDynamicScope (kAudioUnitScope_Output, inNumElements, inChannelsPerElement, inSampleRate);
347 							}
348 
349 	bool					CanBypass 		() const;
350 
351 	bool					GetBypass 		() const;
352 
353 	OSStatus				SetBypass 		(bool				inBypass) const;
354 
355 	OSStatus				GetMaxFramesPerSlice (UInt32& outMaxFrames) const;
356 
357 	OSStatus				SetMaxFramesPerSlice (UInt32 inMaxFrames);
358 
359 	Float64					Latency () const;
360 
361 		// these calls just deal with the global preset state
362 		// you could rescope them to deal with presets on the part scope
363 	OSStatus				GetAUPreset (CFPropertyListRef &outData) const;
364 
365 	OSStatus				SetAUPreset (CFPropertyListRef &inData);
366 
367 	OSStatus				SetAUPresetFromDocument (CFPropertyListRef &inData);
368 
369 	OSStatus				GetPresentPreset (AUPreset &outData) const;
370 
371 	OSStatus				SetPresentPreset (AUPreset &inData);
372 
373 	bool					HasCustomView () const;
374 
375 #pragma mark __Print
Print()376 	void					Print () const { Print (stdout); }
377 	void					Print (FILE* file) const;
378 
379 private:
380 	CAComponent				mComp;
381 
382 	class AUState;
383 	AUState*		mDataPtr;
384 
385 		// this can throw - so wrap this up in a static that returns a result code...
386 	CAAudioUnit (const CAComponent& inComp);
387 
388 	bool				HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const;
389 	OSStatus			ConfigureDynamicScope (AudioUnitScope   inScope,
390 											UInt32				inNumElements,
391 											UInt32				*inChannelsPerElement,
392 											Float64				inSampleRate);
393 	bool				ValidateChannelPair (int 				inChannelsIn,
394 											int 				inChannelsOut,
395 											const AUChannelInfo * info,
396 											UInt32				numChanInfo) const;
397 
398 	bool				ValidateDynamicScope (AudioUnitScope	inScope,
399 											SInt32				&outTotalNumChannels,
400 											const AUChannelInfo * info,
401 											UInt32 numInfo) const;
402 	bool				CheckOneSide (const CAAUChanHelper		&inHelper,
403 											bool				checkOutput,
404 											const AUChannelInfo *info,
405 											UInt32				numInfo) const;
406 	enum {
407 			kCAAU_DoNotKnowIfAUNode = -1
408 	};
409 };
410 
411 class CAAUChanHelper {
412 public:
CAAUChanHelper()413 				CAAUChanHelper()
414 					: mChans(mStaticChans), mNumEls(0), mDidAllocate(false)
415 				{
416 					memset (mChans, 0, sizeof(UInt32) * kStaticElCount);
417 				}
418 				CAAUChanHelper(UInt32 inMaxElems);
419 				CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope);
CAAUChanHelper(const CAAUChanHelper & c)420 				CAAUChanHelper (const CAAUChanHelper &c)
421 					: mChans(mStaticChans), mNumEls(0), mDidAllocate(false)
422 					{ *this = c; }
423 
424 				~CAAUChanHelper();
425 
426 	CAAUChanHelper& operator= (const CAAUChanHelper &c);
427 
428 	UInt32		* mChans;
429 	UInt32		mNumEls;
430 
431 private:
432 	enum {
433 		kStaticElCount = 8
434 	};
435 	UInt32 mStaticChans[kStaticElCount];
436 	bool mDidAllocate;
437 };
438 
439 #endif
440