OSStatus AUBase::DispatchSetProperty()

in Source/AUBase.cpp [683:882]


OSStatus AUBase::DispatchSetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope,
	AudioUnitElement inElement, const void* inData, UInt32 inDataSize)
{
	OSStatus result = noErr;

	switch (inID) {
	case kAudioUnitProperty_MakeConnection: {
		AUSDK_Require(
			inDataSize >= sizeof(AudioUnitConnection), kAudioUnitErr_InvalidPropertyValue);
		const auto& connection = *static_cast<const AudioUnitConnection*>(inData);
		result = SetConnection(connection);
		break;
	}

	case kAudioUnitProperty_SetRenderCallback: {
		AUSDK_Require(
			inDataSize >= sizeof(AURenderCallbackStruct), kAudioUnitErr_InvalidPropertyValue);
		const auto& callback = *static_cast<const AURenderCallbackStruct*>(inData);
		result = SetInputCallback(kAudioUnitProperty_SetRenderCallback, inElement,
			callback.inputProc, callback.inputProcRefCon);
		break;
	}

	case kAudioUnitProperty_ElementCount:
		AUSDK_Require(inDataSize == sizeof(UInt32), kAudioUnitErr_InvalidPropertyValue);
		AUSDK_Require(BusCountWritable(inScope), kAudioUnitErr_PropertyNotWritable);
		result = SetBusCount(inScope, *static_cast<const UInt32*>(inData));
		if (result == noErr) {
			PropertyChanged(inID, inScope, inElement);
		}
		break;

	case kAudioUnitProperty_MaximumFramesPerSlice:
		AUSDK_Require(inDataSize == sizeof(UInt32), kAudioUnitErr_InvalidPropertyValue);
		AUSDK_Require_noerr(CanSetMaxFrames());
		SetMaxFramesPerSlice(*static_cast<const UInt32*>(inData));
		break;

	case kAudioUnitProperty_StreamFormat: {
		constexpr static UInt32 kMinimumValidASBDSize = 36;
		AUSDK_Require(inDataSize >= kMinimumValidASBDSize, kAudioUnitErr_InvalidPropertyValue);
		AUSDK_Require(GetElement(inScope, inElement) != nullptr, kAudioUnitErr_InvalidElement);

		AudioStreamBasicDescription newDesc = {};
		// now we're going to be ultra conservative! because of discrepancies between
		// sizes of this struct based on aligment padding inconsistencies
		memcpy(&newDesc, inData, kMinimumValidASBDSize);

		AUSDK_Require(ASBD::MinimalSafetyCheck(newDesc), kAudioUnitErr_FormatNotSupported);

		AUSDK_Require(ValidFormat(inScope, inElement, newDesc), kAudioUnitErr_FormatNotSupported);

		const AudioStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement);

		if (!ASBD::IsEqual(curDesc, newDesc)) {
			AUSDK_Require(
				IsStreamFormatWritable(inScope, inElement), kAudioUnitErr_PropertyNotWritable);
			result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);
		}
		break;
	}

	case kAudioUnitProperty_SampleRate: {
		AUSDK_Require(inDataSize == sizeof(Float64), kAudioUnitErr_InvalidPropertyValue);
		AUSDK_Require(GetElement(inScope, inElement) != nullptr, kAudioUnitErr_InvalidElement);

		const AudioStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement);
		AudioStreamBasicDescription newDesc = curDesc;
		newDesc.mSampleRate = *static_cast<const Float64*>(inData);

		AUSDK_Require(ValidFormat(inScope, inElement, newDesc), kAudioUnitErr_FormatNotSupported);

		if (!ASBD::IsEqual(curDesc, newDesc)) {
			AUSDK_Require(
				IsStreamFormatWritable(inScope, inElement), kAudioUnitErr_PropertyNotWritable);
			result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);
		}
		break;
	}

	case kAudioUnitProperty_AudioChannelLayout: {
		const auto& layout = *static_cast<const AudioChannelLayout*>(inData);
		constexpr size_t headerSize = sizeof(AudioChannelLayout) - sizeof(AudioChannelDescription);

		AUSDK_Require(inDataSize >= offsetof(AudioChannelLayout, mNumberChannelDescriptions) +
										sizeof(AudioChannelLayout::mNumberChannelDescriptions),
			kAudioUnitErr_InvalidPropertyValue);
		AUSDK_Require(inDataSize >= headerSize + layout.mNumberChannelDescriptions *
													 sizeof(AudioChannelDescription),
			kAudioUnitErr_InvalidPropertyValue);
		result = SetAudioChannelLayout(inScope, inElement, &layout);
		if (result == noErr) {
			PropertyChanged(inID, inScope, inElement);
		}
		break;
	}

	case kAudioUnitProperty_ClassInfo:
		AUSDK_Require(inDataSize == sizeof(CFPropertyListRef*), kAudioUnitErr_InvalidPropertyValue);
		AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);
		result = RestoreState(*static_cast<const CFPropertyListRef*>(inData));
		break;

	case kAudioUnitProperty_PresentPreset: {
		AUSDK_Require(inDataSize == sizeof(AUPreset), kAudioUnitErr_InvalidPropertyValue);
		AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);
		const auto& newPreset = *static_cast<const AUPreset*>(inData);

		if (newPreset.presetNumber >= 0) {
			result = NewFactoryPresetSet(newPreset);
			// NewFactoryPresetSet SHOULD call SetAFactoryPreset if the preset is valid
			// from its own list of preset number->name
			if (result == noErr) {
				PropertyChanged(inID, inScope, inElement);
			}
		} else if (newPreset.presetName != nullptr) {
			result = NewCustomPresetSet(newPreset);
			if (result == noErr) {
				PropertyChanged(inID, inScope, inElement);
			}
		} else {
			result = kAudioUnitErr_InvalidPropertyValue;
		}
		break;
	}

	case kAudioUnitProperty_ElementName: {
		AUSDK_Require(GetElement(inScope, inElement) != nullptr, kAudioUnitErr_InvalidElement);
		AUSDK_Require(inDataSize == sizeof(CFStringRef), kAudioUnitErr_InvalidPropertyValue);
		const auto element = GetScope(inScope).GetElement(inElement);
		const CFStringRef inStr = *static_cast<const CFStringRef*>(inData);
		element->SetName(inStr);
		PropertyChanged(inID, inScope, inElement);
		break;
	}

	case kAudioUnitProperty_ShouldAllocateBuffer: {
		AUSDK_Require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output),
			kAudioUnitErr_InvalidScope);
		AUSDK_Require(GetElement(inScope, inElement) != nullptr, kAudioUnitErr_InvalidElement);
		AUSDK_Require(inDataSize == sizeof(UInt32), kAudioUnitErr_InvalidPropertyValue);
		AUSDK_Require(!IsInitialized(), kAudioUnitErr_Initialized);

		auto& element = IOElement(inScope, inElement);
		element.SetWillAllocateBuffer(*static_cast<const UInt32*>(inData) != 0);
		break;
	}

	case kAudioUnitProperty_HostCallbacks: {
		AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);
		const UInt32 availSize =
			std::min(inDataSize, static_cast<UInt32>(sizeof(HostCallbackInfo)));
		const bool hasChanged = memcmp(&mHostCallbackInfo, inData, availSize) == 0;
		mHostCallbackInfo = {};
		memcpy(&mHostCallbackInfo, inData, availSize);
		if (hasChanged) {
			PropertyChanged(inID, inScope, inElement);
		}
		break;
	}

	case kAudioUnitProperty_ContextName: {
		AUSDK_Require(inDataSize == sizeof(CFStringRef), kAudioUnitErr_InvalidPropertyValue);
		AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);
		const CFStringRef inStr = *static_cast<const CFStringRef*>(inData);
		mContextName = inStr;
		PropertyChanged(inID, inScope, inElement);
		break;
	}


	case kAudioUnitProperty_NickName: {
		AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);
		AUSDK_Require(inDataSize == sizeof(CFStringRef), kAudioUnitErr_InvalidPropertyValue);
		const CFStringRef inStr = *static_cast<const CFStringRef*>(inData);
		mNickName = inStr;
		PropertyChanged(inID, inScope, inElement);
		break;
	}

#if AUSDK_MIDI2_AVAILABLE
	case kAudioUnitProperty_HostMIDIProtocol: {
		AUSDK_Require(inScope == kAudioUnitScope_Global, kAudioUnitErr_InvalidScope);
		AUSDK_Require(inDataSize == sizeof(MIDIProtocolID), kAudioUnitErr_InvalidPropertyValue);
		mHostMIDIProtocol = *static_cast<const MIDIProtocolID*>(inData);
		PropertyChanged(inID, inScope, inElement);
		break;
	}
#endif

	default:
		result = SetProperty(inID, inScope, inElement, inData, inDataSize);
		if (result == noErr) {
			PropertyChanged(inID, inScope, inElement);
		}

		break;
	}
	return result;
}