OSStatus AUBase::RestoreState()

in Source/AUBase.cpp [1845:1968]


OSStatus AUBase::RestoreState(CFPropertyListRef plist)
{
	if (CFGetTypeID(plist) != CFDictionaryGetTypeID()) {
		return kAudioUnitErr_InvalidPropertyValue;
	}

	const AudioComponentDescription desc = GetComponentDescription();

	const auto* const dict = static_cast<CFDictionaryRef>(plist);

	// zeroeth step - make sure the Part key is NOT present, as this method is used
	// to restore the GLOBAL state of the dictionary
	if (CFDictionaryContainsKey(dict, kPartString)) {
		return kAudioUnitErr_InvalidPropertyValue;
	}

	// first step -> check the saved version in the data ref
	// at this point we're only dealing with version==0
	const auto* cfnum = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, kVersionString));
	if (cfnum == nullptr) {
		return kAudioUnitErr_InvalidPropertyValue;
	}
	SInt32 value = 0;
	CFNumberGetValue(cfnum, kCFNumberSInt32Type, &value);
	if (value != kCurrentSavedStateVersion) {
		return kAudioUnitErr_InvalidPropertyValue;
	}

	// second step -> check that this data belongs to this kind of audio unit
	// by checking the component subtype and manuID
	// We're not checking the type, since there may be different versions (effect, format-converter,
	// offline) of essentially the same AU
	cfnum = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, kSubtypeString));
	if (cfnum == nullptr) {
		return kAudioUnitErr_InvalidPropertyValue;
	}
	CFNumberGetValue(cfnum, kCFNumberSInt32Type, &value);
	if (static_cast<UInt32>(value) != desc.componentSubType) {
		return kAudioUnitErr_InvalidPropertyValue;
	}

	cfnum = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, kManufacturerString));
	if (cfnum == nullptr) {
		return kAudioUnitErr_InvalidPropertyValue;
	}
	CFNumberGetValue(cfnum, kCFNumberSInt32Type, &value);
	if (static_cast<UInt32>(value) != desc.componentManufacturer) {
		return kAudioUnitErr_InvalidPropertyValue;
	}

	// fourth step -> restore the state of all of the parameters for each scope and element
	const auto* const data = static_cast<CFDataRef>(CFDictionaryGetValue(dict, kDataString));
	if (data != nullptr) {
		const UInt8* p = CFDataGetBytePtr(data);
		const UInt8* const pend = p + CFDataGetLength(data); // NOLINT

		// we have a zero length data, which may just mean there were no parameters to save!
		//	if (p >= pend) return noErr;

		while (p < pend) {
			const UInt32 scopeIdx =
				CFSwapInt32BigToHost(*reinterpret_cast<const UInt32*>(p)); // NOLINT
			p += sizeof(UInt32);                                           // NOLINT

			const auto& scope = GetScope(scopeIdx);
			p = scope.RestoreState(p);
		}
	}

	// OK - now we're going to do some properties
	// restore the preset name...
	const auto* const name = static_cast<CFStringRef>(CFDictionaryGetValue(dict, kNameString));
	if (mCurrentPreset.presetName != nullptr) {
		CFRelease(mCurrentPreset.presetName);
	}
	if (name != nullptr) {
		mCurrentPreset.presetName = name;
		mCurrentPreset.presetNumber = -1;
	} else { // no name entry make the default one
		mCurrentPreset.presetName = kUntitledString;
		mCurrentPreset.presetNumber = -1;
	}

	CFRetain(mCurrentPreset.presetName);
	PropertyChanged(kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0);

	// Does the dict contain render quality information?
	if (CFDictionaryGetValueIfPresent(
			dict, kRenderQualityString, reinterpret_cast<const void**>(&cfnum))) { // NOLINT
		CFNumberGetValue(cfnum, kCFNumberSInt32Type, &value);
		DispatchSetProperty(
			kAudioUnitProperty_RenderQuality, kAudioUnitScope_Global, 0, &value, sizeof(value));
	}

	// Does the unit support the CPULoad Quality property - if so, save it...
	if (CFDictionaryGetValueIfPresent(
			dict, kCPULoadString, reinterpret_cast<const void**>(&cfnum))) { // NOLINT
		auto floatValue = std::numeric_limits<Float32>::quiet_NaN;
		CFNumberGetValue(cfnum, kCFNumberFloatType, &floatValue);
		DispatchSetProperty(
			kAudioUnitProperty_CPULoad, kAudioUnitScope_Global, 0, &floatValue, sizeof(floatValue));
	}

	// Do we have any element names for any of our scopes?
	CFDictionaryRef nameDict = nullptr;
	if (CFDictionaryGetValueIfPresent(
			dict, kElementNameString, reinterpret_cast<const void**>(&nameDict))) { // NOLINT
		for (AudioUnitScope i = 0; i < kNumScopes; ++i) {
			const CFStringRef key = CFStringCreateWithFormat(
				nullptr, nullptr, CFSTR("%u"), static_cast<unsigned>(i)); // NOLINT
			CFDictionaryRef elementDict = nullptr;
			if (CFDictionaryGetValueIfPresent(
					nameDict, key, reinterpret_cast<const void**>(&elementDict))) { // NOLINT
				const bool didAddElements = GetScope(i).RestoreElementNames(elementDict);
				if (didAddElements) {
					PropertyChanged(kAudioUnitProperty_ElementCount, i, 0);
				}
			}
			CFRelease(key);
		}
	}

	return noErr;
}