OSStatus AUBase::DispatchGetProperty()

in Source/AUBase.cpp [477:676]


OSStatus AUBase::DispatchGetProperty(
	AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData)
{
	// NOTE: We're currently only called from AUBase::ComponentEntryDispatch, which
	// calls DispatchGetPropertyInfo first, which performs validation of the scope/element,
	// and ensures that the outData buffer is non-null and large enough.
	OSStatus result = noErr;

	switch (inID) {
	case kAudioUnitProperty_StreamFormat:
		*static_cast<AudioStreamBasicDescription*>(outData) = GetStreamFormat(inScope, inElement);
		break;

	case kAudioUnitProperty_SampleRate:
		*static_cast<Float64*>(outData) = GetStreamFormat(inScope, inElement).mSampleRate;
		break;

	case kAudioUnitProperty_ParameterList: {
		UInt32 nparams = 0;
		result = GetParameterList(inScope, static_cast<AudioUnitParameterID*>(outData), nparams);
		break;
	}

	case kAudioUnitProperty_ParameterInfo:
		*static_cast<AudioUnitParameterInfo*>(outData) = {};
		result =
			GetParameterInfo(inScope, inElement, *static_cast<AudioUnitParameterInfo*>(outData));
		break;

	case kAudioUnitProperty_ParameterHistoryInfo: {
		auto* const info = static_cast<AudioUnitParameterHistoryInfo*>(outData);
		result = GetParameterHistoryInfo(
			inScope, inElement, info->updatesPerSecond, info->historyDurationInSeconds);
		break;
	}

	case kAudioUnitProperty_ClassInfo: {
		*static_cast<CFPropertyListRef*>(outData) = nullptr;
		result = SaveState(static_cast<CFPropertyListRef*>(outData));
		break;
	}

	case kAudioUnitProperty_FactoryPresets: {
		*static_cast<CFArrayRef*>(outData) = nullptr;
		result = GetPresets(static_cast<CFArrayRef*>(outData));
		break;
	}

	case kAudioUnitProperty_PresentPreset: {
		*static_cast<AUPreset*>(outData) = mCurrentPreset;

		// retain current string (as client owns a reference to it and will release it)
		if ((inID == kAudioUnitProperty_PresentPreset) && (mCurrentPreset.presetName != nullptr)) {
			CFRetain(mCurrentPreset.presetName);
		}

		result = noErr;
		break;
	}

	case kAudioUnitProperty_ElementName: {
		const AUElement* const element = GetElement(inScope, inElement);
		const CFStringRef name = *element->GetName();
		AUSDK_Require(name != nullptr, kAudioUnitErr_PropertyNotInUse);
		CFRetain(name); // must return a +1 reference
		*static_cast<CFStringRef*>(outData) = name;
		break;
	}

	case kAudioUnitProperty_ElementCount:
		*static_cast<UInt32*>(outData) = GetScope(inScope).GetNumberOfElements();
		break;

	case kAudioUnitProperty_Latency:
		*static_cast<Float64*>(outData) = GetLatency();
		break;

	case kAudioUnitProperty_TailTime:
		AUSDK_Require(SupportsTail(), kAudioUnitErr_InvalidProperty);
		*static_cast<Float64*>(outData) = GetTailTime();
		break;

	case kAudioUnitProperty_MaximumFramesPerSlice:
		*static_cast<UInt32*>(outData) = mMaxFramesPerSlice;
		break;

	case kAudioUnitProperty_LastRenderError:
		*static_cast<OSStatus*>(outData) = mLastRenderError;
		mLastRenderError = 0;
		break;

	case kAudioUnitProperty_SupportedNumChannels: {
		const AUChannelInfo* infoPtr = nullptr;
		const UInt32 num = SupportedNumChannels(&infoPtr);
		if (num != 0 && infoPtr != nullptr) {
			memcpy(outData, infoPtr, num * sizeof(AUChannelInfo));
		}
		break;
	}

	case kAudioUnitProperty_SupportedChannelLayoutTags: {
		const auto tags = GetChannelLayoutTags(inScope, inElement);
		AUSDK_Require(!tags.empty(), kAudioUnitErr_InvalidProperty);
		AudioChannelLayoutTag* const ptr =
			outData != nullptr ? static_cast<AudioChannelLayoutTag*>(outData) : nullptr;
		if (ptr != nullptr) {
			memcpy(ptr, tags.data(), tags.size() * sizeof(AudioChannelLayoutTag));
		}
		break;
	}

	case kAudioUnitProperty_AudioChannelLayout: {
		AudioChannelLayout* const ptr =
			outData != nullptr ? static_cast<AudioChannelLayout*>(outData) : nullptr;
		bool writable = false;
		const UInt32 dataSize = GetAudioChannelLayout(inScope, inElement, ptr, writable);
		AUSDK_Require(dataSize != 0, kAudioUnitErr_InvalidProperty);
		break;
	}

	case kAudioUnitProperty_ShouldAllocateBuffer: {
		const auto& element = IOElement(inScope, inElement);
		*static_cast<UInt32*>(outData) = static_cast<UInt32>(element.WillAllocateBuffer());
		break;
	}

	case kAudioUnitProperty_ParameterValueStrings:
		result = GetParameterValueStrings(inScope, inElement, static_cast<CFArrayRef*>(outData));
		break;

	case kAudioUnitProperty_HostCallbacks:
		memcpy(outData, &mHostCallbackInfo, sizeof(mHostCallbackInfo));
		break;

	case kAudioUnitProperty_ContextName:
		if (const CFStringRef name = *mContextName) {
			CFRetain(name); // must return a +1 reference
			*static_cast<CFStringRef*>(outData) = name;
			result = noErr;
		} else {
			*static_cast<CFStringRef*>(outData) = nullptr;
			result = kAudioUnitErr_PropertyNotInUse;
		}
		break;

#if !TARGET_OS_IPHONE
	case kAudioUnitProperty_IconLocation: {
		const CFURLRef iconLocation = CopyIconLocation();
		AUSDK_Require(iconLocation != nullptr, kAudioUnitErr_InvalidProperty);
		*static_cast<CFURLRef*>(outData) = iconLocation;
		break;
	}
#endif

	case kAudioUnitProperty_ParameterClumpName: {
		auto* const ioClumpInfo = static_cast<AudioUnitParameterNameInfo*>(outData);
		AUSDK_Require(ioClumpInfo->inID != kAudioUnitClumpID_System,
			kAudioUnitErr_InvalidPropertyValue); // this ID value is reserved
		result = CopyClumpName(inScope, ioClumpInfo->inID,
			static_cast<UInt32>(std::max(ioClumpInfo->inDesiredLength, SInt32(0))),
			&ioClumpInfo->outName);

		// this is provided for compatbility with existing implementations that don't know
		// about this new mechanism
		if (result == kAudioUnitErr_InvalidProperty) {
			result = GetProperty(inID, inScope, inElement, outData);
		}
		break;
	}

	case 61: // kAudioUnitProperty_LastRenderSampleTime
		*static_cast<Float64*>(outData) = mCurrentRenderTime.mSampleTime;
		break;

	case kAudioUnitProperty_NickName:
		// Ownership follows Core Foundation's 'Copy Rule'
		if (const auto* const name = *mNickName) {
			CFRetain(name);
			*static_cast<CFStringRef*>(outData) = name;
		} else {
			*static_cast<CFStringRef*>(outData) = nullptr;
		}
		break;

#if AUSDK_MIDI2_AVAILABLE
	case kAudioUnitProperty_HostMIDIProtocol:
		if (const auto hostProtocol = mHostMIDIProtocol) {
			*static_cast<MIDIProtocolID*>(outData) = *hostProtocol;
		} else {
			result = kAudioUnitErr_PropertyNotInUse;
		}
		break;
#endif

	default:
		result = GetProperty(inID, inScope, inElement, outData);
		break;
	}
	return result;
}