6 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
7 Inc. ("Apple") in consideration of your agreement to the following
8 terms, and your use, installation, modification or redistribution of
9 this Apple software constitutes acceptance of these terms. If you do
10 not agree with these terms, please do not use, install, modify or
11 redistribute this Apple software.
13 In consideration of your agreement to abide by the following terms, and
14 subject to these terms, Apple grants you a personal, non-exclusive
15 license, under Apple's copyrights in this original Apple software (the
16 "Apple Software"), to use, reproduce, modify and redistribute the Apple
17 Software, with or without modifications, in source and/or binary forms;
18 provided that if you redistribute the Apple Software in its entirety and
19 without modifications, you must retain this notice and the following
20 text and disclaimers in all such redistributions of the Apple Software.
21 Neither the name, trademarks, service marks or logos of Apple Inc. may
22 be used to endorse or promote products derived from the Apple Software
23 without specific prior written permission from Apple. Except as
24 expressly stated in this notice, no other rights or licenses, express or
25 implied, are granted by Apple herein, including but not limited to any
26 patent rights that may be infringed by your derivative works or by other
27 works in which the Apple Software may be incorporated.
29 The Apple Software is provided by Apple on an "AS IS" basis. APPLE
30 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
35 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42 POSSIBILITY OF SUCH DAMAGE.
44 Copyright (C) 2014 Apple Inc. All Rights Reserved.
48 #include "AUDispatch.h"
49 #include "AUInputElement.h"
50 #include "AUOutputElement.h"
53 #include "CAAudioChannelLayout.h"
54 #include "CAHostTimeBase.h"
55 #include "CAVectorUnit.h"
56 #include "CAXException.h"
60 #if TARGET_OS_MAC && (TARGET_CPU_X86 || TARGET_CPU_X86_64)
61 // our compiler does ALL floating point with SSE
62 inline int GETCSR () { int _result; asm volatile ("stmxcsr %0" : "=m" (*&_result) ); return _result; }
63 inline void SETCSR (int a) { int _temp = a; asm volatile( "ldmxcsr %0" : : "m" (*&_temp ) ); }
65 #define DISABLE_DENORMALS int _savemxcsr = GETCSR(); SETCSR(_savemxcsr | 0x8040);
66 #define RESTORE_DENORMALS SETCSR(_savemxcsr);
68 #define DISABLE_DENORMALS
69 #define RESTORE_DENORMALS
72 static bool sAUBaseCFStringsInitialized = false;
73 // this is used for the presets
74 static CFStringRef kUntitledString = NULL;
75 //these are the current keys for the class info document
76 static CFStringRef kVersionString = NULL;
77 static CFStringRef kTypeString = NULL;
78 static CFStringRef kSubtypeString = NULL;
79 static CFStringRef kManufacturerString = NULL;
80 static CFStringRef kDataString = NULL;
81 static CFStringRef kNameString = NULL;
82 static CFStringRef kRenderQualityString = NULL;
83 static CFStringRef kCPULoadString = NULL;
84 static CFStringRef kElementNameString = NULL;
85 static CFStringRef kPartString = NULL;
87 SInt32 AUBase::sVectorUnitType = kVecUninitialized;
89 //_____________________________________________________________________________
91 AUBase::AUBase( AudioComponentInstance inInstance,
92 UInt32 numInputElements,
93 UInt32 numOutputElements,
94 UInt32 numGroupElements) :
95 ComponentBase(inInstance),
96 mElementsCreated(false),
98 mHasBegunInitializing(false),
99 mInitNumInputEls(numInputElements), mInitNumOutputEls(numOutputElements),
100 #if !CA_BASIC_AU_FEATURES
101 mInitNumGroupEls(numGroupElements),
103 mRenderCallbacksTouched(false),
104 mRenderThreadID (NULL),
105 mWantsRenderThreadID (false),
107 mUsesFixedBlockSize(false),
108 mBuffersAllocated(false),
112 #if !CA_NO_AU_UI_FEATURES
119 if(!sAUBaseCFStringsInitialized)
121 kUntitledString = CFSTR("Untitled");
122 kVersionString = CFSTR(kAUPresetVersionKey);
123 kTypeString = CFSTR(kAUPresetTypeKey);
124 kSubtypeString = CFSTR(kAUPresetSubtypeKey);
125 kManufacturerString = CFSTR(kAUPresetManufacturerKey);
126 kDataString = CFSTR(kAUPresetDataKey);
127 kNameString = CFSTR(kAUPresetNameKey);
128 kRenderQualityString = CFSTR(kAUPresetRenderQualityKey);
129 kCPULoadString = CFSTR(kAUPresetCPULoadKey);
130 kElementNameString = CFSTR(kAUPresetElementNameKey);
131 kPartString = CFSTR(kAUPresetPartKey);
132 sAUBaseCFStringsInitialized = true;
135 if (sVectorUnitType == kVecUninitialized) {
136 sVectorUnitType = CAVectorUnit::GetVectorUnitType() ;
139 mAudioUnitAPIVersion = 2;
141 SetMaxFramesPerSlice(kAUDefaultMaxFramesPerSlice);
143 GlobalScope().Initialize(this, kAudioUnitScope_Global, 1);
145 #if !CA_NO_AU_UI_FEATURES
146 memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo));
150 mCurrentPreset.presetNumber = -1;
151 mCurrentPreset.presetName = kUntitledString;
152 CFRetain (mCurrentPreset.presetName);
155 //_____________________________________________________________________________
159 if (mCurrentPreset.presetName) CFRelease (mCurrentPreset.presetName);
160 #if !CA_NO_AU_UI_FEATURES
161 if (mContextName) CFRelease (mContextName);
163 if (mLogString) delete [] mLogString;
164 if (mNickName) CFRelease(mNickName);
167 //_____________________________________________________________________________
169 void AUBase::CreateElements()
171 if (!mElementsCreated) {
172 Inputs().Initialize(this, kAudioUnitScope_Input, mInitNumInputEls);
173 Outputs().Initialize(this, kAudioUnitScope_Output, mInitNumOutputEls);
174 #if !CA_BASIC_AU_FEATURES
175 Groups().Initialize(this, kAudioUnitScope_Group, mInitNumGroupEls);
177 CreateExtendedElements();
179 mElementsCreated = true;
183 //_____________________________________________________________________________
185 void AUBase::SetMaxFramesPerSlice(UInt32 nFrames)
187 mMaxFramesPerSlice = nFrames;
188 if (mBuffersAllocated)
190 PropertyChanged(kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0);
193 //_____________________________________________________________________________
195 OSStatus AUBase::CanSetMaxFrames() const
197 return IsInitialized() ? kAudioUnitErr_Initialized : OSStatus(noErr);
200 //_____________________________________________________________________________
202 void AUBase::ReallocateBuffers()
206 UInt32 nOutputs = Outputs().GetNumberOfElements();
207 for (UInt32 i = 0; i < nOutputs; ++i) {
208 AUOutputElement *output = GetOutput(i);
209 output->AllocateBuffer(); // does no work if already allocated
211 UInt32 nInputs = Inputs().GetNumberOfElements();
212 for (UInt32 i = 0; i < nInputs; ++i) {
213 AUInputElement *input = GetInput(i);
214 input->AllocateBuffer(); // does no work if already allocated
216 mBuffersAllocated = true;
219 //_____________________________________________________________________________
221 void AUBase::DeallocateIOBuffers()
223 if (!mBuffersAllocated)
226 UInt32 nOutputs = Outputs().GetNumberOfElements();
227 for (UInt32 i = 0; i < nOutputs; ++i) {
228 AUOutputElement *output = GetOutput(i);
229 output->DeallocateBuffer();
231 UInt32 nInputs = Inputs().GetNumberOfElements();
232 for (UInt32 i = 0; i < nInputs; ++i) {
233 AUInputElement *input = GetInput(i);
234 input->DeallocateBuffer();
236 mBuffersAllocated = false;
239 //_____________________________________________________________________________
241 OSStatus AUBase::DoInitialize()
243 OSStatus result = noErr;
246 result = Initialize();
247 if (result == noErr) {
248 if (CanScheduleParameters())
249 mParamList.reserve(24);
250 mHasBegunInitializing = true;
251 ReallocateBuffers(); // calls CreateElements()
252 mInitialized = true; // signal that it's okay to render
260 //_____________________________________________________________________________
262 OSStatus AUBase::Initialize()
267 //_____________________________________________________________________________
269 void AUBase::PreDestructor()
271 // this is called from the ComponentBase dispatcher, which doesn't know anything about our (optional) lock
272 CAMutex::Locker lock(mAUMutex);
276 //_____________________________________________________________________________
278 void AUBase::DoCleanup()
283 DeallocateIOBuffers();
286 mInitialized = false;
287 mHasBegunInitializing = false;
290 //_____________________________________________________________________________
292 void AUBase::Cleanup()
296 //_____________________________________________________________________________
298 OSStatus AUBase::Reset( AudioUnitScope inScope,
299 AudioUnitElement inElement)
305 //_____________________________________________________________________________
307 OSStatus AUBase::DispatchGetPropertyInfo(AudioUnitPropertyID inID,
308 AudioUnitScope inScope,
309 AudioUnitElement inElement,
310 UInt32 & outDataSize,
311 Boolean & outWritable)
313 OSStatus result = noErr;
314 bool validateElement = true;
317 case kAudioUnitProperty_MakeConnection:
318 ca_require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global, InvalidScope);
319 outDataSize = sizeof(AudioUnitConnection);
324 case kAudioUnitProperty_SetRenderCallback:
325 ca_require(AudioUnitAPIVersion() > 1, InvalidProperty);
326 ca_require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global, InvalidScope);
327 outDataSize = sizeof(AURenderCallbackStruct);
331 case kAudioUnitProperty_StreamFormat:
332 outDataSize = sizeof(CAStreamBasicDescription);
333 outWritable = IsStreamFormatWritable(inScope, inElement);
336 case kAudioUnitProperty_SampleRate:
337 outDataSize = sizeof(Float64);
338 outWritable = IsStreamFormatWritable(inScope, inElement);
341 case kAudioUnitProperty_ClassInfo:
342 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
343 outDataSize = sizeof(CFPropertyListRef);
347 case kAudioUnitProperty_FactoryPresets:
348 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
349 result = GetPresets(NULL);
351 outDataSize = sizeof(CFArrayRef);
356 case kAudioUnitProperty_PresentPreset:
357 #if !CA_USE_AUDIO_PLUGIN_ONLY
359 case kAudioUnitProperty_CurrentPreset:
362 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
363 outDataSize = sizeof(AUPreset);
367 case kAudioUnitProperty_ElementName:
368 outDataSize = sizeof (CFStringRef);
372 case kAudioUnitProperty_ParameterList:
375 result = GetParameterList(inScope, NULL, nparams);
377 outDataSize = sizeof(AudioUnitParameterID) * nparams;
379 validateElement = false;
383 case kAudioUnitProperty_ParameterInfo:
384 outDataSize = sizeof(AudioUnitParameterInfo);
386 validateElement = false;
389 case kAudioUnitProperty_ParameterHistoryInfo:
390 outDataSize = sizeof(AudioUnitParameterHistoryInfo);
392 validateElement = false;
395 case kAudioUnitProperty_ElementCount:
396 outDataSize = sizeof(UInt32);
397 outWritable = BusCountWritable(inScope);
398 validateElement = false;
401 case kAudioUnitProperty_Latency:
402 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
403 outDataSize = sizeof(Float64);
407 case kAudioUnitProperty_TailTime:
408 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
409 if (SupportsTail()) {
410 outDataSize = sizeof(Float64);
413 goto InvalidProperty;
416 case kAudioUnitProperty_MaximumFramesPerSlice:
417 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
418 outDataSize = sizeof(UInt32);
422 case kAudioUnitProperty_LastRenderError:
423 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
424 outDataSize = sizeof(OSStatus);
428 case kAudioUnitProperty_SupportedNumChannels:
430 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
431 UInt32 num = SupportedNumChannels (NULL);
433 outDataSize = sizeof (AUChannelInfo) * num;
436 goto InvalidProperty;
441 case kAudioUnitProperty_SupportedChannelLayoutTags:
443 UInt32 numLayouts = GetChannelLayoutTags(inScope, inElement, NULL);
445 outDataSize = numLayouts * sizeof(AudioChannelLayoutTag);
448 goto InvalidProperty;
450 validateElement = false; //already done it
454 case kAudioUnitProperty_AudioChannelLayout:
457 outDataSize = GetAudioChannelLayout(inScope, inElement, NULL, outWritable);
461 if (GetChannelLayoutTags(inScope, inElement, NULL) == 0)
462 goto InvalidProperty;
464 result = kAudioUnitErr_InvalidPropertyValue;
466 validateElement = false; //already done it
470 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE
471 case kAudioUnitProperty_ShouldAllocateBuffer:
472 ca_require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output), InvalidScope);
474 outDataSize = sizeof(UInt32);
478 #if !CA_USE_AUDIO_PLUGIN_ONLY
479 case kAudioUnitProperty_FastDispatch:
480 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
481 if (!IsCMgrObject()) goto InvalidProperty;
482 outDataSize = sizeof(void *);
484 validateElement = false;
487 case kAudioUnitProperty_GetUIComponentList:
488 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
489 outDataSize = GetNumCustomUIComponents();
490 if (outDataSize == 0)
491 goto InvalidProperty;
492 outDataSize *= sizeof (AudioComponentDescription);
498 case kAudioUnitProperty_ParameterValueStrings:
499 result = GetParameterValueStrings(inScope, inElement, NULL);
500 if (result == noErr) {
501 outDataSize = sizeof(CFArrayRef);
503 validateElement = false;
507 #if !CA_NO_AU_HOST_CALLBACKS
508 case kAudioUnitProperty_HostCallbacks:
509 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
510 outDataSize = sizeof(mHostCallbackInfo);
514 #if !CA_NO_AU_UI_FEATURES
515 case kAudioUnitProperty_ContextName:
516 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
517 outDataSize = sizeof(CFStringRef);
521 case kAudioUnitProperty_IconLocation:
522 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
525 goto InvalidProperty;
526 outDataSize = sizeof(CFURLRef);
529 case kAudioUnitProperty_ParameterClumpName:
530 outDataSize = sizeof(AudioUnitParameterNameInfo );
534 #endif // !CA_NO_AU_UI_FEATURES
536 case 'lrst' : // kAudioUnitProperty_LastRenderedSampleTime
537 outDataSize = sizeof(Float64);
541 case kAudioUnitProperty_NickName:
542 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
543 outDataSize = sizeof(CFStringRef);
548 result = GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);
549 validateElement = false;
553 if (result == noErr && validateElement) {
554 ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
559 return kAudioUnitErr_InvalidProperty;
561 return kAudioUnitErr_InvalidScope;
563 return kAudioUnitErr_InvalidElement;
566 //_____________________________________________________________________________
568 OSStatus AUBase::DispatchGetProperty( AudioUnitPropertyID inID,
569 AudioUnitScope inScope,
570 AudioUnitElement inElement,
573 // NOTE: We're currently only called from AUBase::ComponentEntryDispatch, which
574 // calls DispatchGetPropertyInfo first, which performs validation of the scope/element,
575 // and ensures that the outData buffer is non-null and large enough.
576 OSStatus result = noErr;
579 case kAudioUnitProperty_StreamFormat:
580 *(CAStreamBasicDescription *)outData = GetStreamFormat(inScope, inElement);
583 case kAudioUnitProperty_SampleRate:
584 *(Float64 *)outData = GetStreamFormat(inScope, inElement).mSampleRate;
587 case kAudioUnitProperty_ParameterList:
590 result = GetParameterList(inScope, (AudioUnitParameterID *)outData, nparams);
594 case kAudioUnitProperty_ParameterInfo:
595 result = GetParameterInfo(inScope, inElement, *(AudioUnitParameterInfo *)outData);
598 case kAudioUnitProperty_ParameterHistoryInfo:
600 AudioUnitParameterHistoryInfo* info = (AudioUnitParameterHistoryInfo*)outData;
601 result = GetParameterHistoryInfo(inScope, inElement, info->updatesPerSecond, info->historyDurationInSeconds);
605 case kAudioUnitProperty_ClassInfo:
607 *(CFPropertyListRef *)outData = NULL;
608 result = SaveState((CFPropertyListRef *)outData);
612 case kAudioUnitProperty_FactoryPresets:
614 *(CFArrayRef *)outData = NULL;
615 result = GetPresets ((CFArrayRef *)outData);
619 case kAudioUnitProperty_PresentPreset:
620 #if !CA_USE_AUDIO_PLUGIN_ONLY
622 case kAudioUnitProperty_CurrentPreset:
626 *(AUPreset *)outData = mCurrentPreset;
628 // retain current string (as client owns a reference to it and will release it)
629 if (inID == kAudioUnitProperty_PresentPreset && mCurrentPreset.presetName)
630 CFRetain (mCurrentPreset.presetName);
636 case kAudioUnitProperty_ElementName:
638 AUElement * element = GetElement(inScope, inElement);
639 if (element->HasName()) {
640 *(CFStringRef *)outData = element->GetName();
641 CFRetain (element->GetName());
644 result = kAudioUnitErr_InvalidPropertyValue;
648 case kAudioUnitProperty_ElementCount:
649 *(UInt32 *)outData = GetScope(inScope).GetNumberOfElements();
652 case kAudioUnitProperty_Latency:
653 *(Float64 *)outData = GetLatency();
656 case kAudioUnitProperty_TailTime:
658 *(Float64 *)outData = GetTailTime();
660 result = kAudioUnitErr_InvalidProperty;
663 case kAudioUnitProperty_MaximumFramesPerSlice:
664 *(UInt32 *)outData = mMaxFramesPerSlice;
667 case kAudioUnitProperty_LastRenderError:
668 *(OSStatus *)outData = mLastRenderError;
669 mLastRenderError = 0;
672 case kAudioUnitProperty_SupportedNumChannels:
674 const AUChannelInfo* infoPtr = NULL;
675 UInt32 num = SupportedNumChannels (&infoPtr);
676 if(num != 0 && infoPtr != NULL)
677 memcpy (outData, infoPtr, num * sizeof (AUChannelInfo));
681 case kAudioUnitProperty_SupportedChannelLayoutTags:
683 AudioChannelLayoutTag* ptr = outData ? static_cast<AudioChannelLayoutTag*>(outData) : NULL;
684 UInt32 numLayouts = GetChannelLayoutTags (inScope, inElement, ptr);
686 result = kAudioUnitErr_InvalidProperty;
690 case kAudioUnitProperty_AudioChannelLayout:
692 AudioChannelLayout* ptr = outData ? static_cast<AudioChannelLayout*>(outData) : NULL;
694 UInt32 dataSize = GetAudioChannelLayout(inScope, inElement, ptr, writable);
696 result = kAudioUnitErr_InvalidProperty;
701 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE
702 case kAudioUnitProperty_ShouldAllocateBuffer:
704 AUIOElement * element = GetIOElement(inScope, inElement);
705 *(UInt32*)outData = element->WillAllocateBuffer();
710 case kAudioUnitProperty_ParameterValueStrings:
711 result = GetParameterValueStrings(inScope, inElement, (CFArrayRef *)outData);
714 #if !CA_USE_AUDIO_PLUGIN_ONLY
715 case kAudioUnitProperty_FastDispatch:
716 if (!IsCMgrObject()) result = kAudioUnitErr_InvalidProperty;
719 case kAudioUnitGetParameterSelect:
720 *(AudioUnitGetParameterProc *)outData = (AudioUnitGetParameterProc)CMgr_AudioUnitBaseGetParameter;
722 case kAudioUnitSetParameterSelect:
723 *(AudioUnitSetParameterProc *)outData = (AudioUnitSetParameterProc)CMgr_AudioUnitBaseSetParameter;
725 case kAudioUnitRenderSelect:
726 if (AudioUnitAPIVersion() > 1)
727 *(AudioUnitRenderProc *)outData = (AudioUnitRenderProc)CMgr_AudioUnitBaseRender;
728 else result = kAudioUnitErr_InvalidElement;
731 result = GetProperty(inID, inScope, inElement, outData);
737 case kAudioUnitProperty_GetUIComponentList:
738 GetUIComponentDescs ((ComponentDescription*)outData);
742 #if !CA_NO_AU_HOST_CALLBACKS
743 case kAudioUnitProperty_HostCallbacks:
744 memcpy(outData, &mHostCallbackInfo, sizeof(mHostCallbackInfo));
747 #if !CA_NO_AU_UI_FEATURES
748 case kAudioUnitProperty_IconLocation:
750 CFURLRef iconLocation = CopyIconLocation();
752 *(CFURLRef*)outData = iconLocation;
754 result = kAudioUnitErr_InvalidProperty;
758 case kAudioUnitProperty_ContextName:
759 *(CFStringRef *)outData = mContextName;
761 CFRetain(mContextName);
762 // retain CFString (if exists) since client will be responsible for its release
765 result = kAudioUnitErr_InvalidPropertyValue;
769 case kAudioUnitProperty_ParameterClumpName:
771 AudioUnitParameterNameInfo * ioClumpInfo = (AudioUnitParameterNameInfo*) outData;
772 if (ioClumpInfo->inID == kAudioUnitClumpID_System) // this ID value is reserved
773 result = kAudioUnitErr_InvalidPropertyValue;
776 result = CopyClumpName(inScope, ioClumpInfo->inID, ioClumpInfo->inDesiredLength, &ioClumpInfo->outName);
778 // this is provided for compatbility with existing implementations that don't know
779 // about this new mechanism
780 if (result == kAudioUnitErr_InvalidProperty)
781 result = GetProperty (inID, inScope, inElement, outData);
786 #endif // !CA_NO_AU_UI_FEATURES
788 case 'lrst' : // kAudioUnitProperty_LastRenderedSampleTime
789 *(Float64*)outData = mCurrentRenderTime.mSampleTime;
792 case kAudioUnitProperty_NickName:
793 // Ownership follows Core Foundation's 'Copy Rule'
794 if (mNickName) CFRetain(mNickName);
795 *(CFStringRef*)outData = mNickName;
799 result = GetProperty(inID, inScope, inElement, outData);
806 //_____________________________________________________________________________
808 OSStatus AUBase::DispatchSetProperty( AudioUnitPropertyID inID,
809 AudioUnitScope inScope,
810 AudioUnitElement inElement,
814 OSStatus result = noErr;
817 case kAudioUnitProperty_MakeConnection:
818 ca_require(inDataSize >= sizeof(AudioUnitConnection), InvalidPropertyValue);
820 AudioUnitConnection &connection = *(AudioUnitConnection *)inData;
821 result = SetConnection(connection);
826 case kAudioUnitProperty_SetRenderCallback:
828 ca_require(inDataSize >= sizeof(AURenderCallbackStruct), InvalidPropertyValue);
829 ca_require(AudioUnitAPIVersion() > 1, InvalidProperty);
830 AURenderCallbackStruct &callback = *(AURenderCallbackStruct*)inData;
831 result = SetInputCallback(kAudioUnitProperty_SetRenderCallback, inElement, callback.inputProc, callback.inputProcRefCon);
835 case kAudioUnitProperty_ElementCount:
836 ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue);
837 ca_require(BusCountWritable(inScope), NotWritable);
838 result = SetBusCount(inScope, *(UInt32*)inData);
839 if (result == noErr) {
840 PropertyChanged(inID, inScope, inElement);
844 case kAudioUnitProperty_MaximumFramesPerSlice:
845 ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue);
846 result = CanSetMaxFrames();
847 if (result) return result;
848 SetMaxFramesPerSlice(*(UInt32 *)inData);
851 case kAudioUnitProperty_StreamFormat:
853 if (inDataSize < 36) goto InvalidPropertyValue;
854 ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
856 CAStreamBasicDescription newDesc;
857 // now we're going to be ultra conservative! because of discrepancies between
858 // sizes of this struct based on aligment padding inconsistencies
859 memset (&newDesc, 0, sizeof(newDesc));
860 memcpy (&newDesc, inData, 36);
862 ca_require(ValidFormat(inScope, inElement, newDesc), InvalidFormat);
864 const CAStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement);
866 if ( !curDesc.IsEqual(newDesc, false) ) {
867 ca_require(IsStreamFormatWritable(inScope, inElement), NotWritable);
868 result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);
873 case kAudioUnitProperty_SampleRate:
875 ca_require(inDataSize == sizeof(Float64), InvalidPropertyValue);
876 ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
878 const CAStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement);
879 CAStreamBasicDescription newDesc = curDesc;
880 newDesc.mSampleRate = *(Float64 *)inData;
882 ca_require(ValidFormat(inScope, inElement, newDesc), InvalidFormat);
884 if ( !curDesc.IsEqual(newDesc, false) ) {
885 ca_require(IsStreamFormatWritable(inScope, inElement), NotWritable);
886 result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);
891 case kAudioUnitProperty_AudioChannelLayout:
893 const AudioChannelLayout *layout = static_cast<const AudioChannelLayout *>(inData);
894 size_t headerSize = sizeof(AudioChannelLayout) - sizeof(AudioChannelDescription);
896 ca_require(inDataSize >= headerSize + layout->mNumberChannelDescriptions * sizeof(AudioChannelDescription), InvalidPropertyValue);
897 result = SetAudioChannelLayout(inScope, inElement, layout);
899 PropertyChanged(inID, inScope, inElement);
903 case kAudioUnitProperty_ClassInfo:
904 ca_require(inDataSize == sizeof(CFPropertyListRef *), InvalidPropertyValue);
905 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
906 result = RestoreState(*(CFPropertyListRef *)inData);
909 case kAudioUnitProperty_PresentPreset:
910 #if !CA_USE_AUDIO_PLUGIN_ONLY
912 case kAudioUnitProperty_CurrentPreset:
916 ca_require(inDataSize == sizeof(AUPreset), InvalidPropertyValue);
917 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
918 AUPreset & newPreset = *(AUPreset *)inData;
920 if (newPreset.presetNumber >= 0)
922 result = NewFactoryPresetSet(newPreset);
923 // NewFactoryPresetSet SHOULD call SetAFactoryPreset if the preset is valid
924 // from its own list of preset number->name
926 PropertyChanged(inID, inScope, inElement);
928 else if (newPreset.presetName)
930 result = NewCustomPresetSet(newPreset);
932 PropertyChanged(inID, inScope, inElement);
935 result = kAudioUnitErr_InvalidPropertyValue;
939 case kAudioUnitProperty_ElementName:
941 ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
942 ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue);
943 AUElement * element = GetScope(inScope).GetElement (inElement);
944 element->SetName (*(CFStringRef *)inData);
945 PropertyChanged(inID, inScope, inElement);
949 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE
950 case kAudioUnitProperty_ShouldAllocateBuffer:
952 ca_require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output), InvalidScope);
953 ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
954 ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue);
955 ca_require(!IsInitialized(), Initialized);
957 AUIOElement * element = GetIOElement(inScope, inElement);
958 element->SetWillAllocateBuffer(*(UInt32 *)inData != 0);
963 #if !CA_NO_AU_HOST_CALLBACKS
964 case kAudioUnitProperty_HostCallbacks:
966 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
967 UInt32 availSize = std::min(inDataSize, (UInt32)sizeof(HostCallbackInfo));
968 bool hasChanged = !memcmp (&mHostCallbackInfo, inData, availSize);
969 memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo));
970 memcpy (&mHostCallbackInfo, inData, availSize);
972 PropertyChanged(inID, inScope, inElement);
976 #if !CA_NO_AU_UI_FEATURES
977 case kAudioUnitProperty_SetExternalBuffer:
978 ca_require(inDataSize >= sizeof(AudioUnitExternalBuffer), InvalidPropertyValue);
979 ca_require(IsInitialized(), Uninitialized);
981 AudioUnitExternalBuffer &buf = *(AudioUnitExternalBuffer*)inData;
982 if (intptr_t(buf.buffer) & 0x0F) result = kAudio_ParamError;
983 else if (inScope == kAudioUnitScope_Input) {
984 AUInputElement *input = GetInput(inElement);
985 input->UseExternalBuffer(buf);
987 AUOutputElement *output = GetOutput(inElement);
988 output->UseExternalBuffer(buf);
993 case kAudioUnitProperty_ContextName:
995 ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue);
996 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
997 CFStringRef inStr = *(CFStringRef *)inData;
998 if (mContextName) CFRelease(mContextName);
999 if (inStr) CFRetain(inStr);
1000 mContextName = inStr;
1001 PropertyChanged(inID, inScope, inElement);
1005 #endif // !CA_NO_AU_UI_FEATURES
1007 case kAudioUnitProperty_NickName:
1009 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
1010 ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue);
1011 CFStringRef inStr = *(CFStringRef *)inData;
1012 if (mNickName) CFRelease(mNickName);
1013 if (inStr) CFRetain(inStr);
1015 PropertyChanged(inID, inScope, inElement);
1020 result = SetProperty(inID, inScope, inElement, inData, inDataSize);
1021 if (result == noErr)
1022 PropertyChanged(inID, inScope, inElement);
1028 return kAudioUnitErr_PropertyNotWritable;
1030 return kAudioUnitErr_FormatNotSupported;
1031 #if !CA_NO_AU_UI_FEATURES
1033 return kAudioUnitErr_Uninitialized;
1035 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || CA_USE_AUDIO_PLUGIN_ONLY
1037 return kAudioUnitErr_Initialized;
1040 return kAudioUnitErr_InvalidScope;
1042 return kAudioUnitErr_InvalidProperty;
1043 InvalidPropertyValue:
1044 return kAudioUnitErr_InvalidPropertyValue;
1046 return kAudioUnitErr_InvalidElement;
1049 //_____________________________________________________________________________
1051 OSStatus AUBase::DispatchRemovePropertyValue (AudioUnitPropertyID inID,
1052 AudioUnitScope inScope,
1053 AudioUnitElement inElement)
1055 OSStatus result = noErr;
1058 case kAudioUnitProperty_AudioChannelLayout:
1060 result = RemoveAudioChannelLayout(inScope, inElement);
1061 if (result == noErr)
1062 PropertyChanged(inID, inScope, inElement);
1066 #if !CA_NO_AU_HOST_CALLBACKS
1067 case kAudioUnitProperty_HostCallbacks:
1069 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
1070 bool hasValue = false;
1071 void* ptr = &mHostCallbackInfo;
1072 for (unsigned int i = 0; i < sizeof (HostCallbackInfo); ++i) {
1073 if (static_cast<char*>(ptr)[i]) {
1079 memset (&mHostCallbackInfo, 0, sizeof (HostCallbackInfo));
1080 PropertyChanged(inID, inScope, inElement);
1085 #if !CA_NO_AU_UI_FEATURES
1086 case kAudioUnitProperty_ContextName:
1087 if (mContextName) CFRelease(mContextName);
1088 mContextName = NULL;
1092 #endif // !CA_NO_AU_UI_FEATURES
1094 case kAudioUnitProperty_NickName:
1096 if(inScope == kAudioUnitScope_Global) {
1097 if (mNickName) CFRelease(mNickName);
1099 PropertyChanged(inID, inScope, inElement);
1101 result = kAudioUnitErr_InvalidScope;
1107 result = RemovePropertyValue (inID, inScope, inElement);
1112 #if !CA_NO_AU_UI_FEATURES || !CA_NO_AU_HOST_CALLBACKS
1114 return kAudioUnitErr_InvalidScope;
1118 //_____________________________________________________________________________
1120 OSStatus AUBase::GetPropertyInfo( AudioUnitPropertyID inID,
1121 AudioUnitScope inScope,
1122 AudioUnitElement inElement,
1123 UInt32 & outDataSize,
1124 Boolean & outWritable)
1126 return kAudioUnitErr_InvalidProperty;
1130 //_____________________________________________________________________________
1132 OSStatus AUBase::GetProperty( AudioUnitPropertyID inID,
1133 AudioUnitScope inScope,
1134 AudioUnitElement inElement,
1137 return kAudioUnitErr_InvalidProperty;
1141 //_____________________________________________________________________________
1143 OSStatus AUBase::SetProperty( AudioUnitPropertyID inID,
1144 AudioUnitScope inScope,
1145 AudioUnitElement inElement,
1146 const void * inData,
1149 return kAudioUnitErr_InvalidProperty;
1152 //_____________________________________________________________________________
1154 OSStatus AUBase::RemovePropertyValue ( AudioUnitPropertyID inID,
1155 AudioUnitScope inScope,
1156 AudioUnitElement inElement)
1158 return kAudioUnitErr_InvalidPropertyValue;
1161 //_____________________________________________________________________________
1163 OSStatus AUBase::AddPropertyListener( AudioUnitPropertyID inID,
1164 AudioUnitPropertyListenerProc inProc,
1165 void * inProcRefCon)
1167 PropertyListener pl;
1169 pl.propertyID = inID;
1170 pl.listenerProc = inProc;
1171 pl.listenerRefCon = inProcRefCon;
1173 if (mPropertyListeners.empty())
1174 mPropertyListeners.reserve(32);
1175 mPropertyListeners.push_back(pl);
1180 //_____________________________________________________________________________
1182 OSStatus AUBase::RemovePropertyListener( AudioUnitPropertyID inID,
1183 AudioUnitPropertyListenerProc inProc,
1184 void * inProcRefCon,
1185 bool refConSpecified)
1187 // iterate in reverse so that it's safe to erase in the middle of the vector
1188 for (int i = (int)mPropertyListeners.size(); --i >=0; ) {
1189 PropertyListeners::iterator it = mPropertyListeners.begin() + i;
1190 if ((*it).propertyID == inID && (*it).listenerProc == inProc && (!refConSpecified || (*it).listenerRefCon == inProcRefCon))
1191 mPropertyListeners.erase(it);
1196 //_____________________________________________________________________________
1198 void AUBase::PropertyChanged( AudioUnitPropertyID inID,
1199 AudioUnitScope inScope,
1200 AudioUnitElement inElement)
1202 for (PropertyListeners::iterator it = mPropertyListeners.begin(); it != mPropertyListeners.end(); ++it)
1203 if ((*it).propertyID == inID)
1204 ((*it).listenerProc)((*it).listenerRefCon, mComponentInstance, inID, inScope, inElement);
1207 //_____________________________________________________________________________
1209 OSStatus AUBase::SetRenderNotification( AURenderCallback inProc,
1213 return kAudio_ParamError;
1215 mRenderCallbacksTouched = true;
1216 mRenderCallbacks.deferred_add(RenderCallback(inProc, inRefCon));
1217 // this will do nothing if it's already in the list
1221 //_____________________________________________________________________________
1223 OSStatus AUBase::RemoveRenderNotification( AURenderCallback inProc,
1226 mRenderCallbacks.deferred_remove(RenderCallback(inProc, inRefCon));
1227 return noErr; // error?
1230 //_____________________________________________________________________________
1232 OSStatus AUBase::GetParameter( AudioUnitParameterID inID,
1233 AudioUnitScope inScope,
1234 AudioUnitElement inElement,
1235 AudioUnitParameterValue & outValue)
1237 AUElement *elem = SafeGetElement(inScope, inElement);
1238 outValue = elem->GetParameter(inID);
1243 //_____________________________________________________________________________
1245 OSStatus AUBase::SetParameter( AudioUnitParameterID inID,
1246 AudioUnitScope inScope,
1247 AudioUnitElement inElement,
1248 AudioUnitParameterValue inValue,
1249 UInt32 inBufferOffsetInFrames)
1251 AUElement *elem = SafeGetElement(inScope, inElement);
1252 elem->SetParameter(inID, inValue);
1256 //_____________________________________________________________________________
1258 OSStatus AUBase::ScheduleParameter ( const AudioUnitParameterEvent *inParameterEvent,
1261 bool canScheduleParameters = CanScheduleParameters();
1263 for (UInt32 i = 0; i < inNumEvents; ++i)
1265 if (inParameterEvent[i].eventType == kParameterEvent_Immediate)
1267 SetParameter (inParameterEvent[i].parameter,
1268 inParameterEvent[i].scope,
1269 inParameterEvent[i].element,
1270 inParameterEvent[i].eventValues.immediate.value,
1271 inParameterEvent[i].eventValues.immediate.bufferOffset);
1273 if (canScheduleParameters) {
1274 mParamList.push_back (inParameterEvent[i]);
1281 // ____________________________________________________________________________
1283 static bool SortParameterEventList(const AudioUnitParameterEvent &ev1, const AudioUnitParameterEvent &ev2 )
1285 int offset1 = ev1.eventType == kParameterEvent_Immediate ? ev1.eventValues.immediate.bufferOffset : ev1.eventValues.ramp.startBufferOffset;
1286 int offset2 = ev2.eventType == kParameterEvent_Immediate ? ev2.eventValues.immediate.bufferOffset : ev2.eventValues.ramp.startBufferOffset;
1288 if(offset1 < offset2) return true;
1293 // ____________________________________________________________________________
1295 OSStatus AUBase::ProcessForScheduledParams( ParameterEventList &inParamList,
1296 UInt32 inFramesToProcess,
1299 OSStatus result = noErr;
1301 int totalFramesToProcess = inFramesToProcess;
1303 int framesRemaining = totalFramesToProcess;
1305 unsigned int currentStartFrame = 0; // start of the whole buffer
1309 // sort the ParameterEventList by startBufferOffset
1310 std::sort(inParamList.begin(), inParamList.end(), SortParameterEventList);
1312 ParameterEventList::iterator iter = inParamList.begin();
1315 while(framesRemaining > 0 )
1317 // first of all, go through the ramped automation events and find out where the next
1318 // division of our whole buffer will be
1320 int currentEndFrame = totalFramesToProcess; // start out assuming we'll process all the way to
1321 // the end of the buffer
1323 iter = inParamList.begin();
1325 // find the next break point
1326 while(iter != inParamList.end() )
1328 AudioUnitParameterEvent &event = *iter;
1330 int offset = event.eventType == kParameterEvent_Immediate ? event.eventValues.immediate.bufferOffset : event.eventValues.ramp.startBufferOffset;
1332 if(offset > (int)currentStartFrame && offset < currentEndFrame )
1334 currentEndFrame = offset;
1338 // consider ramp end to be a possible choice (there may be gaps in the supplied ramp events)
1339 if(event.eventType == kParameterEvent_Ramped )
1341 offset = event.eventValues.ramp.startBufferOffset + event.eventValues.ramp.durationInFrames;
1343 if(offset > (int)currentStartFrame && offset < currentEndFrame )
1345 currentEndFrame = offset;
1352 int framesThisTime = currentEndFrame - currentStartFrame;
1354 // next, setup the parameter maps to be current for the ramp parameters active during
1355 // this time segment...
1357 for(ParameterEventList::iterator iter2 = inParamList.begin(); iter2 != inParamList.end(); iter2++ )
1359 AudioUnitParameterEvent &event = *iter2;
1361 bool eventFallsInSlice;
1364 if(event.eventType == kParameterEvent_Ramped)
1365 eventFallsInSlice = event.eventValues.ramp.startBufferOffset < currentEndFrame
1366 && event.eventValues.ramp.startBufferOffset + event.eventValues.ramp.durationInFrames > currentStartFrame;
1367 else /* kParameterEvent_Immediate */
1368 // actually, for the same parameter, there may be future immediate events which override this one,
1369 // but it's OK since the event list is sorted in time order, we're guaranteed to end up with the current one
1370 eventFallsInSlice = event.eventValues.immediate.bufferOffset <= currentStartFrame;
1372 if(eventFallsInSlice)
1374 AUElement *element = GetElement(event.scope, event.element );
1376 if(element) element->SetScheduledEvent( event.parameter,
1379 currentEndFrame - currentStartFrame );
1385 // Finally, actually do the processing for this slice.....
1387 result = ProcessScheduledSlice( inUserData,
1390 inFramesToProcess );
1392 if(result != noErr) break;
1394 framesRemaining -= framesThisTime;
1395 currentStartFrame = currentEndFrame; // now start from where we left off last time
1401 //_____________________________________________________________________________
1403 void AUBase::SetWantsRenderThreadID (bool inFlag)
1405 if (inFlag == mWantsRenderThreadID)
1408 mWantsRenderThreadID = inFlag;
1409 if (!mWantsRenderThreadID)
1410 mRenderThreadID = NULL;
1413 //_____________________________________________________________________________
1416 //_____________________________________________________________________________
1418 OSStatus AUBase::DoRender( AudioUnitRenderActionFlags & ioActionFlags,
1419 const AudioTimeStamp & inTimeStamp,
1421 UInt32 inFramesToProcess,
1422 AudioBufferList & ioData)
1425 RenderCallbackList::iterator rcit;
1427 AUTRACE(kCATrace_AUBaseRenderStart, mComponentInstance, (uintptr_t)this, inBusNumber, inFramesToProcess, (uintptr_t)ioData.mBuffers[0].mData);
1431 ca_require(IsInitialized(), Uninitialized);
1432 ca_require(mAudioUnitAPIVersion >= 2, ParamErr);
1433 if (inFramesToProcess > mMaxFramesPerSlice) {
1434 static time_t lastTimeMessagePrinted = 0;
1435 time_t now = time(NULL);
1436 if (now != lastTimeMessagePrinted) {
1437 lastTimeMessagePrinted = now;
1438 syslog(LOG_ERR, "kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=%u, mMaxFramesPerSlice=%u", (unsigned)inFramesToProcess, (unsigned)mMaxFramesPerSlice);
1439 DebugMessageN4("%s:%d inFramesToProcess=%u, mMaxFramesPerSlice=%u; TooManyFrames", __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)mMaxFramesPerSlice);
1443 ca_require (!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr);
1445 AUOutputElement *output = GetOutput(inBusNumber); // will throw if non-existant
1446 if (output->GetStreamFormat().NumberChannelStreams() != ioData.mNumberBuffers) {
1447 DebugMessageN4("%s:%d ioData.mNumberBuffers=%u, output->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1448 __FILE__, __LINE__, (unsigned)ioData.mNumberBuffers, (unsigned)output->GetStreamFormat().NumberChannelStreams());
1452 unsigned expectedBufferByteSize = inFramesToProcess * output->GetStreamFormat().mBytesPerFrame;
1453 for (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) {
1454 AudioBuffer &buf = ioData.mBuffers[ibuf];
1455 if (buf.mData != NULL) {
1456 // only care about the size if the buffer is non-null
1457 if (buf.mDataByteSize < expectedBufferByteSize) {
1458 // if the buffer is too small, we cannot render safely. kAudio_ParamError.
1459 DebugMessageN7("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1460 __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)output->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibuf, (unsigned)buf.mDataByteSize);
1463 // Some clients incorrectly pass bigger buffers than expectedBufferByteSize.
1464 // We will generally set the buffer size at the end of rendering, before we return.
1465 // However we should ensure that no one, DURING rendering, READS a
1466 // potentially incorrect size. This can lead to doing too much work, or
1467 // reading past the end of an input buffer into unmapped memory.
1468 buf.mDataByteSize = expectedBufferByteSize;
1472 if (WantsRenderThreadID())
1475 mRenderThreadID = pthread_self();
1476 #elif TARGET_OS_WIN32
1477 mRenderThreadID = GetCurrentThreadId();
1481 AudioUnitRenderActionFlags flags;
1482 if (mRenderCallbacksTouched) {
1483 mRenderCallbacks.update();
1484 flags = ioActionFlags | kAudioUnitRenderAction_PreRender;
1485 for (rcit = mRenderCallbacks.begin(); rcit != mRenderCallbacks.end(); ++rcit) {
1486 RenderCallback &rc = *rcit;
1487 AUTRACE(kCATrace_AUBaseRenderCallbackStart, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 1, 0);
1488 (*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon,
1490 &inTimeStamp, inBusNumber, inFramesToProcess, &ioData);
1491 AUTRACE(kCATrace_AUBaseRenderCallbackEnd, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 1, 0);
1495 theError = DoRenderBus(ioActionFlags, inTimeStamp, inBusNumber, output, inFramesToProcess, ioData);
1497 if (mRenderCallbacksTouched) {
1498 flags = ioActionFlags | kAudioUnitRenderAction_PostRender;
1500 if (SetRenderError (theError)) {
1501 flags |= kAudioUnitRenderAction_PostRenderError;
1504 for (rcit = mRenderCallbacks.begin(); rcit != mRenderCallbacks.end(); ++rcit) {
1505 RenderCallback &rc = *rcit;
1506 AUTRACE(kCATrace_AUBaseRenderCallbackStart, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 2, 0);
1507 (*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon,
1509 &inTimeStamp, inBusNumber, inFramesToProcess, &ioData);
1510 AUTRACE(kCATrace_AUBaseRenderCallbackEnd, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 2, 0);
1514 // The vector's being emptied
1515 // because these events should only apply to this Render cycle, so anything
1516 // left over is from a preceding cycle and should be dumped. New scheduled
1517 // parameters must be scheduled from the next pre-render callback.
1518 if (!mParamList.empty())
1522 catch (OSStatus err) {
1532 AUTRACE(kCATrace_AUBaseRenderEnd, mComponentInstance, (intptr_t)this, theError, ioActionFlags, CATrace::ablData(ioData));
1536 Uninitialized: theError = kAudioUnitErr_Uninitialized; goto errexit;
1537 ParamErr: theError = kAudio_ParamError; goto errexit;
1538 TooManyFrames: theError = kAudioUnitErr_TooManyFramesToProcess; goto errexit;
1540 DebugMessageN2 (" from %s, render err: %d", GetLoggingString(), (int)theError);
1541 SetRenderError(theError);
1545 //_____________________________________________________________________________
1547 OSStatus AUBase::DoProcess ( AudioUnitRenderActionFlags & ioActionFlags,
1548 const AudioTimeStamp & inTimeStamp,
1549 UInt32 inFramesToProcess,
1550 AudioBufferList & ioData)
1553 AUTRACE(kCATrace_AUBaseRenderStart, mComponentInstance, (intptr_t)this, -1, inFramesToProcess, 0);
1558 if (!(ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)) {
1559 ca_require(IsInitialized(), Uninitialized);
1560 ca_require(inFramesToProcess <= mMaxFramesPerSlice, TooManyFrames);
1561 ca_require(!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr);
1563 AUInputElement *input = GetInput(0); // will throw if non-existant
1564 if (input->GetStreamFormat().NumberChannelStreams() != ioData.mNumberBuffers) {
1565 DebugMessageN4("%s:%d ioData.mNumberBuffers=%u, input->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1566 __FILE__, __LINE__, (unsigned)ioData.mNumberBuffers, (unsigned)input->GetStreamFormat().NumberChannelStreams());
1570 unsigned expectedBufferByteSize = inFramesToProcess * input->GetStreamFormat().mBytesPerFrame;
1571 for (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) {
1572 AudioBuffer &buf = ioData.mBuffers[ibuf];
1573 if (buf.mData != NULL) {
1574 // only care about the size if the buffer is non-null
1575 if (buf.mDataByteSize < expectedBufferByteSize) {
1576 // if the buffer is too small, we cannot render safely. kAudio_ParamError.
1577 DebugMessageN7("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1578 __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)input->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibuf, (unsigned)buf.mDataByteSize);
1581 // Some clients incorrectly pass bigger buffers than expectedBufferByteSize.
1582 // We will generally set the buffer size at the end of rendering, before we return.
1583 // However we should ensure that no one, DURING rendering, READS a
1584 // potentially incorrect size. This can lead to doing too much work, or
1585 // reading past the end of an input buffer into unmapped memory.
1586 buf.mDataByteSize = expectedBufferByteSize;
1591 if (WantsRenderThreadID())
1594 mRenderThreadID = pthread_self();
1595 #elif TARGET_OS_WIN32
1596 mRenderThreadID = GetCurrentThreadId();
1600 if (NeedsToRender (inTimeStamp)) {
1601 theError = ProcessBufferLists (ioActionFlags, ioData, ioData, inFramesToProcess);
1606 catch (OSStatus err) {
1616 AUTRACE(kCATrace_AUBaseRenderEnd, mComponentInstance, (intptr_t)this, theError, ioActionFlags, CATrace::ablData(ioData));
1620 Uninitialized: theError = kAudioUnitErr_Uninitialized; goto errexit;
1621 ParamErr: theError = kAudio_ParamError; goto errexit;
1622 TooManyFrames: theError = kAudioUnitErr_TooManyFramesToProcess; goto errexit;
1624 DebugMessageN2 (" from %s, process err: %d", GetLoggingString(), (int)theError);
1625 SetRenderError(theError);
1629 OSStatus AUBase::DoProcessMultiple ( AudioUnitRenderActionFlags & ioActionFlags,
1630 const AudioTimeStamp & inTimeStamp,
1631 UInt32 inFramesToProcess,
1632 UInt32 inNumberInputBufferLists,
1633 const AudioBufferList ** inInputBufferLists,
1634 UInt32 inNumberOutputBufferLists,
1635 AudioBufferList ** ioOutputBufferLists)
1642 if (!(ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)) {
1643 ca_require(IsInitialized(), Uninitialized);
1644 ca_require(inFramesToProcess <= mMaxFramesPerSlice, TooManyFrames);
1645 ca_require (!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr);
1647 for (unsigned ibl = 0; ibl < inNumberInputBufferLists; ++ibl) {
1648 if (inInputBufferLists[ibl] != NULL) {
1649 AUInputElement *input = GetInput(ibl); // will throw if non-existant
1650 unsigned expectedBufferByteSize = inFramesToProcess * input->GetStreamFormat().mBytesPerFrame;
1652 if (input->GetStreamFormat().NumberChannelStreams() != inInputBufferLists[ibl]->mNumberBuffers) {
1653 DebugMessageN5("%s:%d inInputBufferLists[%u]->mNumberBuffers=%u, input->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1654 __FILE__, __LINE__, ibl, (unsigned)inInputBufferLists[ibl]->mNumberBuffers, (unsigned)input->GetStreamFormat().NumberChannelStreams());
1658 for (unsigned ibuf = 0; ibuf < inInputBufferLists[ibl]->mNumberBuffers; ++ibuf) {
1659 const AudioBuffer &buf = inInputBufferLists[ibl]->mBuffers[ibuf];
1660 if (buf.mData != NULL) {
1661 if (buf.mDataByteSize < expectedBufferByteSize) {
1662 // the buffer is too small
1663 DebugMessageN8("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; inInputBufferLists[%u].mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1664 __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)input->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibl, ibuf, (unsigned)buf.mDataByteSize);
1668 // the buffer must exist
1673 // skip NULL input audio buffer list
1677 for (unsigned obl = 0; obl < inNumberOutputBufferLists; ++obl) {
1678 if (ioOutputBufferLists[obl] != NULL) {
1679 AUOutputElement *output = GetOutput(obl); // will throw if non-existant
1680 unsigned expectedBufferByteSize = inFramesToProcess * output->GetStreamFormat().mBytesPerFrame;
1682 if (output->GetStreamFormat().NumberChannelStreams() != ioOutputBufferLists[obl]->mNumberBuffers) {
1683 DebugMessageN5("%s:%d ioOutputBufferLists[%u]->mNumberBuffers=%u, output->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1684 __FILE__, __LINE__, obl, (unsigned)ioOutputBufferLists[obl]->mNumberBuffers, (unsigned)output->GetStreamFormat().NumberChannelStreams());
1688 for (unsigned obuf = 0; obuf < ioOutputBufferLists[obl]->mNumberBuffers; ++obuf) {
1689 AudioBuffer &buf = ioOutputBufferLists[obl]->mBuffers[obuf];
1690 if (buf.mData != NULL) {
1691 // only care about the size if the buffer is non-null
1692 if (buf.mDataByteSize < expectedBufferByteSize) {
1693 // if the buffer is too small, we cannot render safely. kAudio_ParamError.
1694 DebugMessageN8("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioOutputBufferLists[%u]->mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1695 __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)output->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, obl, obuf, (unsigned)buf.mDataByteSize);
1698 // Some clients incorrectly pass bigger buffers than expectedBufferByteSize.
1699 // We will generally set the buffer size at the end of rendering, before we return.
1700 // However we should ensure that no one, DURING rendering, READS a
1701 // potentially incorrect size. This can lead to doing too much work, or
1702 // reading past the end of an input buffer into unmapped memory.
1703 buf.mDataByteSize = expectedBufferByteSize;
1707 // skip NULL output audio buffer list
1712 if (WantsRenderThreadID())
1715 mRenderThreadID = pthread_self();
1716 #elif TARGET_OS_WIN32
1717 mRenderThreadID = GetCurrentThreadId();
1721 if (NeedsToRender (inTimeStamp)) {
1722 theError = ProcessMultipleBufferLists (ioActionFlags, inFramesToProcess, inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists, ioOutputBufferLists);
1726 catch (OSStatus err) {
1739 Uninitialized: theError = kAudioUnitErr_Uninitialized; goto errexit;
1740 ParamErr: theError = kAudio_ParamError; goto errexit;
1741 TooManyFrames: theError = kAudioUnitErr_TooManyFramesToProcess; goto errexit;
1743 DebugMessageN2 (" from %s, processmultiple err: %d", GetLoggingString(), (int)theError);
1744 SetRenderError(theError);
1748 //_____________________________________________________________________________
1750 OSStatus AUBase::SetInputCallback( UInt32 inPropertyID,
1751 AudioUnitElement inElement,
1752 AURenderCallback inProc,
1755 AUInputElement *input = GetInput(inElement); // may throw
1757 input->SetInputCallback(inProc, inRefCon);
1758 PropertyChanged(inPropertyID, kAudioUnitScope_Input, inElement);
1763 //_____________________________________________________________________________
1765 OSStatus AUBase::SetConnection( const AudioUnitConnection & inConnection)
1769 AUInputElement *input = GetInput(inConnection.destInputNumber); // may throw
1771 if (inConnection.sourceAudioUnit) {
1772 // connecting, not disconnecting
1773 CAStreamBasicDescription sourceDesc;
1774 UInt32 size = sizeof(CAStreamBasicDescription);
1775 ca_require_noerr(err = AudioUnitGetProperty(
1776 inConnection.sourceAudioUnit,
1777 kAudioUnitProperty_StreamFormat,
1778 kAudioUnitScope_Output,
1779 inConnection.sourceOutputNumber,
1782 ca_require_noerr(err = DispatchSetProperty (kAudioUnitProperty_StreamFormat,
1783 kAudioUnitScope_Input, inConnection.destInputNumber,
1784 &sourceDesc, sizeof(CAStreamBasicDescription)), errexit);
1786 input->SetConnection(inConnection);
1788 PropertyChanged(kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, inConnection.destInputNumber);
1795 //_____________________________________________________________________________
1797 UInt32 AUBase::SupportedNumChannels ( const AUChannelInfo** outInfo)
1802 //_____________________________________________________________________________
1804 bool AUBase::ValidFormat( AudioUnitScope inScope,
1805 AudioUnitElement inElement,
1806 const CAStreamBasicDescription & inNewFormat)
1808 return FormatIsCanonical(inNewFormat);
1811 //_____________________________________________________________________________
1813 bool AUBase::IsStreamFormatWritable( AudioUnitScope scope,
1814 AudioUnitElement element)
1817 case kAudioUnitScope_Input:
1819 AUInputElement *input = GetInput(element);
1820 if (input->HasConnection()) return false; // can't write format when input comes from connection
1823 case kAudioUnitScope_Output:
1824 return StreamFormatWritable(scope, element);
1826 //#warning "aliasing of global scope format should be pushed to subclasses"
1827 case kAudioUnitScope_Global:
1828 return StreamFormatWritable(kAudioUnitScope_Output, 0);
1833 //_____________________________________________________________________________
1835 const CAStreamBasicDescription &
1836 AUBase::GetStreamFormat( AudioUnitScope inScope,
1837 AudioUnitElement inElement)
1839 //#warning "aliasing of global scope format should be pushed to subclasses"
1840 AUIOElement *element;
1843 case kAudioUnitScope_Input:
1844 element = Inputs().GetIOElement(inElement);
1846 case kAudioUnitScope_Output:
1847 element = Outputs().GetIOElement(inElement);
1849 case kAudioUnitScope_Global: // global stream description is an alias for that of output 0
1850 element = Outputs().GetIOElement(0);
1853 COMPONENT_THROW(kAudioUnitErr_InvalidScope);
1855 return element->GetStreamFormat();
1858 OSStatus AUBase::SetBusCount( AudioUnitScope inScope,
1861 if (IsInitialized())
1862 return kAudioUnitErr_Initialized;
1864 GetScope(inScope).SetNumberOfElements(inCount);
1868 //_____________________________________________________________________________
1870 OSStatus AUBase::ChangeStreamFormat( AudioUnitScope inScope,
1871 AudioUnitElement inElement,
1872 const CAStreamBasicDescription & inPrevFormat,
1873 const CAStreamBasicDescription & inNewFormat)
1875 //#warning "aliasing of global scope format should be pushed to subclasses"
1876 AUIOElement *element;
1879 case kAudioUnitScope_Input:
1880 element = Inputs().GetIOElement(inElement);
1882 case kAudioUnitScope_Output:
1883 element = Outputs().GetIOElement(inElement);
1885 case kAudioUnitScope_Global:
1886 element = Outputs().GetIOElement(0);
1889 COMPONENT_THROW(kAudioUnitErr_InvalidScope);
1891 element->SetStreamFormat(inNewFormat);
1892 PropertyChanged(kAudioUnitProperty_StreamFormat, inScope, inElement);
1896 UInt32 AUBase::GetChannelLayoutTags( AudioUnitScope inScope,
1897 AudioUnitElement inElement,
1898 AudioChannelLayoutTag * outLayoutTags)
1900 return GetIOElement(inScope, inElement)->GetChannelLayoutTags(outLayoutTags);
1903 UInt32 AUBase::GetAudioChannelLayout( AudioUnitScope scope,
1904 AudioUnitElement element,
1905 AudioChannelLayout * outLayoutPtr,
1906 Boolean & outWritable)
1908 AUIOElement * el = GetIOElement(scope, element);
1909 return el->GetAudioChannelLayout(outLayoutPtr, outWritable);
1912 OSStatus AUBase::RemoveAudioChannelLayout( AudioUnitScope inScope,
1913 AudioUnitElement inElement)
1915 OSStatus result = noErr;
1916 AUIOElement * el = GetIOElement(inScope, inElement);
1918 if (el->GetAudioChannelLayout(NULL, writable)) {
1919 result = el->RemoveAudioChannelLayout();
1924 OSStatus AUBase::SetAudioChannelLayout( AudioUnitScope inScope,
1925 AudioUnitElement inElement,
1926 const AudioChannelLayout * inLayout)
1928 AUIOElement* ioEl = GetIOElement (inScope, inElement);
1930 // the num channels of the layout HAS TO MATCH the current channels of the Element's stream format
1931 UInt32 currentChannels = ioEl->GetStreamFormat().NumberChannels();
1932 UInt32 numChannelsInLayout = CAAudioChannelLayout::NumberChannels(*inLayout);
1933 if (currentChannels != numChannelsInLayout)
1934 return kAudioUnitErr_InvalidPropertyValue;
1936 UInt32 numLayouts = GetChannelLayoutTags (inScope, inElement, NULL);
1937 if (numLayouts == 0)
1938 return kAudioUnitErr_InvalidProperty;
1939 AudioChannelLayoutTag *tags = (AudioChannelLayoutTag *)CA_malloc (numLayouts * sizeof (AudioChannelLayoutTag));
1940 GetChannelLayoutTags (inScope, inElement, tags);
1941 bool foundTag = false;
1942 for (unsigned int i = 0; i < numLayouts; ++i) {
1943 if (tags[i] == inLayout->mChannelLayoutTag || tags[i] == kAudioChannelLayoutTag_UseChannelDescriptions) {
1950 if (foundTag == false)
1951 return kAudioUnitErr_InvalidPropertyValue;
1953 return ioEl->SetAudioChannelLayout(*inLayout);
1956 static void AddNumToDictionary (CFMutableDictionaryRef dict, CFStringRef key, SInt32 value)
1958 CFNumberRef num = CFNumberCreate (NULL, kCFNumberSInt32Type, &value);
1959 CFDictionarySetValue (dict, key, num);
1963 #define kCurrentSavedStateVersion 0
1965 OSStatus AUBase::SaveState( CFPropertyListRef * outData)
1967 AudioComponentDescription desc = GetComponentDescription();
1969 CFMutableDictionaryRef dict = CFDictionaryCreateMutable (NULL, 0,
1970 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1972 // first step -> save the version to the data ref
1973 SInt32 value = kCurrentSavedStateVersion;
1974 AddNumToDictionary (dict, kVersionString, value);
1976 // second step -> save the component type, subtype, manu to the data ref
1977 value = desc.componentType;
1978 AddNumToDictionary (dict, kTypeString, value);
1980 value = desc.componentSubType;
1981 AddNumToDictionary (dict, kSubtypeString, value);
1983 value = desc.componentManufacturer;
1984 AddNumToDictionary (dict, kManufacturerString, value);
1986 // fourth step -> save the state of all parameters on all scopes and elements
1987 CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
1988 for (AudioUnitScope iscope = 0; iscope < 3; ++iscope) {
1989 AUScope &scope = GetScope(iscope);
1990 scope.SaveState (data);
1993 SaveExtendedScopes(data);
1995 // save all this in the data section of the dictionary
1996 CFDictionarySetValue(dict, kDataString, data);
1999 //OK - now we're going to do some properties
2000 //save the preset name...
2001 CFDictionarySetValue (dict, kNameString, mCurrentPreset.presetName);
2003 // Does the unit support the RenderQuality property - if so, save it...
2005 OSStatus result = DispatchGetProperty (kAudioUnitProperty_RenderQuality,
2006 kAudioUnitScope_Global,
2010 if (result == noErr) {
2011 AddNumToDictionary (dict, kRenderQualityString, value);
2014 // Does the unit support the CPULoad Quality property - if so, save it...
2016 result = DispatchGetProperty (6/*kAudioUnitProperty_CPULoad*/,
2017 kAudioUnitScope_Global,
2021 if (result == noErr) {
2022 CFNumberRef num = CFNumberCreate (NULL, kCFNumberFloatType, &cpuLoad);
2023 CFDictionarySetValue (dict, kCPULoadString, num);
2027 // Do we have any element names for any of our scopes?
2028 // first check to see if we have any names...
2029 bool foundName = false;
2030 for (AudioUnitScope i = 0; i < kNumScopes; ++i) {
2031 foundName = GetScope (i).HasElementWithName();
2035 // OK - we found a name away we go...
2037 CFMutableDictionaryRef nameDict = CFDictionaryCreateMutable (NULL, 0,
2038 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2039 for (AudioUnitScope i = 0; i < kNumScopes; ++i) {
2040 GetScope (i).AddElementNamesToDict (nameDict);
2043 CFDictionarySetValue (dict, kElementNameString, nameDict);
2044 CFRelease (nameDict);
2053 //_____________________________________________________________________________
2055 OSStatus AUBase::RestoreState( CFPropertyListRef plist)
2057 if (CFGetTypeID(plist) != CFDictionaryGetTypeID()) return kAudioUnitErr_InvalidPropertyValue;
2059 AudioComponentDescription desc = GetComponentDescription();
2061 CFDictionaryRef dict = static_cast<CFDictionaryRef>(plist);
2063 // zeroeth step - make sure the Part key is NOT present, as this method is used
2064 // to restore the GLOBAL state of the dictionary
2065 if (CFDictionaryContainsKey (dict, kPartString))
2066 return kAudioUnitErr_InvalidPropertyValue;
2068 // first step -> check the saved version in the data ref
2069 // at this point we're only dealing with version==0
2070 CFNumberRef cfnum = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue (dict, kVersionString));
2071 if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue;
2073 CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2074 if (value != kCurrentSavedStateVersion) return kAudioUnitErr_InvalidPropertyValue;
2076 // second step -> check that this data belongs to this kind of audio unit
2077 // by checking the component subtype and manuID
2078 // We're not checking the type, since there may be different versions (effect, format-converter, offline)
2079 // of essentially the same AU
2080 cfnum = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue (dict, kSubtypeString));
2081 if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue;
2082 CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2083 if (UInt32(value) != desc.componentSubType) return kAudioUnitErr_InvalidPropertyValue;
2085 cfnum = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue (dict, kManufacturerString));
2086 if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue;
2087 CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2088 if (UInt32(value) != desc.componentManufacturer) return kAudioUnitErr_InvalidPropertyValue;
2090 // fourth step -> restore the state of all of the parameters for each scope and element
2091 CFDataRef data = reinterpret_cast<CFDataRef>(CFDictionaryGetValue (dict, kDataString));
2094 const UInt8 *p, *pend;
2096 p = CFDataGetBytePtr(data);
2097 pend = p + CFDataGetLength(data);
2099 // we have a zero length data, which may just mean there were no parameters to save!
2100 // if (p >= pend) return noErr;
2103 UInt32 scopeIdx = CFSwapInt32BigToHost(*(UInt32 *)p);
2104 p += sizeof(UInt32);
2106 AUScope &scope = GetScope(scopeIdx);
2107 p = scope.RestoreState(p);
2111 //OK - now we're going to do some properties
2112 //restore the preset name...
2113 CFStringRef name = reinterpret_cast<CFStringRef>(CFDictionaryGetValue (dict, kNameString));
2114 if (mCurrentPreset.presetName) CFRelease (mCurrentPreset.presetName);
2117 mCurrentPreset.presetName = name;
2118 mCurrentPreset.presetNumber = -1;
2120 else { // no name entry make the default one
2121 mCurrentPreset.presetName = kUntitledString;
2122 mCurrentPreset.presetNumber = -1;
2125 CFRetain (mCurrentPreset.presetName);
2126 #if !CA_USE_AUDIO_PLUGIN_ONLY
2128 PropertyChanged(kAudioUnitProperty_CurrentPreset, kAudioUnitScope_Global, 0);
2131 PropertyChanged(kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0);
2133 // Does the dict contain render quality information?
2134 if (CFDictionaryGetValueIfPresent (dict, kRenderQualityString, reinterpret_cast<const void**>(&cfnum)))
2136 CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2137 DispatchSetProperty (kAudioUnitProperty_RenderQuality,
2138 kAudioUnitScope_Global,
2144 // Does the unit support the CPULoad Quality property - if so, save it...
2145 if (CFDictionaryGetValueIfPresent (dict, kCPULoadString, reinterpret_cast<const void**>(&cfnum)))
2148 CFNumberGetValue (cfnum, kCFNumberFloatType, &floatValue);
2149 DispatchSetProperty (6/*kAudioUnitProperty_CPULoad*/,
2150 kAudioUnitScope_Global,
2153 sizeof(floatValue));
2156 // Do we have any element names for any of our scopes?
2157 CFDictionaryRef nameDict;
2158 if (CFDictionaryGetValueIfPresent (dict, kElementNameString, reinterpret_cast<const void**>(&nameDict)))
2161 for (int i = 0; i < kNumScopes; ++i)
2163 snprintf (string, sizeof(string), "%d", i);
2164 CFStringRef key = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII);
2165 CFDictionaryRef elementDict;
2166 if (CFDictionaryGetValueIfPresent (nameDict, key, reinterpret_cast<const void**>(&elementDict)))
2168 bool didAddElements = GetScope (i).RestoreElementNames (elementDict);
2170 PropertyChanged (kAudioUnitProperty_ElementCount, i, 0);
2179 OSStatus AUBase::GetPresets ( CFArrayRef * outData) const
2181 return kAudioUnitErr_InvalidProperty;
2184 OSStatus AUBase::NewFactoryPresetSet (const AUPreset & inNewFactoryPreset)
2186 return kAudioUnitErr_InvalidProperty;
2189 OSStatus AUBase::NewCustomPresetSet (const AUPreset & inNewCustomPreset)
2191 CFRelease (mCurrentPreset.presetName);
2192 mCurrentPreset = inNewCustomPreset;
2193 CFRetain (mCurrentPreset.presetName);
2197 // set the default preset for the unit -> the number of the preset MUST be >= 0
2198 // and the name should be valid, or the preset WON'T take
2199 bool AUBase::SetAFactoryPresetAsCurrent (const AUPreset & inPreset)
2201 if (inPreset.presetNumber < 0 || inPreset.presetName == NULL) return false;
2202 CFRelease (mCurrentPreset.presetName);
2203 mCurrentPreset = inPreset;
2204 CFRetain (mCurrentPreset.presetName);
2208 #if !CA_USE_AUDIO_PLUGIN_ONLY
2209 int AUBase::GetNumCustomUIComponents ()
2214 void AUBase::GetUIComponentDescs (ComponentDescription* inDescArray) {}
2217 bool AUBase::HasIcon ()
2219 #if !CA_NO_AU_UI_FEATURES
2220 CFURLRef url = CopyIconLocation();
2229 CFURLRef AUBase::CopyIconLocation ()
2234 //_____________________________________________________________________________
2236 OSStatus AUBase::GetParameterList( AudioUnitScope inScope,
2237 AudioUnitParameterID * outParameterList,
2238 UInt32 & outNumParameters)
2240 AUScope &scope = GetScope(inScope);
2241 AUElement *elementWithMostParameters = NULL;
2242 UInt32 maxNumParams = 0;
2244 int nElems = scope.GetNumberOfElements();
2245 for (int ielem = 0; ielem < nElems; ++ielem) {
2246 AUElement *element = scope.GetElement(ielem);
2247 UInt32 nParams = element->GetNumberOfParameters();
2248 if (nParams > maxNumParams) {
2249 maxNumParams = nParams;
2250 elementWithMostParameters = element;
2254 if (outParameterList != NULL && elementWithMostParameters != NULL)
2255 elementWithMostParameters->GetParameterList(outParameterList);
2257 outNumParameters = maxNumParams;
2261 //_____________________________________________________________________________
2263 OSStatus AUBase::GetParameterInfo( AudioUnitScope inScope,
2264 AudioUnitParameterID inParameterID,
2265 AudioUnitParameterInfo &outParameterInfo )
2267 return kAudioUnitErr_InvalidParameter;
2270 //_____________________________________________________________________________
2272 OSStatus AUBase::GetParameterValueStrings(AudioUnitScope inScope,
2273 AudioUnitParameterID inParameterID,
2274 CFArrayRef * outStrings)
2276 return kAudioUnitErr_InvalidProperty;
2279 //_____________________________________________________________________________
2281 OSStatus AUBase::GetParameterHistoryInfo( AudioUnitScope inScope,
2282 AudioUnitParameterID inParameterID,
2283 Float32 & outUpdatesPerSecond,
2284 Float32 & outHistoryDurationInSeconds)
2286 return kAudioUnitErr_InvalidProperty;
2290 //_____________________________________________________________________________
2292 OSStatus AUBase::CopyClumpName( AudioUnitScope inScope,
2294 UInt32 inDesiredNameLength,
2295 CFStringRef * outClumpName)
2297 return kAudioUnitErr_InvalidProperty;
2300 //_____________________________________________________________________________
2302 void AUBase::SetNumberOfElements( AudioUnitScope inScope,
2305 if (inScope == kAudioUnitScope_Global && numElements != 1)
2306 COMPONENT_THROW(kAudioUnitErr_InvalidScope);
2308 GetScope(inScope).SetNumberOfElements(numElements);
2311 //_____________________________________________________________________________
2313 AUElement * AUBase::CreateElement( AudioUnitScope scope,
2314 AudioUnitElement element)
2317 case kAudioUnitScope_Global:
2318 return new AUElement(this);
2319 case kAudioUnitScope_Input:
2320 return new AUInputElement(this);
2321 case kAudioUnitScope_Output:
2322 return new AUOutputElement(this);
2323 #if !CA_BASIC_AU_FEATURES
2324 case kAudioUnitScope_Group:
2325 return new AUElement(this);
2326 case kAudioUnitScope_Part:
2327 return new AUElement(this);
2330 COMPONENT_THROW(kAudioUnitErr_InvalidScope);
2332 return NULL; // get rid of compiler warning
2335 //_____________________________________________________________________________
2337 bool AUBase::FormatIsCanonical( const CAStreamBasicDescription &f)
2339 return (f.mFormatID == kAudioFormatLinearPCM
2340 && f.mFramesPerPacket == 1
2341 && f.mBytesPerPacket == f.mBytesPerFrame
2342 // && f.mChannelsPerFrame >= 0 -- this is always true since it's unsigned
2343 // so far, it's a valid PCM format
2344 #if CA_PREFER_FIXED_POINT
2345 && (f.mFormatFlags & kLinearPCMFormatFlagIsFloat) == 0
2346 && (((f.mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift) == kAudioUnitSampleFractionBits)
2348 && (f.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0
2350 && ((f.mChannelsPerFrame == 1) || ((f.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0) == (mAudioUnitAPIVersion == 1))
2351 #if TARGET_RT_BIG_ENDIAN
2352 && (f.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) != 0
2354 && (f.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) == 0
2356 && f.mBitsPerChannel == 8 * sizeof(AudioUnitSampleType)
2357 && f.mBytesPerFrame == f.NumberInterleavedChannels() * sizeof(AudioUnitSampleType)
2361 //_____________________________________________________________________________
2363 void AUBase::MakeCanonicalFormat( CAStreamBasicDescription & f,
2366 f.SetAUCanonical(nChannels, mAudioUnitAPIVersion < 2); // interleaved for v1, non for v2
2367 f.mSampleRate = 0.0;
2370 const Float64 AUBase::kNoLastRenderedSampleTime = -1.;
2372 #include "AUBaseHelper.h"
2374 char* AUBase::GetLoggingString () const
2376 if (mLogString) return mLogString;
2378 AudioComponentDescription desc = GetComponentDescription();
2380 const size_t logStringSize = 256;
2381 const_cast<AUBase*>(this)->mLogString = new char[logStringSize];
2385 snprintf (const_cast<AUBase*>(this)->mLogString, logStringSize, "AU (%p): %s %s %s",
2386 GetComponentInstance(),
2387 CAStringForOSType(desc.componentType, str, sizeof(str)),
2388 CAStringForOSType(desc.componentSubType, str1, sizeof(str1)),
2389 CAStringForOSType(desc.componentManufacturer, str2, sizeof(str2)));