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 #include "AUBase.h"
10 #include "AUDispatch.h"
11 #include "AUInputElement.h"
12 #include "AUOutputElement.h"
13 #include <algorithm>
14 #include <syslog.h>
15 #include "CAAudioChannelLayout.h"
16 #include "CAHostTimeBase.h"
17 #include "CAVectorUnit.h"
18 #include "CAXException.h"
19 
20 #if TARGET_OS_MAC && (TARGET_CPU_X86 || TARGET_CPU_X86_64)
21 	// our compiler does ALL floating point with SSE
GETCSR()22 	inline int  GETCSR ()    { int _result; asm volatile ("stmxcsr %0" : "=m" (*&_result) ); return _result; }
SETCSR(int a)23 	inline void SETCSR (int a)    { int _temp = a; asm volatile( "ldmxcsr %0" : : "m" (*&_temp ) ); }
24 
25 	#define DISABLE_DENORMALS int _savemxcsr = GETCSR(); SETCSR(_savemxcsr | 0x8040);
26 	#define RESTORE_DENORMALS SETCSR(_savemxcsr);
27 #else
28 	#define DISABLE_DENORMALS
29 	#define RESTORE_DENORMALS
30 #endif
31 
32 static bool sAUBaseCFStringsInitialized = false;
33 // this is used for the presets
34 static CFStringRef kUntitledString = NULL;
35 //these are the current keys for the class info document
36 static CFStringRef kVersionString = NULL;
37 static CFStringRef kTypeString = NULL;
38 static CFStringRef kSubtypeString = NULL;
39 static CFStringRef kManufacturerString = NULL;
40 static CFStringRef kDataString = NULL;
41 static CFStringRef kNameString = NULL;
42 static CFStringRef kRenderQualityString = NULL;
43 static CFStringRef kCPULoadString = NULL;
44 static CFStringRef kElementNameString = NULL;
45 static CFStringRef kPartString = NULL;
46 
47 SInt32 AUBase::sVectorUnitType = kVecUninitialized;
48 
49 //_____________________________________________________________________________
50 //
AUBase(AudioComponentInstance inInstance,UInt32 numInputElements,UInt32 numOutputElements,UInt32 numGroupElements)51 AUBase::AUBase(	AudioComponentInstance			inInstance,
52 				UInt32							numInputElements,
53 				UInt32							numOutputElements,
54 				UInt32							numGroupElements) :
55 	ComponentBase(inInstance),
56 	mElementsCreated(false),
57 	mInitialized(false),
58 	mHasBegunInitializing(false),
59 	mInitNumInputEls(numInputElements), mInitNumOutputEls(numOutputElements),
60 #if !CA_BASIC_AU_FEATURES
61 	mInitNumGroupEls(numGroupElements),
62 #endif
63 	mRenderCallbacksTouched(false),
64 	mRenderThreadID (NULL),
65 	mWantsRenderThreadID (false),
66 	mLastRenderError(0),
67 	mUsesFixedBlockSize(false),
68 	mBuffersAllocated(false),
69 	mLogString (NULL),
70     mNickName (NULL),
71 	mAUMutex(NULL)
72 	#if !CA_NO_AU_UI_FEATURES
73 		,
74 		mContextName(NULL)
75 	#endif
76 {
77 	ResetRenderTime ();
78 
79 	if(!sAUBaseCFStringsInitialized)
80 	{
81 		kUntitledString = CFSTR("Untitled");
82 		kVersionString = CFSTR(kAUPresetVersionKey);
83 		kTypeString = CFSTR(kAUPresetTypeKey);
84 		kSubtypeString = CFSTR(kAUPresetSubtypeKey);
85 		kManufacturerString = CFSTR(kAUPresetManufacturerKey);
86 		kDataString = CFSTR(kAUPresetDataKey);
87 		kNameString = CFSTR(kAUPresetNameKey);
88 		kRenderQualityString = CFSTR(kAUPresetRenderQualityKey);
89 		kCPULoadString = CFSTR(kAUPresetCPULoadKey);
90 		kElementNameString = CFSTR(kAUPresetElementNameKey);
91 		kPartString = CFSTR(kAUPresetPartKey);
92 		sAUBaseCFStringsInitialized = true;
93 	}
94 
95 	if (sVectorUnitType == kVecUninitialized) {
96 		sVectorUnitType = CAVectorUnit::GetVectorUnitType() ;
97 	}
98 
99 	mAudioUnitAPIVersion = 2;
100 
101 	SetMaxFramesPerSlice(kAUDefaultMaxFramesPerSlice);
102 
103 	GlobalScope().Initialize(this, kAudioUnitScope_Global, 1);
104 
105 #if !CA_NO_AU_UI_FEATURES
106 	memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo));
107 #endif
108 
109 
110 	mCurrentPreset.presetNumber = -1;
111 	mCurrentPreset.presetName = kUntitledString;
112 	CFRetain (mCurrentPreset.presetName);
113 }
114 
115 //_____________________________________________________________________________
116 //
~AUBase()117 AUBase::~AUBase()
118 {
119 	if (mCurrentPreset.presetName) CFRelease (mCurrentPreset.presetName);
120 #if !CA_NO_AU_UI_FEATURES
121 	if (mContextName) CFRelease (mContextName);
122 #endif
123 	if (mLogString) delete [] mLogString;
124     if (mNickName) CFRelease(mNickName);
125 }
126 
127 //_____________________________________________________________________________
128 //
CreateElements()129 void	AUBase::CreateElements()
130 {
131 	if (!mElementsCreated) {
132 		Inputs().Initialize(this, kAudioUnitScope_Input, mInitNumInputEls);
133 		Outputs().Initialize(this, kAudioUnitScope_Output, mInitNumOutputEls);
134 #if !CA_BASIC_AU_FEATURES
135 		Groups().Initialize(this, kAudioUnitScope_Group, mInitNumGroupEls);
136 #endif
137 		CreateExtendedElements();
138 
139 		mElementsCreated = true;
140 	}
141 }
142 
143 //_____________________________________________________________________________
144 //
SetMaxFramesPerSlice(UInt32 nFrames)145 void	AUBase::SetMaxFramesPerSlice(UInt32 nFrames)
146 {
147 	mMaxFramesPerSlice = nFrames;
148 	if (mBuffersAllocated)
149 		ReallocateBuffers();
150 	PropertyChanged(kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0);
151 }
152 
153 //_____________________________________________________________________________
154 //
CanSetMaxFrames() const155 OSStatus			AUBase::CanSetMaxFrames() const
156 {
157 	return IsInitialized() ? kAudioUnitErr_Initialized : OSStatus(noErr);
158 }
159 
160 //_____________________________________________________________________________
161 //
ReallocateBuffers()162 void				AUBase::ReallocateBuffers()
163 {
164 	CreateElements();
165 
166 	UInt32 nOutputs = Outputs().GetNumberOfElements();
167 	for (UInt32 i = 0; i < nOutputs; ++i) {
168 		AUOutputElement *output = GetOutput(i);
169 		output->AllocateBuffer();	// does no work if already allocated
170 	}
171 	UInt32 nInputs = Inputs().GetNumberOfElements();
172 	for (UInt32 i = 0; i < nInputs; ++i) {
173 		AUInputElement *input = GetInput(i);
174 		input->AllocateBuffer();	// does no work if already allocated
175 	}
176 	mBuffersAllocated = true;
177 }
178 
179 //_____________________________________________________________________________
180 //
DeallocateIOBuffers()181 void				AUBase::DeallocateIOBuffers()
182 {
183 	if (!mBuffersAllocated)
184 		return;
185 
186 	UInt32 nOutputs = Outputs().GetNumberOfElements();
187 	for (UInt32 i = 0; i < nOutputs; ++i) {
188 		AUOutputElement *output = GetOutput(i);
189 		output->DeallocateBuffer();
190 	}
191 	UInt32 nInputs = Inputs().GetNumberOfElements();
192 	for (UInt32 i = 0; i < nInputs; ++i) {
193 		AUInputElement *input = GetInput(i);
194 		input->DeallocateBuffer();
195 	}
196 	mBuffersAllocated = false;
197 }
198 
199 //_____________________________________________________________________________
200 //
DoInitialize()201 OSStatus			AUBase::DoInitialize()
202 {
203 	OSStatus result = noErr;
204 
205 	if (!mInitialized) {
206 		result = Initialize();
207 		if (result == noErr) {
208 			if (CanScheduleParameters())
209 				mParamList.reserve(24);
210 			mHasBegunInitializing = true;
211 			ReallocateBuffers();	// calls CreateElements()
212 			mInitialized = true;	// signal that it's okay to render
213 			CAMemoryBarrier();
214 		}
215 	}
216 
217 	return result;
218 }
219 
220 //_____________________________________________________________________________
221 //
Initialize()222 OSStatus			AUBase::Initialize()
223 {
224 	return noErr;
225 }
226 
227 //_____________________________________________________________________________
228 //
PreDestructor()229 void				AUBase::PreDestructor()
230 {
231 	// this is called from the ComponentBase dispatcher, which doesn't know anything about our (optional) lock
232 	CAMutex::Locker lock(mAUMutex);
233 	DoCleanup();
234 }
235 
236 //_____________________________________________________________________________
237 //
DoCleanup()238 void				AUBase::DoCleanup()
239 {
240 	if (mInitialized)
241 		Cleanup();
242 
243 	DeallocateIOBuffers();
244 	ResetRenderTime ();
245 
246 	mInitialized = false;
247 	mHasBegunInitializing = false;
248 }
249 
250 //_____________________________________________________________________________
251 //
Cleanup()252 void				AUBase::Cleanup()
253 {
254 }
255 
256 //_____________________________________________________________________________
257 //
Reset(AudioUnitScope inScope,AudioUnitElement inElement)258 OSStatus			AUBase::Reset(					AudioUnitScope 					inScope,
259 													AudioUnitElement 				inElement)
260 {
261 	ResetRenderTime ();
262 	return noErr;
263 }
264 
265 //_____________________________________________________________________________
266 //
DispatchGetPropertyInfo(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,UInt32 & outDataSize,Boolean & outWritable)267 OSStatus			AUBase::DispatchGetPropertyInfo(AudioUnitPropertyID				inID,
268 													AudioUnitScope					inScope,
269 													AudioUnitElement				inElement,
270 													UInt32 &						outDataSize,
271 													Boolean &						outWritable)
272 {
273 	OSStatus result = noErr;
274 	bool validateElement = true;
275 
276 	switch (inID) {
277 	case kAudioUnitProperty_MakeConnection:
278 		ca_require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global, InvalidScope);
279 		outDataSize = sizeof(AudioUnitConnection);
280 		outWritable = true;
281 		break;
282 
283 
284 	case kAudioUnitProperty_SetRenderCallback:
285 		ca_require(AudioUnitAPIVersion() > 1, InvalidProperty);
286 		ca_require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global, InvalidScope);
287 		outDataSize = sizeof(AURenderCallbackStruct);
288 		outWritable = true;
289 		break;
290 
291 	case kAudioUnitProperty_StreamFormat:
292 		outDataSize = sizeof(CAStreamBasicDescription);
293 		outWritable = IsStreamFormatWritable(inScope, inElement);
294 		break;
295 
296 	case kAudioUnitProperty_SampleRate:
297 		outDataSize = sizeof(Float64);
298 		outWritable = IsStreamFormatWritable(inScope, inElement);
299 		break;
300 
301 	case kAudioUnitProperty_ClassInfo:
302 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
303 		outDataSize = sizeof(CFPropertyListRef);
304 		outWritable = true;
305 		break;
306 
307 	case kAudioUnitProperty_FactoryPresets:
308 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
309 		result = GetPresets(NULL);
310 		if (!result) {
311 			outDataSize = sizeof(CFArrayRef);
312 			outWritable = false;
313 		}
314 		break;
315 
316 	case kAudioUnitProperty_PresentPreset:
317 #if !CA_USE_AUDIO_PLUGIN_ONLY
318 #ifndef __LP64__
319 	case kAudioUnitProperty_CurrentPreset:
320 #endif
321 #endif
322 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
323 		outDataSize = sizeof(AUPreset);
324 		outWritable = true;
325 		break;
326 
327 	case kAudioUnitProperty_ElementName:
328 		outDataSize = sizeof (CFStringRef);
329 		outWritable = true;
330 		break;
331 
332 	case kAudioUnitProperty_ParameterList:
333 		{
334 			UInt32 nparams = 0;
335 			result = GetParameterList(inScope, NULL, nparams);
336 
337 			outDataSize = sizeof(AudioUnitParameterID) * nparams;
338 			outWritable = false;
339 			validateElement = false;
340 		}
341 		break;
342 
343 	case kAudioUnitProperty_ParameterInfo:
344 		outDataSize = sizeof(AudioUnitParameterInfo);
345 		outWritable = false;
346 		validateElement = false;
347 		break;
348 
349 	case kAudioUnitProperty_ParameterHistoryInfo:
350 		outDataSize = sizeof(AudioUnitParameterHistoryInfo);
351 		outWritable = false;
352 		validateElement = false;
353 		break;
354 
355 	case kAudioUnitProperty_ElementCount:
356 		outDataSize = sizeof(UInt32);
357 		outWritable = BusCountWritable(inScope);
358 		validateElement = false;
359 		break;
360 
361 	case kAudioUnitProperty_Latency:
362 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
363 		outDataSize = sizeof(Float64);
364 		outWritable = false;
365 		break;
366 
367 	case kAudioUnitProperty_TailTime:
368 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
369 		if (SupportsTail()) {
370 			outDataSize = sizeof(Float64);
371 			outWritable = false;
372 		} else
373 			goto InvalidProperty;
374 		break;
375 
376 	case kAudioUnitProperty_MaximumFramesPerSlice:
377 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
378 		outDataSize = sizeof(UInt32);
379 		outWritable = true;
380 		break;
381 
382 	case kAudioUnitProperty_LastRenderError:
383 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
384 		outDataSize = sizeof(OSStatus);
385 		outWritable = false;
386 		break;
387 
388 	case kAudioUnitProperty_SupportedNumChannels:
389 	{
390 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
391 		UInt32 num = SupportedNumChannels (NULL);
392 		if (num) {
393 			outDataSize = sizeof (AUChannelInfo) * num;
394 			result = noErr;
395 		} else
396 			goto InvalidProperty;
397 		outWritable = false;
398 		break;
399 	}
400 
401 	case kAudioUnitProperty_SupportedChannelLayoutTags:
402 	{
403 		UInt32 numLayouts = GetChannelLayoutTags(inScope, inElement, NULL);
404 		if (numLayouts) {
405 			outDataSize = numLayouts * sizeof(AudioChannelLayoutTag);
406 			result = noErr;
407 		} else
408 			goto InvalidProperty;
409 		outWritable = false;
410 		validateElement = false; //already done it
411 		break;
412 	}
413 
414 	case kAudioUnitProperty_AudioChannelLayout:
415 	{
416 		outWritable = false;
417 		outDataSize = GetAudioChannelLayout(inScope, inElement, NULL, outWritable);
418 		if (outDataSize) {
419 			result = noErr;
420 		} else {
421 			if (GetChannelLayoutTags(inScope, inElement, NULL) == 0)
422 				goto InvalidProperty;
423 			else
424 				result = kAudioUnitErr_InvalidPropertyValue;
425 		}
426 		validateElement = false; //already done it
427 		break;
428 	}
429 
430 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE
431 	case kAudioUnitProperty_ShouldAllocateBuffer:
432 		ca_require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output), InvalidScope);
433 		outWritable = true;
434 		outDataSize = sizeof(UInt32);
435 		break;
436 #endif
437 
438 #if !CA_USE_AUDIO_PLUGIN_ONLY
439 	case kAudioUnitProperty_FastDispatch:
440 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
441 		if (!IsCMgrObject()) goto InvalidProperty;
442 		outDataSize = sizeof(void *);
443 		outWritable = false;
444 		validateElement = false;
445 		break;
446 
447 	case kAudioUnitProperty_GetUIComponentList:
448 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
449 		outDataSize = GetNumCustomUIComponents();
450 		if (outDataSize == 0)
451 			goto InvalidProperty;
452 		outDataSize *= sizeof (AudioComponentDescription);
453 
454 		outWritable = false;
455 		break;
456 #endif
457 
458 	case kAudioUnitProperty_ParameterValueStrings:
459 		result = GetParameterValueStrings(inScope, inElement, NULL);
460 		if (result == noErr) {
461 			outDataSize = sizeof(CFArrayRef);
462 			outWritable = false;
463 			validateElement = false;
464 		}
465 		break;
466 
467 #if !CA_NO_AU_HOST_CALLBACKS
468 	case kAudioUnitProperty_HostCallbacks:
469 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
470 		outDataSize = sizeof(mHostCallbackInfo);
471 		outWritable = true;
472 		break;
473 #endif
474 #if !CA_NO_AU_UI_FEATURES
475 	case kAudioUnitProperty_ContextName:
476 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
477 		outDataSize = sizeof(CFStringRef);
478 		outWritable = true;
479 		break;
480 
481 	case kAudioUnitProperty_IconLocation:
482 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
483 		outWritable = false;
484 		if (!HasIcon())
485 			goto InvalidProperty;
486 		outDataSize = sizeof(CFURLRef);
487 		break;
488 
489 	case kAudioUnitProperty_ParameterClumpName:
490 		outDataSize = sizeof(AudioUnitParameterNameInfo );
491 		outWritable = false;
492 		break;
493 
494 #endif // !CA_NO_AU_UI_FEATURES
495 
496 	case 'lrst' :  // kAudioUnitProperty_LastRenderedSampleTime
497 		outDataSize = sizeof(Float64);
498 		outWritable = false;
499 		break;
500 
501     case kAudioUnitProperty_NickName:
502         ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
503         outDataSize = sizeof(CFStringRef);
504         outWritable = true;
505         break;
506 
507 	default:
508 		result = GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);
509 		validateElement = false;
510 		break;
511 	}
512 
513 	if (result == noErr && validateElement) {
514 		ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
515 	}
516 
517 	return result;
518 InvalidProperty:
519 	return kAudioUnitErr_InvalidProperty;
520 InvalidScope:
521 	return kAudioUnitErr_InvalidScope;
522 InvalidElement:
523 	return kAudioUnitErr_InvalidElement;
524 }
525 
526 //_____________________________________________________________________________
527 //
DispatchGetProperty(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,void * outData)528 OSStatus			AUBase::DispatchGetProperty(	AudioUnitPropertyID 			inID,
529 													AudioUnitScope 					inScope,
530 													AudioUnitElement			 	inElement,
531 													void *							outData)
532 {
533 	// NOTE: We're currently only called from AUBase::ComponentEntryDispatch, which
534 	// calls DispatchGetPropertyInfo first, which performs validation of the scope/element,
535 	// and ensures that the outData buffer is non-null and large enough.
536 	OSStatus result = noErr;
537 
538 	switch (inID) {
539 	case kAudioUnitProperty_StreamFormat:
540 		*(CAStreamBasicDescription *)outData = GetStreamFormat(inScope, inElement);
541 		break;
542 
543 	case kAudioUnitProperty_SampleRate:
544 		*(Float64 *)outData = GetStreamFormat(inScope, inElement).mSampleRate;
545 		break;
546 
547 	case kAudioUnitProperty_ParameterList:
548 		{
549 			UInt32 nparams = 0;
550 			result = GetParameterList(inScope, (AudioUnitParameterID *)outData, nparams);
551 		}
552 		break;
553 
554 	case kAudioUnitProperty_ParameterInfo:
555 		result = GetParameterInfo(inScope, inElement, *(AudioUnitParameterInfo *)outData);
556 		break;
557 
558 	case kAudioUnitProperty_ParameterHistoryInfo:
559 		{
560 			AudioUnitParameterHistoryInfo* info = (AudioUnitParameterHistoryInfo*)outData;
561 			result = GetParameterHistoryInfo(inScope, inElement, info->updatesPerSecond, info->historyDurationInSeconds);
562 		}
563 		break;
564 
565 	case kAudioUnitProperty_ClassInfo:
566 		{
567 			*(CFPropertyListRef *)outData = NULL;
568 			result = SaveState((CFPropertyListRef *)outData);
569 		}
570 		break;
571 
572 	case kAudioUnitProperty_FactoryPresets:
573 		{
574 			*(CFArrayRef *)outData = NULL;
575 			result = GetPresets ((CFArrayRef *)outData);
576 		}
577 		break;
578 
579 	case kAudioUnitProperty_PresentPreset:
580 #if !CA_USE_AUDIO_PLUGIN_ONLY
581 #ifndef __LP64__
582 	case kAudioUnitProperty_CurrentPreset:
583 #endif
584 #endif
585 		{
586 			*(AUPreset *)outData = mCurrentPreset;
587 
588 				// retain current string (as client owns a reference to it and will release it)
589 			if (inID == kAudioUnitProperty_PresentPreset && mCurrentPreset.presetName)
590 				CFRetain (mCurrentPreset.presetName);
591 
592 			result = noErr;
593 		}
594 		break;
595 
596 	case kAudioUnitProperty_ElementName:
597 		{
598 			AUElement * element = GetElement(inScope, inElement);
599 			if (element->HasName()) {
600 				*(CFStringRef *)outData = element->GetName();
601 				CFRetain (element->GetName());
602 				result = noErr;
603 			} else
604 				result = kAudioUnitErr_InvalidPropertyValue;
605 		}
606 		break;
607 
608 	case kAudioUnitProperty_ElementCount:
609 		*(UInt32 *)outData = GetScope(inScope).GetNumberOfElements();
610 		break;
611 
612 	case kAudioUnitProperty_Latency:
613 		*(Float64 *)outData = GetLatency();
614 		break;
615 
616 	case kAudioUnitProperty_TailTime:
617 		if (SupportsTail())
618 			*(Float64 *)outData = GetTailTime();
619 		else
620 			result = kAudioUnitErr_InvalidProperty;
621 		break;
622 
623 	case kAudioUnitProperty_MaximumFramesPerSlice:
624 		*(UInt32 *)outData = mMaxFramesPerSlice;
625 		break;
626 
627 	case kAudioUnitProperty_LastRenderError:
628 		*(OSStatus *)outData = mLastRenderError;
629 		mLastRenderError = 0;
630 		break;
631 
632 	case kAudioUnitProperty_SupportedNumChannels:
633 		{
634 			const AUChannelInfo* infoPtr = NULL;
635 			UInt32 num = SupportedNumChannels (&infoPtr);
636 			if(num != 0 && infoPtr != NULL)
637 				memcpy (outData, infoPtr, num * sizeof (AUChannelInfo));
638 		}
639 		break;
640 
641 	case kAudioUnitProperty_SupportedChannelLayoutTags:
642 		{
643 			AudioChannelLayoutTag* ptr = outData ? static_cast<AudioChannelLayoutTag*>(outData) : NULL;
644 			UInt32 numLayouts = GetChannelLayoutTags (inScope, inElement, ptr);
645 			if (numLayouts == 0)
646 				result = kAudioUnitErr_InvalidProperty;
647 		}
648 		break;
649 
650 	case kAudioUnitProperty_AudioChannelLayout:
651 	{
652 		AudioChannelLayout* ptr = outData ? static_cast<AudioChannelLayout*>(outData) : NULL;
653 		Boolean writable;
654 		UInt32 dataSize = GetAudioChannelLayout(inScope, inElement, ptr, writable);
655 		if (!dataSize) {
656 			result = kAudioUnitErr_InvalidProperty;
657 		}
658 		break;
659 	}
660 
661 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE
662 	case kAudioUnitProperty_ShouldAllocateBuffer:
663 	{
664 		AUIOElement * element = GetIOElement(inScope, inElement);
665 		*(UInt32*)outData = element->WillAllocateBuffer();
666 		break;
667 	}
668 #endif
669 
670  	case kAudioUnitProperty_ParameterValueStrings:
671 		result = GetParameterValueStrings(inScope, inElement, (CFArrayRef *)outData);
672 		break;
673 
674 #if !CA_USE_AUDIO_PLUGIN_ONLY
675 	case kAudioUnitProperty_FastDispatch:
676 		if (!IsCMgrObject()) result = kAudioUnitErr_InvalidProperty;
677 		else {
678 			switch (inElement) {
679 			case kAudioUnitGetParameterSelect:
680 				*(AudioUnitGetParameterProc *)outData = (AudioUnitGetParameterProc)CMgr_AudioUnitBaseGetParameter;
681 				break;
682 			case kAudioUnitSetParameterSelect:
683 				*(AudioUnitSetParameterProc *)outData = (AudioUnitSetParameterProc)CMgr_AudioUnitBaseSetParameter;
684 				break;
685 			case kAudioUnitRenderSelect:
686 				if (AudioUnitAPIVersion() > 1)
687 					*(AudioUnitRenderProc *)outData = (AudioUnitRenderProc)CMgr_AudioUnitBaseRender;
688 				else result = kAudioUnitErr_InvalidElement;
689 				break;
690 			default:
691 				result = GetProperty(inID, inScope, inElement, outData);
692 				break;
693 			}
694 		}
695 		break;
696 
697 	case kAudioUnitProperty_GetUIComponentList:
698 		GetUIComponentDescs ((ComponentDescription*)outData);
699 		break;
700 #endif
701 
702 #if !CA_NO_AU_HOST_CALLBACKS
703 	case kAudioUnitProperty_HostCallbacks:
704 		memcpy(outData, &mHostCallbackInfo, sizeof(mHostCallbackInfo));
705 		break;
706 #endif
707 #if !CA_NO_AU_UI_FEATURES
708 	case kAudioUnitProperty_ContextName:
709 		*(CFStringRef *)outData = mContextName;
710 		if (mContextName) {
711 			CFRetain(mContextName);
712 			// retain CFString (if exists) since client will be responsible for its release
713 			result = noErr;
714 		} else {
715 			result = kAudioUnitErr_InvalidPropertyValue;
716 		}
717 		break;
718 
719 	case kAudioUnitProperty_IconLocation:
720 		{
721 			CFURLRef iconLocation = CopyIconLocation();
722 			if (iconLocation) {
723 				*(CFURLRef*)outData = iconLocation;
724 			} else
725 				result = kAudioUnitErr_InvalidProperty;
726 		}
727 		break;
728 
729 	case kAudioUnitProperty_ParameterClumpName:
730 		{
731 			AudioUnitParameterNameInfo * ioClumpInfo = (AudioUnitParameterNameInfo*) outData;
732 			if (ioClumpInfo->inID == kAudioUnitClumpID_System)	// this ID value is reserved
733 				result = kAudioUnitErr_InvalidPropertyValue;
734 			else
735 			{
736 				result = CopyClumpName(inScope, ioClumpInfo->inID, ioClumpInfo->inDesiredLength, &ioClumpInfo->outName);
737 
738 					// this is provided for compatibility with existing implementations that don't know
739 					// about this new mechanism
740 				if (result == kAudioUnitErr_InvalidProperty)
741 					result = GetProperty (inID, inScope, inElement, outData);
742 			}
743 		}
744 		break;
745 
746 #endif  // !CA_NO_AU_UI_FEATURES
747 
748 	case 'lrst' : // kAudioUnitProperty_LastRenderedSampleTime
749 		*(Float64*)outData = mCurrentRenderTime.mSampleTime;
750 		break;
751 
752     case kAudioUnitProperty_NickName:
753         // Ownership follows Core Foundation's 'Copy Rule'
754         if (mNickName) CFRetain(mNickName);
755         *(CFStringRef*)outData = mNickName;
756         break;
757 
758 	default:
759 		result = GetProperty(inID, inScope, inElement, outData);
760 		break;
761 	}
762 	return result;
763 }
764 
765 
766 //_____________________________________________________________________________
767 //
DispatchSetProperty(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,const void * inData,UInt32 inDataSize)768 OSStatus			AUBase::DispatchSetProperty(	AudioUnitPropertyID 			inID,
769 													AudioUnitScope 					inScope,
770 													AudioUnitElement 				inElement,
771 													const void *					inData,
772 													UInt32 							inDataSize)
773 {
774 	OSStatus result = noErr;
775 
776 	switch (inID) {
777 	case kAudioUnitProperty_MakeConnection:
778 		ca_require(inDataSize >= sizeof(AudioUnitConnection), InvalidPropertyValue);
779 		{
780 			AudioUnitConnection &connection = *(AudioUnitConnection *)inData;
781 			result = SetConnection(connection);
782 		}
783 		break;
784 
785 
786 	case kAudioUnitProperty_SetRenderCallback:
787 		{
788 			ca_require(inDataSize >= sizeof(AURenderCallbackStruct), InvalidPropertyValue);
789 			ca_require(AudioUnitAPIVersion() > 1, InvalidProperty);
790 			AURenderCallbackStruct &callback = *(AURenderCallbackStruct*)inData;
791 			result = SetInputCallback(kAudioUnitProperty_SetRenderCallback, inElement, callback.inputProc, callback.inputProcRefCon);
792 		}
793 		break;
794 
795 	case kAudioUnitProperty_ElementCount:
796 		ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue);
797 		ca_require(BusCountWritable(inScope), NotWritable);
798 		result = SetBusCount(inScope, *(UInt32*)inData);
799 		if (result == noErr) {
800 			PropertyChanged(inID, inScope, inElement);
801 		}
802 		break;
803 
804 	case kAudioUnitProperty_MaximumFramesPerSlice:
805 		ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue);
806 		result = CanSetMaxFrames();
807 		if (result) return result;
808 		SetMaxFramesPerSlice(*(UInt32 *)inData);
809 		break;
810 
811 	case kAudioUnitProperty_StreamFormat:
812 		{
813 			if (inDataSize < 36) goto InvalidPropertyValue;
814 			ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
815 
816 			CAStreamBasicDescription newDesc;
817 				// now we're going to be ultra conservative! because of discrepancies between
818 				// sizes of this struct based on aligment padding inconsistencies
819 			memset (&newDesc, 0, sizeof(newDesc));
820 			memcpy (&newDesc, inData, 36);
821 
822 			ca_require(SanityCheck(newDesc), InvalidFormat);
823 
824 			ca_require(ValidFormat(inScope, inElement, newDesc), InvalidFormat);
825 
826 			const CAStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement);
827 
828 			if ( !curDesc.IsExactlyEqual(newDesc) ) {
829 				ca_require(IsStreamFormatWritable(inScope, inElement), NotWritable);
830 				result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);
831 			}
832 		}
833 		break;
834 
835 	case kAudioUnitProperty_SampleRate:
836 		{
837 			ca_require(inDataSize == sizeof(Float64), InvalidPropertyValue);
838 			ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
839 
840 			const CAStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement);
841 			CAStreamBasicDescription newDesc = curDesc;
842 			newDesc.mSampleRate = *(Float64 *)inData;
843 
844 			ca_require(ValidFormat(inScope, inElement, newDesc), InvalidFormat);
845 
846 			if ( !curDesc.IsExactlyEqual(newDesc) ) {
847 				ca_require(IsStreamFormatWritable(inScope, inElement), NotWritable);
848 				result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);
849 			}
850 		}
851 		break;
852 
853 	case kAudioUnitProperty_AudioChannelLayout:
854 		{
855 			const AudioChannelLayout *layout = static_cast<const AudioChannelLayout *>(inData);
856 			size_t headerSize = sizeof(AudioChannelLayout) - sizeof(AudioChannelDescription);
857 
858 			ca_require(inDataSize >= headerSize + layout->mNumberChannelDescriptions * sizeof(AudioChannelDescription), InvalidPropertyValue);
859 			result = SetAudioChannelLayout(inScope, inElement, layout);
860 			if (result == noErr)
861 				PropertyChanged(inID, inScope, inElement);
862 			break;
863 		}
864 
865 	case kAudioUnitProperty_ClassInfo:
866 		ca_require(inDataSize == sizeof(CFPropertyListRef *), InvalidPropertyValue);
867 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
868 		result = RestoreState(*(CFPropertyListRef *)inData);
869 		break;
870 
871 	case kAudioUnitProperty_PresentPreset:
872 #if !CA_USE_AUDIO_PLUGIN_ONLY
873 #ifndef __LP64__
874 	case kAudioUnitProperty_CurrentPreset:
875 #endif
876 #endif
877 		{
878 			ca_require(inDataSize == sizeof(AUPreset), InvalidPropertyValue);
879 			ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
880 			AUPreset & newPreset = *(AUPreset *)inData;
881 
882 			if (newPreset.presetNumber >= 0)
883 			{
884 				result = NewFactoryPresetSet(newPreset);
885 				// NewFactoryPresetSet SHOULD call SetAFactoryPreset if the preset is valid
886 				// from its own list of preset number->name
887 				if (!result)
888 					PropertyChanged(inID, inScope, inElement);
889 			}
890 			else if (newPreset.presetName)
891 			{
892 				result = NewCustomPresetSet(newPreset);
893                 if (!result)
894                     PropertyChanged(inID, inScope, inElement);
895 			}
896 			else
897 				result = kAudioUnitErr_InvalidPropertyValue;
898 		}
899 		break;
900 
901 	case kAudioUnitProperty_ElementName:
902 		{
903 			ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
904 			ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue);
905 			AUElement * element = GetScope(inScope).GetElement (inElement);
906 			element->SetName (*(CFStringRef *)inData);
907 			PropertyChanged(inID, inScope, inElement);
908 		}
909 		break;
910 
911 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE
912 	case kAudioUnitProperty_ShouldAllocateBuffer:
913 		{
914 			ca_require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output), InvalidScope);
915 			ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
916 			ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue);
917 			ca_require(!IsInitialized(), Initialized);
918 
919 			AUIOElement * element = GetIOElement(inScope, inElement);
920 			element->SetWillAllocateBuffer(*(UInt32 *)inData != 0);
921 		}
922 		break;
923 #endif
924 
925 #if !CA_NO_AU_HOST_CALLBACKS
926 	case kAudioUnitProperty_HostCallbacks:
927 	{
928 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
929 		UInt32 availSize = std::min(inDataSize, (UInt32)sizeof(HostCallbackInfo));
930 		bool hasChanged = !memcmp (&mHostCallbackInfo, inData, availSize);
931 		memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo));
932 		memcpy (&mHostCallbackInfo, inData, availSize);
933 		if (hasChanged)
934 			PropertyChanged(inID, inScope, inElement);
935 		break;
936 	}
937 #endif
938 #if !CA_NO_AU_UI_FEATURES
939 	case kAudioUnitProperty_SetExternalBuffer:
940 		ca_require(inDataSize >= sizeof(AudioUnitExternalBuffer), InvalidPropertyValue);
941 		ca_require(IsInitialized(), Uninitialized);
942 		{
943 			AudioUnitExternalBuffer &buf = *(AudioUnitExternalBuffer*)inData;
944 			if (intptr_t(buf.buffer) & 0x0F) result = kAudio_ParamError;
945 			else if (inScope == kAudioUnitScope_Input) {
946 				AUInputElement *input = GetInput(inElement);
947 				input->UseExternalBuffer(buf);
948 			} else {
949 				AUOutputElement *output = GetOutput(inElement);
950 				output->UseExternalBuffer(buf);
951 			}
952 		}
953 		break;
954 
955 	case kAudioUnitProperty_ContextName:
956 		{
957 			ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue);
958 			ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
959 			CFStringRef inStr = *(CFStringRef *)inData;
960 			if (mContextName) CFRelease(mContextName);
961 			if (inStr) CFRetain(inStr);
962 			mContextName = inStr;
963 			PropertyChanged(inID, inScope, inElement);
964 		}
965 		break;
966 
967 #endif // !CA_NO_AU_UI_FEATURES
968 
969     case kAudioUnitProperty_NickName:
970     {
971 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
972         ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue);
973         CFStringRef inStr = *(CFStringRef *)inData;
974         if (mNickName) CFRelease(mNickName);
975         if (inStr) CFRetain(inStr);
976         mNickName = inStr;
977         PropertyChanged(inID, inScope, inElement);
978         break;
979     }
980 
981 	default:
982 		result = SetProperty(inID, inScope, inElement, inData, inDataSize);
983 		if (result == noErr)
984 			PropertyChanged(inID, inScope, inElement);
985 
986 		break;
987 	}
988 	return result;
989 NotWritable:
990 	return kAudioUnitErr_PropertyNotWritable;
991 InvalidFormat:
992 	return kAudioUnitErr_FormatNotSupported;
993 #if !CA_NO_AU_UI_FEATURES
994 Uninitialized:
995 	return kAudioUnitErr_Uninitialized;
996 #endif
997 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || CA_USE_AUDIO_PLUGIN_ONLY
998 Initialized:
999 	return kAudioUnitErr_Initialized;
1000 #endif
1001 InvalidScope:
1002 	return kAudioUnitErr_InvalidScope;
1003 InvalidProperty:
1004 	return kAudioUnitErr_InvalidProperty;
1005 InvalidPropertyValue:
1006 	return kAudioUnitErr_InvalidPropertyValue;
1007 InvalidElement:
1008 	return kAudioUnitErr_InvalidElement;
1009 }
1010 
1011 //_____________________________________________________________________________
1012 //
DispatchRemovePropertyValue(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement)1013 OSStatus			AUBase::DispatchRemovePropertyValue (AudioUnitPropertyID		inID,
1014 													AudioUnitScope 					inScope,
1015 													AudioUnitElement 				inElement)
1016 {
1017 	OSStatus result = noErr;
1018 	switch (inID)
1019 	{
1020 	case kAudioUnitProperty_AudioChannelLayout:
1021 	{
1022 		result = RemoveAudioChannelLayout(inScope, inElement);
1023 		if (result == noErr)
1024 			PropertyChanged(inID, inScope, inElement);
1025 		break;
1026 	}
1027 
1028 #if !CA_NO_AU_HOST_CALLBACKS
1029 	case kAudioUnitProperty_HostCallbacks:
1030 	{
1031 		ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
1032 		bool hasValue = false;
1033 		void* ptr = &mHostCallbackInfo;
1034 		for (unsigned int i = 0; i <  sizeof (HostCallbackInfo); ++i) {
1035 			if (static_cast<char*>(ptr)[i]) {
1036 				hasValue = true;
1037 				break;
1038 			}
1039 		}
1040 		if (hasValue) {
1041 			memset (&mHostCallbackInfo, 0, sizeof (HostCallbackInfo));
1042 			PropertyChanged(inID, inScope, inElement);
1043 		}
1044 		break;
1045 	}
1046 #endif
1047 #if !CA_NO_AU_UI_FEATURES
1048 	case kAudioUnitProperty_ContextName:
1049 		if (mContextName) CFRelease(mContextName);
1050 		mContextName = NULL;
1051 		result = noErr;
1052 		break;
1053 
1054 #endif // !CA_NO_AU_UI_FEATURES
1055 
1056     case kAudioUnitProperty_NickName:
1057     {
1058         if(inScope == kAudioUnitScope_Global) {
1059             if (mNickName) CFRelease(mNickName);
1060             mNickName = NULL;
1061             PropertyChanged(inID, inScope, inElement);
1062         } else {
1063             result = kAudioUnitErr_InvalidScope;
1064         }
1065         break;
1066     }
1067 
1068 	default:
1069 		result = RemovePropertyValue (inID, inScope, inElement);
1070 		break;
1071 	}
1072 
1073 	return result;
1074 #if !CA_NO_AU_UI_FEATURES || !CA_NO_AU_HOST_CALLBACKS
1075 InvalidScope:
1076 	return kAudioUnitErr_InvalidScope;
1077 #endif
1078 }
1079 
1080 //_____________________________________________________________________________
1081 //
GetPropertyInfo(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,UInt32 & outDataSize,Boolean & outWritable)1082 OSStatus			AUBase::GetPropertyInfo(		AudioUnitPropertyID				inID,
1083 													AudioUnitScope					inScope,
1084 													AudioUnitElement				inElement,
1085 													UInt32 &						outDataSize,
1086 													Boolean &						outWritable)
1087 {
1088 	return kAudioUnitErr_InvalidProperty;
1089 }
1090 
1091 
1092 //_____________________________________________________________________________
1093 //
GetProperty(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,void * outData)1094 OSStatus			AUBase::GetProperty(			AudioUnitPropertyID 			inID,
1095 													AudioUnitScope 					inScope,
1096 													AudioUnitElement			 	inElement,
1097 													void *							outData)
1098 {
1099 	return kAudioUnitErr_InvalidProperty;
1100 }
1101 
1102 
1103 //_____________________________________________________________________________
1104 //
SetProperty(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,const void * inData,UInt32 inDataSize)1105 OSStatus			AUBase::SetProperty(			AudioUnitPropertyID 			inID,
1106 													AudioUnitScope 					inScope,
1107 													AudioUnitElement 				inElement,
1108 													const void *					inData,
1109 													UInt32 							inDataSize)
1110 {
1111 	return kAudioUnitErr_InvalidProperty;
1112 }
1113 
1114 //_____________________________________________________________________________
1115 //
RemovePropertyValue(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement)1116 OSStatus			AUBase::RemovePropertyValue (	AudioUnitPropertyID		 		inID,
1117 													AudioUnitScope 					inScope,
1118 													AudioUnitElement 				inElement)
1119 {
1120 	return kAudioUnitErr_InvalidPropertyValue;
1121 }
1122 
1123 //_____________________________________________________________________________
1124 //
AddPropertyListener(AudioUnitPropertyID inID,AudioUnitPropertyListenerProc inProc,void * inProcRefCon)1125 OSStatus			AUBase::AddPropertyListener(	AudioUnitPropertyID				inID,
1126 													AudioUnitPropertyListenerProc	inProc,
1127 													void *							inProcRefCon)
1128 {
1129 	PropertyListener pl;
1130 
1131 	pl.propertyID = inID;
1132 	pl.listenerProc = inProc;
1133 	pl.listenerRefCon = inProcRefCon;
1134 
1135 	if (mPropertyListeners.empty())
1136 		mPropertyListeners.reserve(32);
1137 	mPropertyListeners.push_back(pl);
1138 
1139 	return noErr;
1140 }
1141 
1142 //_____________________________________________________________________________
1143 //
RemovePropertyListener(AudioUnitPropertyID inID,AudioUnitPropertyListenerProc inProc,void * inProcRefCon,bool refConSpecified)1144 OSStatus			AUBase::RemovePropertyListener(		AudioUnitPropertyID				inID,
1145 														AudioUnitPropertyListenerProc	inProc,
1146 														void *							inProcRefCon,
1147 														bool							refConSpecified)
1148 {
1149 	// iterate in reverse so that it's safe to erase in the middle of the vector
1150 	for (int i = (int)mPropertyListeners.size(); --i >=0; ) {
1151 		PropertyListeners::iterator it = mPropertyListeners.begin() + i;
1152 		if ((*it).propertyID == inID && (*it).listenerProc == inProc && (!refConSpecified || (*it).listenerRefCon == inProcRefCon))
1153 			mPropertyListeners.erase(it);
1154 	}
1155 	return noErr;
1156 }
1157 
1158 //_____________________________________________________________________________
1159 //
PropertyChanged(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement)1160 void				AUBase::PropertyChanged(			AudioUnitPropertyID				inID,
1161 														AudioUnitScope					inScope,
1162 														AudioUnitElement				inElement)
1163 {
1164 	for (PropertyListeners::iterator it = mPropertyListeners.begin(); it != mPropertyListeners.end(); ++it)
1165 		if ((*it).propertyID == inID)
1166 			((*it).listenerProc)((*it).listenerRefCon, mComponentInstance, inID, inScope, inElement);
1167 }
1168 
1169 //_____________________________________________________________________________
1170 //
SetRenderNotification(AURenderCallback inProc,void * inRefCon)1171 OSStatus			AUBase::SetRenderNotification(	AURenderCallback		 		inProc,
1172 													void *							inRefCon)
1173 {
1174 	if (inProc == NULL)
1175 		return kAudio_ParamError;
1176 
1177 	mRenderCallbacksTouched = true;
1178 	mRenderCallbacks.deferred_add(RenderCallback(inProc, inRefCon));
1179 			// this will do nothing if it's already in the list
1180 	return noErr;
1181 }
1182 
1183 //_____________________________________________________________________________
1184 //
RemoveRenderNotification(AURenderCallback inProc,void * inRefCon)1185 OSStatus			AUBase::RemoveRenderNotification(	AURenderCallback			inProc,
1186 														void *						inRefCon)
1187 {
1188 	mRenderCallbacks.deferred_remove(RenderCallback(inProc, inRefCon));
1189 	return noErr;	// error?
1190 }
1191 
1192 //_____________________________________________________________________________
1193 //
GetParameter(AudioUnitParameterID inID,AudioUnitScope inScope,AudioUnitElement inElement,AudioUnitParameterValue & outValue)1194 OSStatus 	AUBase::GetParameter(			AudioUnitParameterID			inID,
1195 													AudioUnitScope 					inScope,
1196 													AudioUnitElement 				inElement,
1197 													AudioUnitParameterValue &		outValue)
1198 {
1199 	AUElement *elem = SafeGetElement(inScope, inElement);
1200 	outValue = elem->GetParameter(inID);
1201 	return noErr;
1202 }
1203 
1204 
1205 //_____________________________________________________________________________
1206 //
SetParameter(AudioUnitParameterID inID,AudioUnitScope inScope,AudioUnitElement inElement,AudioUnitParameterValue inValue,UInt32 inBufferOffsetInFrames)1207 OSStatus 	AUBase::SetParameter(			AudioUnitParameterID			inID,
1208 													AudioUnitScope 					inScope,
1209 													AudioUnitElement 				inElement,
1210 													AudioUnitParameterValue			inValue,
1211 													UInt32							inBufferOffsetInFrames)
1212 {
1213 	AUElement *elem = SafeGetElement(inScope, inElement);
1214 	elem->SetParameter(inID, inValue);
1215 	return noErr;
1216 }
1217 
1218 //_____________________________________________________________________________
1219 //
ScheduleParameter(const AudioUnitParameterEvent * inParameterEvent,UInt32 inNumEvents)1220 OSStatus 	AUBase::ScheduleParameter (	const AudioUnitParameterEvent 		*inParameterEvent,
1221 													UInt32							inNumEvents)
1222 {
1223 	bool canScheduleParameters = CanScheduleParameters();
1224 
1225 	for (UInt32 i = 0; i < inNumEvents; ++i)
1226 	{
1227 		if (inParameterEvent[i].eventType == kParameterEvent_Immediate)
1228 		{
1229 			SetParameter (inParameterEvent[i].parameter,
1230 							inParameterEvent[i].scope,
1231 							inParameterEvent[i].element,
1232 							inParameterEvent[i].eventValues.immediate.value,
1233 							inParameterEvent[i].eventValues.immediate.bufferOffset);
1234 		}
1235 		if (canScheduleParameters) {
1236 			mParamList.push_back (inParameterEvent[i]);
1237 		}
1238 	}
1239 
1240 	return noErr;
1241 }
1242 
1243 // ____________________________________________________________________________
1244 //
SortParameterEventList(const AudioUnitParameterEvent & ev1,const AudioUnitParameterEvent & ev2)1245 static bool SortParameterEventList(const AudioUnitParameterEvent &ev1, const AudioUnitParameterEvent &ev2 )
1246 {
1247 	int offset1 = ev1.eventType == kParameterEvent_Immediate ?  ev1.eventValues.immediate.bufferOffset : ev1.eventValues.ramp.startBufferOffset;
1248 	int offset2 = ev2.eventType == kParameterEvent_Immediate ?  ev2.eventValues.immediate.bufferOffset : ev2.eventValues.ramp.startBufferOffset;
1249 
1250 	if(offset1 < offset2) return true;
1251 	return false;
1252 }
1253 
1254 
1255 // ____________________________________________________________________________
1256 //
ProcessForScheduledParams(ParameterEventList & inParamList,UInt32 inFramesToProcess,void * inUserData)1257 OSStatus 	AUBase::ProcessForScheduledParams(	ParameterEventList		&inParamList,
1258 														UInt32					inFramesToProcess,
1259 														void					*inUserData )
1260 {
1261 	OSStatus result = noErr;
1262 
1263 	int totalFramesToProcess = inFramesToProcess;
1264 
1265 	int framesRemaining = totalFramesToProcess;
1266 
1267 	unsigned int currentStartFrame = 0;	// start of the whole buffer
1268 
1269 
1270 
1271 	// sort the ParameterEventList by startBufferOffset
1272 	std::sort(inParamList.begin(), inParamList.end(), SortParameterEventList);
1273 
1274 	ParameterEventList::iterator iter = inParamList.begin();
1275 
1276 
1277 	while(framesRemaining > 0 )
1278 	{
1279 		// first of all, go through the ramped automation events and find out where the next
1280 		// division of our whole buffer will be
1281 
1282 		int currentEndFrame = totalFramesToProcess;	// start out assuming we'll process all the way to
1283 													// the end of the buffer
1284 
1285 		iter = inParamList.begin();
1286 
1287 		// find the next break point
1288 		while(iter != inParamList.end() )
1289 		{
1290 			AudioUnitParameterEvent &event = *iter;
1291 
1292 			int offset = event.eventType == kParameterEvent_Immediate ?  event.eventValues.immediate.bufferOffset : event.eventValues.ramp.startBufferOffset;
1293 
1294 			if(offset > (int)currentStartFrame && offset < currentEndFrame )
1295 			{
1296 				currentEndFrame = offset;
1297 				break;
1298 			}
1299 
1300 			// consider ramp end to be a possible choice (there may be gaps in the supplied ramp events)
1301 			if(event.eventType == kParameterEvent_Ramped )
1302 			{
1303 				offset = event.eventValues.ramp.startBufferOffset + event.eventValues.ramp.durationInFrames;
1304 
1305 				if(offset > (int)currentStartFrame && offset < currentEndFrame )
1306 				{
1307 					currentEndFrame = offset;
1308 				}
1309 			}
1310 
1311 			iter++;
1312 		}
1313 
1314 		int framesThisTime = currentEndFrame - currentStartFrame;
1315 
1316 		// next, setup the parameter maps to be current for the ramp parameters active during
1317 		// this time segment...
1318 
1319 		for(ParameterEventList::iterator iter2 = inParamList.begin(); iter2 != inParamList.end(); iter2++ )
1320 		{
1321 			AudioUnitParameterEvent &event = *iter2;
1322 
1323 			bool eventFallsInSlice;
1324 
1325 
1326 			if(event.eventType == kParameterEvent_Ramped)
1327 				eventFallsInSlice = event.eventValues.ramp.startBufferOffset < currentEndFrame
1328 					&& event.eventValues.ramp.startBufferOffset + event.eventValues.ramp.durationInFrames > currentStartFrame;
1329 			else /* kParameterEvent_Immediate */
1330 				// actually, for the same parameter, there may be future immediate events which override this one,
1331 				// but it's OK since the event list is sorted in time order, we're guaranteed to end up with the current one
1332 				eventFallsInSlice = event.eventValues.immediate.bufferOffset <= currentStartFrame;
1333 
1334 			if(eventFallsInSlice)
1335 			{
1336 				AUElement *element = GetElement(event.scope, event.element );
1337 
1338 				if(element) element->SetScheduledEvent(	event.parameter,
1339 														event,
1340 														currentStartFrame,
1341 														currentEndFrame - currentStartFrame );
1342 			}
1343 		}
1344 
1345 
1346 
1347 		// Finally, actually do the processing for this slice.....
1348 
1349 		result = ProcessScheduledSlice(	inUserData,
1350 										currentStartFrame,
1351 										framesThisTime,
1352 										inFramesToProcess );
1353 
1354 		if(result != noErr) break;
1355 
1356 		framesRemaining -= framesThisTime;
1357 		currentStartFrame = currentEndFrame;	// now start from where we left off last time
1358 	}
1359 
1360 	return result;
1361 }
1362 
1363 //_____________________________________________________________________________
1364 //
SetWantsRenderThreadID(bool inFlag)1365 void				AUBase::SetWantsRenderThreadID (bool inFlag)
1366 {
1367 	if (inFlag == mWantsRenderThreadID)
1368 		return;
1369 
1370 	mWantsRenderThreadID = inFlag;
1371 	if (!mWantsRenderThreadID)
1372 		mRenderThreadID = NULL;
1373 }
1374 
1375 //_____________________________________________________________________________
1376 //
1377 
1378 //_____________________________________________________________________________
1379 //
DoRender(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inBusNumber,UInt32 inFramesToProcess,AudioBufferList & ioData)1380 OSStatus			AUBase::DoRender(		AudioUnitRenderActionFlags &	ioActionFlags,
1381 											const AudioTimeStamp &			inTimeStamp,
1382 											UInt32							inBusNumber,
1383 											UInt32							inFramesToProcess,
1384 											AudioBufferList &				ioData)
1385 {
1386 	OSStatus theError;
1387 	RenderCallbackList::iterator rcit;
1388 
1389 	AUTRACE(kCATrace_AUBaseRenderStart, mComponentInstance, (uintptr_t)this, inBusNumber, inFramesToProcess, (uintptr_t)ioData.mBuffers[0].mData);
1390 	DISABLE_DENORMALS
1391 
1392 	try {
1393 		ca_require(IsInitialized(), Uninitialized);
1394 		ca_require(mAudioUnitAPIVersion >= 2, ParamErr);
1395 		if (inFramesToProcess > mMaxFramesPerSlice) {
1396 			static UInt64 lastTimeMessagePrinted = 0;
1397 			UInt64 now = CAHostTimeBase::GetCurrentTime();
1398 			if (now - lastTimeMessagePrinted > CAHostTimeBase::GetFrequency()) { // not more than once per second.
1399 				lastTimeMessagePrinted = now;
1400 				syslog(LOG_ERR, "kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=%u, mMaxFramesPerSlice=%u", (unsigned)inFramesToProcess, (unsigned)mMaxFramesPerSlice);
1401 				DebugMessageN4("%s:%d inFramesToProcess=%u, mMaxFramesPerSlice=%u; TooManyFrames", __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)mMaxFramesPerSlice);
1402 			}
1403 			goto TooManyFrames;
1404 		}
1405 		ca_require (!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr);
1406 
1407 		AUOutputElement *output = GetOutput(inBusNumber);	// will throw if non-existent
1408 		if (output->GetStreamFormat().NumberChannelStreams() != ioData.mNumberBuffers) {
1409 			DebugMessageN4("%s:%d ioData.mNumberBuffers=%u, output->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1410 				__FILE__, __LINE__, (unsigned)ioData.mNumberBuffers, (unsigned)output->GetStreamFormat().NumberChannelStreams());
1411 			goto ParamErr;
1412 		}
1413 
1414 		unsigned expectedBufferByteSize = inFramesToProcess * output->GetStreamFormat().mBytesPerFrame;
1415 		for (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) {
1416 			AudioBuffer &buf = ioData.mBuffers[ibuf];
1417 			if (buf.mData != NULL) {
1418 				// only care about the size if the buffer is non-null
1419 				if (buf.mDataByteSize < expectedBufferByteSize) {
1420 					// if the buffer is too small, we cannot render safely. kAudio_ParamError.
1421 					DebugMessageN7("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1422 						__FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)output->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibuf, (unsigned)buf.mDataByteSize);
1423 					goto ParamErr;
1424 				}
1425 				// Some clients incorrectly pass bigger buffers than expectedBufferByteSize.
1426 				// We will generally set the buffer size at the end of rendering, before we return.
1427 				// However we should ensure that no one, DURING rendering, READS a
1428 				// potentially incorrect size. This can lead to doing too much work, or
1429 				// reading past the end of an input buffer into unmapped memory.
1430 				buf.mDataByteSize = expectedBufferByteSize;
1431 			}
1432 		}
1433 
1434 		if (WantsRenderThreadID())
1435 		{
1436 			#if TARGET_OS_MAC
1437 				mRenderThreadID = pthread_self();
1438 			#elif TARGET_OS_WIN32
1439 				mRenderThreadID = GetCurrentThreadId();
1440 			#endif
1441 		}
1442 
1443 		AudioUnitRenderActionFlags flags;
1444 		if (mRenderCallbacksTouched) {
1445 			mRenderCallbacks.update();
1446 			flags = ioActionFlags | kAudioUnitRenderAction_PreRender;
1447 			for (rcit = mRenderCallbacks.begin(); rcit != mRenderCallbacks.end(); ++rcit) {
1448 				RenderCallback &rc = *rcit;
1449 				AUTRACE(kCATrace_AUBaseRenderCallbackStart, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 1, 0);
1450 				(*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon,
1451 								&flags,
1452 								&inTimeStamp, inBusNumber, inFramesToProcess, &ioData);
1453 				AUTRACE(kCATrace_AUBaseRenderCallbackEnd, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 1, 0);
1454 			}
1455 		}
1456 
1457 		theError = DoRenderBus(ioActionFlags, inTimeStamp, inBusNumber, output, inFramesToProcess, ioData);
1458 
1459 		if (mRenderCallbacksTouched) {
1460 			flags = ioActionFlags | kAudioUnitRenderAction_PostRender;
1461 
1462 			if (SetRenderError (theError)) {
1463 				flags |= kAudioUnitRenderAction_PostRenderError;
1464 			}
1465 
1466 			for (rcit = mRenderCallbacks.begin(); rcit != mRenderCallbacks.end(); ++rcit) {
1467 				RenderCallback &rc = *rcit;
1468 				AUTRACE(kCATrace_AUBaseRenderCallbackStart, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 2, 0);
1469 				(*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon,
1470 								&flags,
1471 								&inTimeStamp, inBusNumber, inFramesToProcess, &ioData);
1472 				AUTRACE(kCATrace_AUBaseRenderCallbackEnd, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 2, 0);
1473 			}
1474 		}
1475 
1476 		// The vector's being emptied
1477 		// because these events should only apply to this Render cycle, so anything
1478 		// left over is from a preceding cycle and should be dumped.  New scheduled
1479 		// parameters must be scheduled from the next pre-render callback.
1480 		if (!mParamList.empty())
1481 			mParamList.clear();
1482 
1483 	}
1484 	catch (OSStatus err) {
1485 		theError = err;
1486 		goto errexit;
1487 	}
1488 	catch (...) {
1489 		theError = -1;
1490 		goto errexit;
1491 	}
1492 done:
1493 	RESTORE_DENORMALS
1494 	AUTRACE(kCATrace_AUBaseRenderEnd, mComponentInstance, (intptr_t)this, theError, ioActionFlags, CATrace_ablData(ioData));
1495 
1496 	return theError;
1497 
1498 Uninitialized:	theError = kAudioUnitErr_Uninitialized;				goto errexit;
1499 ParamErr:		theError = kAudio_ParamError;						goto errexit;
1500 TooManyFrames:	theError = kAudioUnitErr_TooManyFramesToProcess;	goto errexit;
1501 errexit:
1502 	DebugMessageN2 ("  from %s, render err: %d", GetLoggingString(), (int)theError);
1503 	SetRenderError(theError);
1504 	goto done;
1505 }
1506 
1507 //_____________________________________________________________________________
1508 //
DoProcess(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inFramesToProcess,AudioBufferList & ioData)1509 OSStatus	AUBase::DoProcess (	AudioUnitRenderActionFlags  &		ioActionFlags,
1510 								const AudioTimeStamp &				inTimeStamp,
1511 								UInt32								inFramesToProcess,
1512 								AudioBufferList &					ioData)
1513 {
1514 	OSStatus theError;
1515 	AUTRACE(kCATrace_AUBaseRenderStart, mComponentInstance, (intptr_t)this, -1, inFramesToProcess, 0);
1516 	DISABLE_DENORMALS
1517 
1518 	try {
1519 
1520 		if (!(ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)) {
1521 			ca_require(IsInitialized(), Uninitialized);
1522 			ca_require(inFramesToProcess <= mMaxFramesPerSlice, TooManyFrames);
1523 			ca_require(!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr);
1524 
1525 			AUInputElement *input = GetInput(0);	// will throw if non-existent
1526 			if (input->GetStreamFormat().NumberChannelStreams() != ioData.mNumberBuffers) {
1527 				DebugMessageN4("%s:%d ioData.mNumberBuffers=%u, input->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1528 					__FILE__, __LINE__, (unsigned)ioData.mNumberBuffers, (unsigned)input->GetStreamFormat().NumberChannelStreams());
1529 				goto ParamErr;
1530 			}
1531 
1532 			unsigned expectedBufferByteSize = inFramesToProcess * input->GetStreamFormat().mBytesPerFrame;
1533 			for (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) {
1534 				AudioBuffer &buf = ioData.mBuffers[ibuf];
1535 				if (buf.mData != NULL) {
1536 					// only care about the size if the buffer is non-null
1537 					if (buf.mDataByteSize < expectedBufferByteSize) {
1538 						// if the buffer is too small, we cannot render safely. kAudio_ParamError.
1539 						DebugMessageN7("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1540 							__FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)input->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibuf, (unsigned)buf.mDataByteSize);
1541 						goto ParamErr;
1542 					}
1543 					// Some clients incorrectly pass bigger buffers than expectedBufferByteSize.
1544 					// We will generally set the buffer size at the end of rendering, before we return.
1545 					// However we should ensure that no one, DURING rendering, READS a
1546 					// potentially incorrect size. This can lead to doing too much work, or
1547 					// reading past the end of an input buffer into unmapped memory.
1548 					buf.mDataByteSize = expectedBufferByteSize;
1549 				}
1550 			}
1551 		}
1552 
1553 		if (WantsRenderThreadID())
1554 		{
1555 			#if TARGET_OS_MAC
1556 				mRenderThreadID = pthread_self();
1557 			#elif TARGET_OS_WIN32
1558 				mRenderThreadID = GetCurrentThreadId();
1559 			#endif
1560 		}
1561 
1562 		if (NeedsToRender (inTimeStamp)) {
1563 			theError = ProcessBufferLists (ioActionFlags, ioData, ioData, inFramesToProcess);
1564 		} else
1565 			theError = noErr;
1566 
1567 	}
1568 	catch (OSStatus err) {
1569 		theError = err;
1570 		goto errexit;
1571 	}
1572 	catch (...) {
1573 		theError = -1;
1574 		goto errexit;
1575 	}
1576 done:
1577 	RESTORE_DENORMALS
1578 	AUTRACE(kCATrace_AUBaseRenderEnd, mComponentInstance, (intptr_t)this, theError, ioActionFlags, CATrace_ablData(ioData));
1579 
1580 	return theError;
1581 
1582 Uninitialized:	theError = kAudioUnitErr_Uninitialized;				goto errexit;
1583 ParamErr:		theError = kAudio_ParamError;						goto errexit;
1584 TooManyFrames:	theError = kAudioUnitErr_TooManyFramesToProcess;	goto errexit;
1585 errexit:
1586 	DebugMessageN2 ("  from %s, process err: %d", GetLoggingString(), (int)theError);
1587 	SetRenderError(theError);
1588 	goto done;
1589 }
1590 
DoProcessMultiple(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inFramesToProcess,UInt32 inNumberInputBufferLists,const AudioBufferList ** inInputBufferLists,UInt32 inNumberOutputBufferLists,AudioBufferList ** ioOutputBufferLists)1591 OSStatus	AUBase::DoProcessMultiple (	AudioUnitRenderActionFlags  & ioActionFlags,
1592 							   const AudioTimeStamp &				inTimeStamp,
1593 							   UInt32								inFramesToProcess,
1594 							   UInt32								inNumberInputBufferLists,
1595 							   const AudioBufferList **				inInputBufferLists,
1596 							   UInt32								inNumberOutputBufferLists,
1597 							   AudioBufferList **					ioOutputBufferLists)
1598 {
1599 	OSStatus theError;
1600 	DISABLE_DENORMALS
1601 
1602 	try {
1603 
1604 		if (!(ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)) {
1605 			ca_require(IsInitialized(), Uninitialized);
1606 			ca_require(inFramesToProcess <= mMaxFramesPerSlice, TooManyFrames);
1607 			ca_require (!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr);
1608 
1609 			for (unsigned ibl = 0; ibl < inNumberInputBufferLists; ++ibl) {
1610 				if (inInputBufferLists[ibl] != NULL) {
1611 					AUInputElement *input = GetInput(ibl);	// will throw if non-existent
1612 					unsigned expectedBufferByteSize = inFramesToProcess * input->GetStreamFormat().mBytesPerFrame;
1613 
1614 					if (input->GetStreamFormat().NumberChannelStreams() != inInputBufferLists[ibl]->mNumberBuffers) {
1615 						DebugMessageN5("%s:%d inInputBufferLists[%u]->mNumberBuffers=%u, input->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1616 									   __FILE__, __LINE__, ibl, (unsigned)inInputBufferLists[ibl]->mNumberBuffers, (unsigned)input->GetStreamFormat().NumberChannelStreams());
1617 						goto ParamErr;
1618 					}
1619 
1620 					for (unsigned ibuf = 0; ibuf < inInputBufferLists[ibl]->mNumberBuffers; ++ibuf) {
1621 						const AudioBuffer &buf = inInputBufferLists[ibl]->mBuffers[ibuf];
1622 						if (buf.mData != NULL) {
1623 							if (buf.mDataByteSize < expectedBufferByteSize) {
1624 								// the buffer is too small
1625 								DebugMessageN8("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; inInputBufferLists[%u].mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1626 											   __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)input->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibl, ibuf, (unsigned)buf.mDataByteSize);
1627 								goto ParamErr;
1628 							}
1629 						} else {
1630 							// the buffer must exist
1631 							goto ParamErr;
1632 						}
1633 					}
1634 				} else {
1635 					// skip NULL input audio buffer list
1636 				}
1637 			}
1638 
1639 			for (unsigned obl = 0; obl < inNumberOutputBufferLists; ++obl) {
1640 				if (ioOutputBufferLists[obl] != NULL) {
1641 					AUOutputElement *output = GetOutput(obl);	// will throw if non-existent
1642 					unsigned expectedBufferByteSize = inFramesToProcess * output->GetStreamFormat().mBytesPerFrame;
1643 
1644 					if (output->GetStreamFormat().NumberChannelStreams() != ioOutputBufferLists[obl]->mNumberBuffers) {
1645 						DebugMessageN5("%s:%d ioOutputBufferLists[%u]->mNumberBuffers=%u, output->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1646 									   __FILE__, __LINE__, obl, (unsigned)ioOutputBufferLists[obl]->mNumberBuffers, (unsigned)output->GetStreamFormat().NumberChannelStreams());
1647 						goto ParamErr;
1648 					}
1649 
1650 					for (unsigned obuf = 0; obuf < ioOutputBufferLists[obl]->mNumberBuffers; ++obuf) {
1651 						AudioBuffer &buf = ioOutputBufferLists[obl]->mBuffers[obuf];
1652 						if (buf.mData != NULL) {
1653 							// only care about the size if the buffer is non-null
1654 							if (buf.mDataByteSize < expectedBufferByteSize) {
1655 								// if the buffer is too small, we cannot render safely. kAudio_ParamError.
1656 								DebugMessageN8("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioOutputBufferLists[%u]->mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1657 											   __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)output->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, obl, obuf, (unsigned)buf.mDataByteSize);
1658 								goto ParamErr;
1659 							}
1660 							// Some clients incorrectly pass bigger buffers than expectedBufferByteSize.
1661 							// We will generally set the buffer size at the end of rendering, before we return.
1662 							// However we should ensure that no one, DURING rendering, READS a
1663 							// potentially incorrect size. This can lead to doing too much work, or
1664 							// reading past the end of an input buffer into unmapped memory.
1665 							buf.mDataByteSize = expectedBufferByteSize;
1666 						}
1667 					}
1668 				} else {
1669 					// skip NULL output audio buffer list
1670 				}
1671 			}
1672 		}
1673 
1674 		if (WantsRenderThreadID())
1675 		{
1676 #if TARGET_OS_MAC
1677 			mRenderThreadID = pthread_self();
1678 #elif TARGET_OS_WIN32
1679 			mRenderThreadID = GetCurrentThreadId();
1680 #endif
1681 		}
1682 
1683 		if (NeedsToRender (inTimeStamp)) {
1684 			theError = ProcessMultipleBufferLists (ioActionFlags, inFramesToProcess, inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists, ioOutputBufferLists);
1685 		} else
1686 			theError = noErr;
1687 	}
1688 	catch (OSStatus err) {
1689 		theError = err;
1690 		goto errexit;
1691 	}
1692 	catch (...) {
1693 		theError = -1;
1694 		goto errexit;
1695 	}
1696 done:
1697 	RESTORE_DENORMALS
1698 
1699 	return theError;
1700 
1701 Uninitialized:	theError = kAudioUnitErr_Uninitialized;				goto errexit;
1702 ParamErr:		theError = kAudio_ParamError;						goto errexit;
1703 TooManyFrames:	theError = kAudioUnitErr_TooManyFramesToProcess;	goto errexit;
1704 errexit:
1705 	DebugMessageN2 ("  from %s, processmultiple err: %d", GetLoggingString(), (int)theError);
1706 	SetRenderError(theError);
1707 	goto done;
1708 }
1709 
1710 //_____________________________________________________________________________
1711 //
SetInputCallback(UInt32 inPropertyID,AudioUnitElement inElement,AURenderCallback inProc,void * inRefCon)1712 OSStatus			AUBase::SetInputCallback(		UInt32							inPropertyID,
1713 													AudioUnitElement 				inElement,
1714 													AURenderCallback				inProc,
1715 													void *							inRefCon)
1716 {
1717 	AUInputElement *input = GetInput(inElement);	// may throw
1718 
1719 	input->SetInputCallback(inProc, inRefCon);
1720 	PropertyChanged(inPropertyID, kAudioUnitScope_Input, inElement);
1721 
1722 	return noErr;
1723 }
1724 
1725 //_____________________________________________________________________________
1726 //
SetConnection(const AudioUnitConnection & inConnection)1727 OSStatus			AUBase::SetConnection(			const AudioUnitConnection &		inConnection)
1728 {
1729 
1730 	OSStatus err;
1731 	AUInputElement *input = GetInput(inConnection.destInputNumber);	// may throw
1732 
1733 	if (inConnection.sourceAudioUnit) {
1734 		// connecting, not disconnecting
1735 		CAStreamBasicDescription sourceDesc;
1736 		UInt32 size = sizeof(CAStreamBasicDescription);
1737 		ca_require_noerr(err = AudioUnitGetProperty(
1738 										inConnection.sourceAudioUnit,
1739 										kAudioUnitProperty_StreamFormat,
1740 										kAudioUnitScope_Output,
1741 										inConnection.sourceOutputNumber,
1742 										&sourceDesc,
1743 										&size), errexit);
1744 		ca_require_noerr(err = DispatchSetProperty (kAudioUnitProperty_StreamFormat,
1745 								kAudioUnitScope_Input, inConnection.destInputNumber,
1746 								&sourceDesc, sizeof(CAStreamBasicDescription)), errexit);
1747 	}
1748 	input->SetConnection(inConnection);
1749 
1750 	PropertyChanged(kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, inConnection.destInputNumber);
1751 	return noErr;
1752 
1753 errexit:
1754 	return err;
1755 }
1756 
1757 //_____________________________________________________________________________
1758 //
SupportedNumChannels(const AUChannelInfo ** outInfo)1759 UInt32				AUBase::SupportedNumChannels (	const AUChannelInfo** 			outInfo)
1760 {
1761 	return 0;
1762 }
1763 
1764 //_____________________________________________________________________________
1765 //
ValidFormat(AudioUnitScope inScope,AudioUnitElement inElement,const CAStreamBasicDescription & inNewFormat)1766 bool				AUBase::ValidFormat(			AudioUnitScope					inScope,
1767 													AudioUnitElement				inElement,
1768 													const CAStreamBasicDescription &		inNewFormat)
1769 {
1770 	bool isInterleaved = false;
1771 
1772 	return inNewFormat.IsCommonFloat32(&isInterleaved) && !isInterleaved;
1773 }
1774 
1775 //_____________________________________________________________________________
1776 //
IsStreamFormatWritable(AudioUnitScope scope,AudioUnitElement element)1777 bool				AUBase::IsStreamFormatWritable(	AudioUnitScope					scope,
1778 													AudioUnitElement				element)
1779 {
1780 	switch (scope) {
1781 	case kAudioUnitScope_Input:
1782 		{
1783 			AUInputElement *input = GetInput(element);
1784 			if (input->HasConnection()) return false;	// can't write format when input comes from connection
1785 		}
1786 		// ... fall ...
1787 	case kAudioUnitScope_Output:
1788 		return StreamFormatWritable(scope, element);
1789 
1790 //#warning "aliasing of global scope format should be pushed to subclasses"
1791 	case kAudioUnitScope_Global:
1792 		return StreamFormatWritable(kAudioUnitScope_Output, 0);
1793 	}
1794 	return false;
1795 }
1796 
1797 //_____________________________________________________________________________
1798 //
1799 const CAStreamBasicDescription &
GetStreamFormat(AudioUnitScope inScope,AudioUnitElement inElement)1800 					AUBase::GetStreamFormat(		AudioUnitScope					inScope,
1801 													AudioUnitElement				inElement)
1802 {
1803 //#warning "aliasing of global scope format should be pushed to subclasses"
1804 	AUIOElement *element;
1805 
1806 	switch (inScope) {
1807 	case kAudioUnitScope_Input:
1808 		element = Inputs().GetIOElement(inElement);
1809 		break;
1810 	case kAudioUnitScope_Output:
1811 		element = Outputs().GetIOElement(inElement);
1812 		break;
1813 	case kAudioUnitScope_Global:	// global stream description is an alias for that of output 0
1814 		element = Outputs().GetIOElement(0);
1815 		break;
1816 	default:
1817 		COMPONENT_THROW(kAudioUnitErr_InvalidScope);
1818 	}
1819 	return element->GetStreamFormat();
1820 }
1821 
SetBusCount(AudioUnitScope inScope,UInt32 inCount)1822 OSStatus			AUBase::SetBusCount(	AudioUnitScope					inScope,
1823 											UInt32 							inCount)
1824 {
1825 	if (IsInitialized())
1826 		return kAudioUnitErr_Initialized;
1827 
1828 	GetScope(inScope).SetNumberOfElements(inCount);
1829 	return noErr;
1830 }
1831 
1832 //_____________________________________________________________________________
1833 //
ChangeStreamFormat(AudioUnitScope inScope,AudioUnitElement inElement,const CAStreamBasicDescription & inPrevFormat,const CAStreamBasicDescription & inNewFormat)1834 OSStatus			AUBase::ChangeStreamFormat(		AudioUnitScope					inScope,
1835 													AudioUnitElement				inElement,
1836 													const CAStreamBasicDescription & inPrevFormat,
1837 													const CAStreamBasicDescription & inNewFormat)
1838 {
1839 	if (inNewFormat.IsExactlyEqual(inPrevFormat))
1840 		return noErr;
1841 
1842 //#warning "aliasing of global scope format should be pushed to subclasses"
1843 	AUIOElement *element;
1844 
1845 	switch (inScope) {
1846 	case kAudioUnitScope_Input:
1847 		element = Inputs().GetIOElement(inElement);
1848 		break;
1849 	case kAudioUnitScope_Output:
1850 		element = Outputs().GetIOElement(inElement);
1851 		break;
1852 	case kAudioUnitScope_Global:
1853 		element = Outputs().GetIOElement(0);
1854 		break;
1855 	default:
1856 		COMPONENT_THROW(kAudioUnitErr_InvalidScope);
1857 	}
1858 	element->SetStreamFormat(inNewFormat);
1859 	PropertyChanged(kAudioUnitProperty_StreamFormat, inScope, inElement);
1860 	return noErr;
1861 }
1862 
GetChannelLayoutTags(AudioUnitScope inScope,AudioUnitElement inElement,AudioChannelLayoutTag * outLayoutTags)1863 UInt32		AUBase::GetChannelLayoutTags(	AudioUnitScope				inScope,
1864 											AudioUnitElement 			inElement,
1865 											AudioChannelLayoutTag *		outLayoutTags)
1866 {
1867 	return GetIOElement(inScope, inElement)->GetChannelLayoutTags(outLayoutTags);
1868 }
1869 
GetAudioChannelLayout(AudioUnitScope scope,AudioUnitElement element,AudioChannelLayout * outLayoutPtr,Boolean & outWritable)1870 UInt32		AUBase::GetAudioChannelLayout(	AudioUnitScope				scope,
1871 											AudioUnitElement 			element,
1872 											AudioChannelLayout *		outLayoutPtr,
1873 											Boolean &					outWritable)
1874 {
1875 	AUIOElement * el = GetIOElement(scope, element);
1876 	return el->GetAudioChannelLayout(outLayoutPtr, outWritable);
1877 }
1878 
RemoveAudioChannelLayout(AudioUnitScope inScope,AudioUnitElement inElement)1879 OSStatus	AUBase::RemoveAudioChannelLayout(			AudioUnitScope				inScope,
1880 														AudioUnitElement			inElement)
1881 {
1882 	OSStatus result = noErr;
1883 	AUIOElement * el = GetIOElement(inScope, inElement);
1884 	Boolean writable;
1885 	if (el->GetAudioChannelLayout(NULL, writable)) {
1886 		result = el->RemoveAudioChannelLayout();
1887 	}
1888 	return result;
1889 }
1890 
SetAudioChannelLayout(AudioUnitScope inScope,AudioUnitElement inElement,const AudioChannelLayout * inLayout)1891 OSStatus 	AUBase::SetAudioChannelLayout(				AudioUnitScope 				inScope,
1892 														AudioUnitElement 			inElement,
1893 														const AudioChannelLayout *	inLayout)
1894 {
1895 	AUIOElement* ioEl = GetIOElement (inScope, inElement);
1896 
1897 	// the num channels of the layout HAS TO MATCH the current channels of the Element's stream format
1898 	UInt32 currentChannels = ioEl->GetStreamFormat().NumberChannels();
1899 	UInt32 numChannelsInLayout = CAAudioChannelLayout::NumberChannels(*inLayout);
1900 	if (currentChannels != numChannelsInLayout)
1901 		return kAudioUnitErr_InvalidPropertyValue;
1902 
1903 	UInt32 numLayouts = GetChannelLayoutTags (inScope, inElement, NULL);
1904 	if (numLayouts == 0)
1905 		return kAudioUnitErr_InvalidProperty;
1906 	AudioChannelLayoutTag *tags = (AudioChannelLayoutTag *)CA_malloc (numLayouts * sizeof (AudioChannelLayoutTag));
1907 	GetChannelLayoutTags (inScope, inElement, tags);
1908 	bool foundTag = false;
1909 	for (unsigned int i = 0; i < numLayouts; ++i) {
1910 		if (tags[i] == inLayout->mChannelLayoutTag || tags[i] == kAudioChannelLayoutTag_UseChannelDescriptions) {
1911 			foundTag = true;
1912 			break;
1913 		}
1914 	}
1915 	free(tags);
1916 
1917 	if (foundTag == false)
1918 		return kAudioUnitErr_InvalidPropertyValue;
1919 
1920 	return ioEl->SetAudioChannelLayout(*inLayout);
1921 }
1922 
AddNumToDictionary(CFMutableDictionaryRef dict,CFStringRef key,SInt32 value)1923 static void AddNumToDictionary (CFMutableDictionaryRef dict, CFStringRef key, SInt32 value)
1924 {
1925 	CFNumberRef num = CFNumberCreate (NULL, kCFNumberSInt32Type, &value);
1926 	CFDictionarySetValue (dict, key, num);
1927 	CFRelease (num);
1928 }
1929 
1930 #define kCurrentSavedStateVersion 0
1931 
SaveState(CFPropertyListRef * outData)1932 OSStatus			AUBase::SaveState(		CFPropertyListRef * outData)
1933 {
1934 	AudioComponentDescription desc = GetComponentDescription();
1935 
1936 	CFMutableDictionaryRef dict = CFDictionaryCreateMutable	(NULL, 0,
1937 								&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1938 
1939 // first step -> save the version to the data ref
1940 	SInt32 value = kCurrentSavedStateVersion;
1941 	AddNumToDictionary (dict, kVersionString, value);
1942 
1943 // second step -> save the component type, subtype, manu to the data ref
1944 	value = desc.componentType;
1945 	AddNumToDictionary (dict, kTypeString, value);
1946 
1947 	value = desc.componentSubType;
1948 	AddNumToDictionary (dict, kSubtypeString, value);
1949 
1950 	value = desc.componentManufacturer;
1951 	AddNumToDictionary (dict, kManufacturerString, value);
1952 
1953 // fourth step -> save the state of all parameters on all scopes and elements
1954 	CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
1955 	for (AudioUnitScope iscope = 0; iscope < 3; ++iscope) {
1956 		AUScope &scope = GetScope(iscope);
1957 		scope.SaveState (data);
1958 	}
1959 
1960     SaveExtendedScopes(data);
1961 
1962 // save all this in the data section of the dictionary
1963 	CFDictionarySetValue(dict, kDataString, data);
1964 	CFRelease (data);
1965 
1966 //OK - now we're going to do some properties
1967 //save the preset name...
1968 	CFDictionarySetValue (dict, kNameString, mCurrentPreset.presetName);
1969 
1970 // Does the unit support the RenderQuality property - if so, save it...
1971 	value = 0;
1972 	OSStatus result = DispatchGetProperty (kAudioUnitProperty_RenderQuality,
1973 								kAudioUnitScope_Global,
1974 								0,
1975 								&value);
1976 
1977 	if (result == noErr) {
1978 		AddNumToDictionary (dict, kRenderQualityString, value);
1979 	}
1980 
1981 // Does the unit support the CPULoad Quality property - if so, save it...
1982 	Float32 cpuLoad;
1983 	result = DispatchGetProperty (6/*kAudioUnitProperty_CPULoad*/,
1984 								kAudioUnitScope_Global,
1985 								0,
1986 								&cpuLoad);
1987 
1988 	if (result == noErr) {
1989 		CFNumberRef num = CFNumberCreate (NULL, kCFNumberFloatType, &cpuLoad);
1990 		CFDictionarySetValue (dict, kCPULoadString, num);
1991 		CFRelease (num);
1992 	}
1993 
1994 // Do we have any element names for any of our scopes?
1995 	// first check to see if we have any names...
1996 	bool foundName = false;
1997 	for (AudioUnitScope i = 0; i < kNumScopes; ++i) {
1998 		foundName = GetScope (i).HasElementWithName();
1999 		if (foundName)
2000 			break;
2001 	}
2002 		// OK - we found a name away we go...
2003 	if (foundName) {
2004 		CFMutableDictionaryRef nameDict = CFDictionaryCreateMutable	(NULL, 0,
2005 								&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2006 		for (AudioUnitScope i = 0; i < kNumScopes; ++i) {
2007 			GetScope (i).AddElementNamesToDict (nameDict);
2008 		}
2009 
2010 		CFDictionarySetValue (dict, kElementNameString, nameDict);
2011 		CFRelease (nameDict);
2012 	}
2013 
2014 // we're done!!!
2015 	*outData = dict;
2016 
2017 	return noErr;
2018 }
2019 
2020 //_____________________________________________________________________________
2021 //
RestoreState(CFPropertyListRef plist)2022 OSStatus			AUBase::RestoreState(	CFPropertyListRef	plist)
2023 {
2024 	if (CFGetTypeID(plist) != CFDictionaryGetTypeID()) return kAudioUnitErr_InvalidPropertyValue;
2025 
2026 	AudioComponentDescription desc = GetComponentDescription();
2027 
2028 	CFDictionaryRef dict = static_cast<CFDictionaryRef>(plist);
2029 
2030 // zeroeth step - make sure the Part key is NOT present, as this method is used
2031 // to restore the GLOBAL state of the dictionary
2032 	if (CFDictionaryContainsKey (dict, kPartString))
2033 		return kAudioUnitErr_InvalidPropertyValue;
2034 
2035 // first step -> check the saved version in the data ref
2036 // at this point we're only dealing with version==0
2037 	CFNumberRef cfnum = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue (dict, kVersionString));
2038 	if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue;
2039 	SInt32 value;
2040 	CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2041 	if (value != kCurrentSavedStateVersion) return kAudioUnitErr_InvalidPropertyValue;
2042 
2043 // second step -> check that this data belongs to this kind of audio unit
2044 // by checking the component subtype and manuID
2045 // We're not checking the type, since there may be different versions (effect, format-converter, offline)
2046 // of essentially the same AU
2047 	cfnum = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue (dict, kSubtypeString));
2048 	if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue;
2049 	CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2050 	if (UInt32(value) != desc.componentSubType) return kAudioUnitErr_InvalidPropertyValue;
2051 
2052 	cfnum = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue (dict, kManufacturerString));
2053 	if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue;
2054 	CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2055 	if (UInt32(value) != desc.componentManufacturer) return kAudioUnitErr_InvalidPropertyValue;
2056 
2057 // fourth step -> restore the state of all of the parameters for each scope and element
2058 	CFDataRef data = reinterpret_cast<CFDataRef>(CFDictionaryGetValue (dict, kDataString));
2059 	if (data != NULL)
2060 	{
2061 		const UInt8 *p, *pend;
2062 
2063 		p = CFDataGetBytePtr(data);
2064 		pend = p + CFDataGetLength(data);
2065 
2066 		// we have a zero length data, which may just mean there were no parameters to save!
2067 		//	if (p >= pend) return noErr;
2068 
2069 		while (p < pend) {
2070             UInt32 scopeIdx = CFSwapInt32BigToHost(*(UInt32 *)p);
2071             p += sizeof(UInt32);
2072 
2073 			AUScope &scope = GetScope(scopeIdx);
2074             p = scope.RestoreState(p);
2075         }
2076 	}
2077 
2078 //OK - now we're going to do some properties
2079 //restore the preset name...
2080 	CFStringRef name = reinterpret_cast<CFStringRef>(CFDictionaryGetValue (dict, kNameString));
2081 	if (mCurrentPreset.presetName) CFRelease (mCurrentPreset.presetName);
2082 	if (name)
2083 	{
2084 		mCurrentPreset.presetName = name;
2085 		mCurrentPreset.presetNumber = -1;
2086 	}
2087 	else { // no name entry make the default one
2088 		mCurrentPreset.presetName = kUntitledString;
2089 		mCurrentPreset.presetNumber = -1;
2090 	}
2091 
2092 	CFRetain (mCurrentPreset.presetName);
2093 #if !CA_USE_AUDIO_PLUGIN_ONLY
2094 #ifndef __LP64__
2095 	PropertyChanged(kAudioUnitProperty_CurrentPreset, kAudioUnitScope_Global, 0);
2096 #endif
2097 #endif
2098 	PropertyChanged(kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0);
2099 
2100 // Does the dict contain render quality information?
2101 	if (CFDictionaryGetValueIfPresent (dict, kRenderQualityString, reinterpret_cast<const void**>(&cfnum)))
2102 	{
2103 		CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2104 		DispatchSetProperty (kAudioUnitProperty_RenderQuality,
2105 								kAudioUnitScope_Global,
2106 								0,
2107 								&value,
2108 								sizeof(value));
2109 	}
2110 
2111 // Does the unit support the CPULoad Quality property - if so, save it...
2112 	if (CFDictionaryGetValueIfPresent (dict, kCPULoadString, reinterpret_cast<const void**>(&cfnum)))
2113 	{
2114 		Float32 floatValue;
2115 		CFNumberGetValue (cfnum, kCFNumberFloatType, &floatValue);
2116 		DispatchSetProperty (6/*kAudioUnitProperty_CPULoad*/,
2117 								kAudioUnitScope_Global,
2118 								0,
2119 								&floatValue,
2120 								sizeof(floatValue));
2121 	}
2122 
2123 // Do we have any element names for any of our scopes?
2124 	CFDictionaryRef nameDict;
2125 	if (CFDictionaryGetValueIfPresent (dict, kElementNameString, reinterpret_cast<const void**>(&nameDict)))
2126 	{
2127 		char string[64];
2128 		for (int i = 0; i < kNumScopes; ++i)
2129 		{
2130 			snprintf (string, sizeof(string), "%d", i);
2131 			CFStringRef key = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII);
2132 			CFDictionaryRef elementDict;
2133 			if (CFDictionaryGetValueIfPresent (nameDict, key, reinterpret_cast<const void**>(&elementDict)))
2134 			{
2135 				bool didAddElements = GetScope (i).RestoreElementNames (elementDict);
2136 				if (didAddElements)
2137 					PropertyChanged (kAudioUnitProperty_ElementCount, i, 0);
2138 			}
2139 			CFRelease (key);
2140 		}
2141 	}
2142 
2143 	return noErr;
2144 }
2145 
GetPresets(CFArrayRef * outData) const2146 OSStatus			AUBase::GetPresets (			CFArrayRef * 					outData) const
2147 {
2148 	return kAudioUnitErr_InvalidProperty;
2149 }
2150 
NewFactoryPresetSet(const AUPreset & inNewFactoryPreset)2151 OSStatus			AUBase::NewFactoryPresetSet (const AUPreset & inNewFactoryPreset)
2152 {
2153 	return kAudioUnitErr_InvalidProperty;
2154 }
2155 
NewCustomPresetSet(const AUPreset & inNewCustomPreset)2156 OSStatus            AUBase::NewCustomPresetSet (const AUPreset & inNewCustomPreset)
2157 {
2158     CFRelease (mCurrentPreset.presetName);
2159     mCurrentPreset = inNewCustomPreset;
2160     CFRetain (mCurrentPreset.presetName);
2161     return noErr;
2162 }
2163 
2164 		// set the default preset for the unit -> the number of the preset MUST be >= 0
2165 		// and the name should be valid, or the preset WON'T take
SetAFactoryPresetAsCurrent(const AUPreset & inPreset)2166 bool				AUBase::SetAFactoryPresetAsCurrent (const AUPreset & inPreset)
2167 {
2168 	if (inPreset.presetNumber < 0 || inPreset.presetName == NULL) return false;
2169 	CFRelease (mCurrentPreset.presetName);
2170 	mCurrentPreset = inPreset;
2171 	CFRetain (mCurrentPreset.presetName);
2172 	return true;
2173 }
2174 
2175 #if !CA_USE_AUDIO_PLUGIN_ONLY
GetNumCustomUIComponents()2176 int			AUBase::GetNumCustomUIComponents ()
2177 {
2178 	return 0;
2179 }
2180 
GetUIComponentDescs(ComponentDescription * inDescArray)2181 void		AUBase::GetUIComponentDescs (ComponentDescription* inDescArray) {}
2182 #endif
2183 
HasIcon()2184 bool		AUBase::HasIcon ()
2185 {
2186 #if !CA_NO_AU_UI_FEATURES
2187 	CFURLRef url = CopyIconLocation();
2188 	if (url) {
2189 		CFRelease (url);
2190 		return true;
2191 	}
2192 #endif
2193 	return false;
2194 }
2195 
CopyIconLocation()2196 CFURLRef	AUBase::CopyIconLocation ()
2197 {
2198 	return NULL;
2199 }
2200 
2201 //_____________________________________________________________________________
2202 //
GetParameterList(AudioUnitScope inScope,AudioUnitParameterID * outParameterList,UInt32 & outNumParameters)2203 OSStatus			AUBase::GetParameterList(		AudioUnitScope					inScope,
2204 													AudioUnitParameterID *			outParameterList,
2205 													UInt32 &						outNumParameters)
2206 {
2207 	AUScope &scope = GetScope(inScope);
2208 	AUElement *elementWithMostParameters = NULL;
2209 	UInt32 maxNumParams = 0;
2210 
2211 	int nElems = scope.GetNumberOfElements();
2212 	for (int ielem = 0; ielem < nElems; ++ielem) {
2213 		AUElement *element = scope.GetElement(ielem);
2214 		UInt32 nParams = element->GetNumberOfParameters();
2215 		if (nParams > maxNumParams) {
2216 			maxNumParams = nParams;
2217 			elementWithMostParameters = element;
2218 		}
2219 	}
2220 
2221 	if (outParameterList != NULL && elementWithMostParameters != NULL)
2222 		elementWithMostParameters->GetParameterList(outParameterList);
2223 
2224 	outNumParameters = maxNumParams;
2225 	return noErr;
2226 }
2227 
2228 //_____________________________________________________________________________
2229 //
GetParameterInfo(AudioUnitScope inScope,AudioUnitParameterID inParameterID,AudioUnitParameterInfo & outParameterInfo)2230 OSStatus			AUBase::GetParameterInfo(		AudioUnitScope			inScope,
2231 													AudioUnitParameterID	inParameterID,
2232 													AudioUnitParameterInfo	&outParameterInfo )
2233 {
2234 	return kAudioUnitErr_InvalidParameter;
2235 }
2236 
2237 //_____________________________________________________________________________
2238 //
GetParameterValueStrings(AudioUnitScope inScope,AudioUnitParameterID inParameterID,CFArrayRef * outStrings)2239 OSStatus			AUBase::GetParameterValueStrings(AudioUnitScope			inScope,
2240 													AudioUnitParameterID	inParameterID,
2241 													CFArrayRef *			outStrings)
2242 {
2243 	return kAudioUnitErr_InvalidProperty;
2244 }
2245 
2246 //_____________________________________________________________________________
2247 //
GetParameterHistoryInfo(AudioUnitScope inScope,AudioUnitParameterID inParameterID,Float32 & outUpdatesPerSecond,Float32 & outHistoryDurationInSeconds)2248 OSStatus			AUBase::GetParameterHistoryInfo(	AudioUnitScope					inScope,
2249 														AudioUnitParameterID			inParameterID,
2250 														Float32 &						outUpdatesPerSecond,
2251 														Float32 &						outHistoryDurationInSeconds)
2252 {
2253 	return kAudioUnitErr_InvalidProperty;
2254 }
2255 
2256 
2257 //_____________________________________________________________________________
2258 //
CopyClumpName(AudioUnitScope inScope,UInt32 inClumpID,UInt32 inDesiredNameLength,CFStringRef * outClumpName)2259 OSStatus			AUBase::CopyClumpName(			AudioUnitScope			inScope,
2260 													UInt32					inClumpID,
2261 													UInt32					inDesiredNameLength,
2262 													CFStringRef *			outClumpName)
2263 {
2264 	return kAudioUnitErr_InvalidProperty;
2265 }
2266 
2267 //_____________________________________________________________________________
2268 //
SetNumberOfElements(AudioUnitScope inScope,UInt32 numElements)2269 void				AUBase::SetNumberOfElements(	AudioUnitScope					inScope,
2270 													UInt32							numElements)
2271 {
2272 	if (inScope == kAudioUnitScope_Global && numElements != 1)
2273 		COMPONENT_THROW(kAudioUnitErr_InvalidScope);
2274 
2275 	GetScope(inScope).SetNumberOfElements(numElements);
2276 }
2277 
2278 //_____________________________________________________________________________
2279 //
CreateElement(AudioUnitScope scope,AudioUnitElement element)2280 AUElement *			AUBase::CreateElement(			AudioUnitScope					scope,
2281 													AudioUnitElement				element)
2282 {
2283 	switch (scope) {
2284 	case kAudioUnitScope_Global:
2285 		return new AUElement(this);
2286 	case kAudioUnitScope_Input:
2287 		return new AUInputElement(this);
2288 	case kAudioUnitScope_Output:
2289 		return new AUOutputElement(this);
2290 #if !CA_BASIC_AU_FEATURES
2291 	case kAudioUnitScope_Group:
2292 		return new AUElement(this);
2293 	case kAudioUnitScope_Part:
2294 		return new AUElement(this);
2295 #endif
2296 	}
2297 	COMPONENT_THROW(kAudioUnitErr_InvalidScope);
2298 
2299 	return NULL;	// get rid of compiler warning
2300 }
2301 
2302 //_____________________________________________________________________________
2303 //
FormatIsCanonical(const CAStreamBasicDescription & f)2304 bool	AUBase::FormatIsCanonical(		const CAStreamBasicDescription &f)
2305 {
2306 	return (f.mFormatID == kAudioFormatLinearPCM
2307 		&&	f.mFramesPerPacket == 1
2308 		&&	f.mBytesPerPacket == f.mBytesPerFrame
2309 //		&&	f.mChannelsPerFrame >= 0	-- this is always true since it's unsigned
2310 		// so far, it's a valid PCM format
2311 #if CA_PREFER_FIXED_POINT
2312 		&&	(f.mFormatFlags & kLinearPCMFormatFlagIsFloat) == 0
2313 		&&	(((f.mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift) == kAudioUnitSampleFractionBits)
2314 #else
2315 		&&	(f.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0
2316 #endif
2317 		&&	((f.mChannelsPerFrame == 1) || ((f.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0) == (mAudioUnitAPIVersion == 1))
2318 #if TARGET_RT_BIG_ENDIAN
2319 		&&	(f.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) != 0
2320 #else
2321 		&&	(f.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) == 0
2322 #endif
2323 		&&	f.mBitsPerChannel == 8 * sizeof(AudioUnitSampleType)
2324 		&&	f.mBytesPerFrame == f.NumberInterleavedChannels() * sizeof(AudioUnitSampleType)
2325 		);
2326 }
2327 
2328 //_____________________________________________________________________________
2329 //
MakeCanonicalFormat(CAStreamBasicDescription & f,int nChannels)2330 void	AUBase::MakeCanonicalFormat(	CAStreamBasicDescription &		f,
2331 										int								nChannels)
2332 {
2333 	f.SetAUCanonical(nChannels, mAudioUnitAPIVersion < 2);	// interleaved for v1, non for v2
2334 	f.mSampleRate = 0.0;
2335 }
2336 
2337 const Float64 AUBase::kNoLastRenderedSampleTime = -1.;
2338 
2339 #include "AUBaseHelper.h"
2340 
GetLoggingString() const2341 char*	AUBase::GetLoggingString () const
2342 {
2343 	if (mLogString) return mLogString;
2344 
2345 	AudioComponentDescription desc = GetComponentDescription();
2346 
2347 	const size_t logStringSize = 256;
2348 	const_cast<AUBase*>(this)->mLogString = new char[logStringSize];
2349 	char str[24];
2350 	char str1[24];
2351 	char str2[24];
2352 	snprintf (const_cast<AUBase*>(this)->mLogString, logStringSize, "AU (%p): %s %s %s",
2353 		GetComponentInstance(),
2354 		CAStringForOSType(desc.componentType, str, sizeof(str)),
2355 		CAStringForOSType(desc.componentSubType, str1, sizeof(str1)),
2356 		CAStringForOSType(desc.componentManufacturer, str2, sizeof(str2)));
2357 
2358 	return mLogString;
2359 }
2360 
2361