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