static OSStatus AUMethodSetProperty(void *self, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void *inData, UInt32 inDataSize)
{
    OSStatus result = noErr;
    try {
        AUI_LOCK
        if (inData && inDataSize)
            result = AUI->DispatchSetProperty(inID, inScope, inElement, inData, inDataSize);
        else {
            if (inData == NULL && inDataSize == 0) {
                result = AUI->DispatchRemovePropertyValue(inID, inScope, inElement);
            } else {
                if (inData == NULL) {
                    ca_debug_string("AudioUnitSetProperty: inData == NULL");
                    result = kAudio_ParamError;
                    goto finishSetProperty;
                }

                if (inDataSize == 0) {
                    ca_debug_string("AudioUnitSetProperty: inDataSize == 0");
                    result = kAudio_ParamError;
                    goto finishSetProperty;
                }
            }
        }
    }
    COMPONENT_CATCH
finishSetProperty:
    return result;
}
static OSStatus AUMethodGetProperty(void *self, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void *outData, UInt32 *ioDataSize)
{
    OSStatus result = noErr;
    try {
        UInt32 actualPropertySize, clientBufferSize;
        Boolean writable;
        char *tempBuffer;
        void *destBuffer;

        AUI_LOCK
        if (ioDataSize == NULL) {
            ca_debug_string("AudioUnitGetProperty: null size pointer");
            result = kAudio_ParamError;
            goto finishGetProperty;
        }
        if (outData == NULL) {
            UInt32 dataSize;

            result = AUI->DispatchGetPropertyInfo(inID, inScope, inElement, dataSize, writable);
            *ioDataSize = dataSize;
            goto finishGetProperty;
        }

        clientBufferSize = *ioDataSize;
        if (clientBufferSize == 0)
        {
            ca_debug_string("AudioUnitGetProperty: *ioDataSize == 0 on entry");
            // $$$ or should we allow this as a shortcut for finding the size?
            result = kAudio_ParamError;
            goto finishGetProperty;
        }

        result = AUI->DispatchGetPropertyInfo(inID, inScope, inElement, actualPropertySize, writable);
        if (result != noErr)
            goto finishGetProperty;

        if (clientBufferSize < actualPropertySize)
        {
            tempBuffer = new char[actualPropertySize];
            destBuffer = tempBuffer;
        } else {
            tempBuffer = NULL;
            destBuffer = outData;
        }

        result = AUI->DispatchGetProperty(inID, inScope, inElement, destBuffer);

        if (result == noErr) {
            if (clientBufferSize < actualPropertySize && tempBuffer != NULL)
            {
                memcpy(outData, tempBuffer, clientBufferSize);
                delete[] tempBuffer;
                // ioDataSize remains correct, the number of bytes we wrote
            } else
                *ioDataSize = actualPropertySize;
        } else
            *ioDataSize = 0;
    }
    COMPONENT_CATCH
finishGetProperty:
    return result;
}
OSStatus		AUBase::ComponentEntryDispatch(ComponentParameters *params, AUBase *This)
{
	if (This == NULL) return kAudio_ParamError;

	OSStatus result = noErr;

	switch (params->what) {
	case kComponentCanDoSelect:
		switch (GetSelectorForCanDo(params)) {
	// any selectors
			case kAudioUnitInitializeSelect:
			case kAudioUnitUninitializeSelect:
			case kAudioUnitGetPropertyInfoSelect:
			case kAudioUnitGetPropertySelect:
			case kAudioUnitSetPropertySelect:
			case kAudioUnitAddPropertyListenerSelect:
#if (!__LP64__)
			case kAudioUnitRemovePropertyListenerSelect:
#endif
			case kAudioUnitGetParameterSelect:
			case kAudioUnitSetParameterSelect:
			case kAudioUnitResetSelect:
				result = 1;
				break;
	// v1 selectors

	// v2 selectors
			case kAudioUnitRemovePropertyListenerWithUserDataSelect:
			case kAudioUnitAddRenderNotifySelect:
			case kAudioUnitRemoveRenderNotifySelect:
			case kAudioUnitScheduleParametersSelect:
			case kAudioUnitRenderSelect:
				result = (This->AudioUnitAPIVersion() > 1);
				break;
				
			default:
				return ComponentBase::ComponentEntryDispatch(params, This);
		}
		break;
		
	case kAudioUnitInitializeSelect:
	{
		CAMutex::Locker lock2(This->GetMutex());
		result = This->DoInitialize();
	}
		break;
		
	case kAudioUnitUninitializeSelect:
	{
		CAMutex::Locker lock2(This->GetMutex());
		This->DoCleanup();
		result = noErr;
	}
		break;

	case kAudioUnitGetPropertyInfoSelect:
		{
			CAMutex::Locker lock(This->GetMutex());
			PARAM(AudioUnitPropertyID, pinID, 0, 5);
			PARAM(AudioUnitScope, pinScope, 1, 5);
			PARAM(AudioUnitElement, pinElement, 2, 5);
			PARAM(UInt32 *, poutDataSize, 3, 5);
			PARAM(Boolean *, poutWritable, 4, 5);

			// pass our own copies so that we assume responsibility for testing
			// the caller's pointers against null and our C++ classes can
			// always assume they're non-null
			UInt32 dataSize;
			Boolean writable;
			
			result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, dataSize, writable);
			if (poutDataSize != NULL)
				*poutDataSize = dataSize;
			if (poutWritable != NULL)
				*poutWritable = writable;
		}
		break;

	case kAudioUnitGetPropertySelect:
		{
			CAMutex::Locker lock(This->GetMutex());
			PARAM(AudioUnitPropertyID, pinID, 0, 5);
			PARAM(AudioUnitScope, pinScope, 1, 5);
			PARAM(AudioUnitElement, pinElement, 2, 5);
			PARAM(void *, poutData, 3, 5);
			PARAM(UInt32 *, pioDataSize, 4, 5);

			UInt32 actualPropertySize, clientBufferSize;
			Boolean writable;
			char *tempBuffer;
			void *destBuffer;
			
			if (pioDataSize == NULL) {
				ca_debug_string("AudioUnitGetProperty: null size pointer");
				result = kAudio_ParamError;
				goto finishGetProperty;
			}
			if (poutData == NULL) {
				UInt32 dataSize;
				
				result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, dataSize, writable);
				*pioDataSize = dataSize;
				goto finishGetProperty;
			}
			
			clientBufferSize = *pioDataSize;
			if (clientBufferSize == 0)
			{
				ca_debug_string("AudioUnitGetProperty: *ioDataSize == 0 on entry");
				// $$$ or should we allow this as a shortcut for finding the size?
				result = kAudio_ParamError;
				goto finishGetProperty;
			}
			
			result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, 
													actualPropertySize, writable);
			if (result) 
				goto finishGetProperty;
			
			if (clientBufferSize < actualPropertySize) 
			{
				tempBuffer = new char[actualPropertySize];
				destBuffer = tempBuffer;
			} else {
				tempBuffer = NULL;
				destBuffer = poutData;
			}
			
			result = This->DispatchGetProperty(pinID, pinScope, pinElement, destBuffer);
			
			if (result == noErr) {
				if (clientBufferSize < actualPropertySize && tempBuffer != NULL)
				{
					memcpy(poutData, tempBuffer, clientBufferSize);
					delete[] tempBuffer;
					// pioDataSize remains correct, the number of bytes we wrote
				} else
					*pioDataSize = actualPropertySize;
			} else
				*pioDataSize = 0;

			finishGetProperty:
				;

		}
		break;
		
	case kAudioUnitSetPropertySelect:
		{
			CAMutex::Locker lock(This->GetMutex());
			PARAM(AudioUnitPropertyID, pinID, 0, 5);
			PARAM(AudioUnitScope, pinScope, 1, 5);
			PARAM(AudioUnitElement, pinElement, 2, 5);
			PARAM(const void *, pinData, 3, 5);
			PARAM(UInt32, pinDataSize, 4, 5);
			
			if (pinData && pinDataSize)
				result = This->DispatchSetProperty(pinID, pinScope, pinElement, pinData, pinDataSize);
			else {
				if (pinData == NULL && pinDataSize == 0) {
					result = This->DispatchRemovePropertyValue (pinID, pinScope, pinElement);
				} else {
					if (pinData == NULL) {
						ca_debug_string("AudioUnitSetProperty: inData == NULL");
						result = kAudio_ParamError;
						goto finishSetProperty;
					}

					if (pinDataSize == 0) {
						ca_debug_string("AudioUnitSetProperty: inDataSize == 0");
						result = kAudio_ParamError;
						goto finishSetProperty;
					}
				}
			}
			finishSetProperty:
					;

		}
		break;
		
	case kAudioUnitAddPropertyListenerSelect:
		{
			CAMutex::Locker lock(This->GetMutex());
			PARAM(AudioUnitPropertyID, pinID, 0, 3);
			PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 3);
			PARAM(void *, pinProcRefCon, 2, 3);
			result = This->AddPropertyListener(pinID, pinProc, pinProcRefCon);
		}
		break;

#if (!__LP64__)
	case kAudioUnitRemovePropertyListenerSelect:
		{
			CAMutex::Locker lock(This->GetMutex());
			PARAM(AudioUnitPropertyID, pinID, 0, 2);
			PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 2);
			result = This->RemovePropertyListener(pinID, pinProc, NULL, false);
		}
		break;
#endif

	case kAudioUnitRemovePropertyListenerWithUserDataSelect:
		{
			CAMutex::Locker lock(This->GetMutex());
			PARAM(AudioUnitPropertyID, pinID, 0, 3);
			PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 3);
			PARAM(void *, pinProcRefCon, 2, 3);
			result = This->RemovePropertyListener(pinID, pinProc, pinProcRefCon, true);
		}
		break;
		
	case kAudioUnitAddRenderNotifySelect:
		{
			CAMutex::Locker lock(This->GetMutex());
			PARAM(AURenderCallback, pinProc, 0, 2);
			PARAM(void *, pinProcRefCon, 1, 2);
			result = This->SetRenderNotification (pinProc, pinProcRefCon);
		}
		break;

	case kAudioUnitRemoveRenderNotifySelect:
		{
			CAMutex::Locker lock(This->GetMutex());
			PARAM(AURenderCallback, pinProc, 0, 2);
			PARAM(void *, pinProcRefCon, 1, 2);
			result = This->RemoveRenderNotification (pinProc, pinProcRefCon);
		}
		break;

	case kAudioUnitGetParameterSelect:
		{
			CAMutex::Locker lock(This->GetMutex());
			PARAM(AudioUnitParameterID, pinID, 0, 4);
			PARAM(AudioUnitScope, pinScope, 1, 4);
			PARAM(AudioUnitElement, pinElement, 2, 4);
			PARAM(AudioUnitParameterValue *, poutValue, 3, 4);
			result = (poutValue == NULL ? kAudio_ParamError : This->GetParameter(pinID, pinScope, pinElement, *poutValue));
		}
		break;

	case kAudioUnitSetParameterSelect:
		{
			CAMutex::Locker lock(This->GetMutex()); // is this realtime or no???
			PARAM(AudioUnitParameterID, pinID, 0, 5);
			PARAM(AudioUnitScope, pinScope, 1, 5);
			PARAM(AudioUnitElement, pinElement, 2, 5);
			PARAM(AudioUnitParameterValue, pinValue, 3, 5);
			PARAM(UInt32, pinBufferOffsetInFrames, 4, 5);
			result = This->SetParameter(pinID, pinScope, pinElement, pinValue, pinBufferOffsetInFrames);
		}
		break;

	case kAudioUnitScheduleParametersSelect:
		{
			CAMutex::Locker lock(This->GetMutex()); // is this realtime or no???
			if (This->AudioUnitAPIVersion() > 1)
			{
				PARAM(AudioUnitParameterEvent *, pinParameterEvent, 0, 2);
				PARAM(UInt32, pinNumParamEvents, 1, 2);
				result = This->ScheduleParameter (pinParameterEvent, pinNumParamEvents);
			} else
				result = badComponentSelector;
		}