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;
}