Pro Tools does not guarantee thread safety of GetChunkSize / GetChunk calls, although these calls will always be called in pairs from a thread, multiple different threads can make these pairs of calls simultaneously. To block this from happening I've added a chunkThreadId mutable varible to the JuceAAX_Processor class and use atomic operations around this to make sure Pro Tools won't break things:
// edit: added new error code
#define AAX_ERROR_PLUGIN_API_INVALID_THREAD 20700
AAX_Result GetChunkSize (AAX_CTypeID chunkID, uint32_t* oSize) const override
{
if (chunkID != juceChunkType)
return AAX_CEffectParameters::GetChunkSize (chunkID, oSize);
Thread::ThreadID threadId = Thread::getCurrentThreadId ();
if ((Thread::ThreadID)(nullptr) == chunkThreadId.compareAndSetValue (threadId, (Thread::ThreadID)(nullptr)))
{
tempFilterData.reset();
pluginInstance->getStateInformation (tempFilterData);
*oSize = (uint32_t) tempFilterData.getSize();
return AAX_SUCCESS;
}
return AAX_ERROR_PLUGIN_API_INVALID_THREAD;
}
AAX_Result GetChunk (AAX_CTypeID chunkID, AAX_SPlugInChunk* oChunk) const override
{
if (chunkID != juceChunkType)
return AAX_CEffectParameters::GetChunk (chunkID, oChunk);
Thread::ThreadID threadId = Thread::getCurrentThreadId ();
if (threadId == chunkThreadId.get ())
{
if (tempFilterData.getSize () <= oChunk->fSize)
{
oChunk->fSize = (uint32_t) tempFilterData.getSize();
tempFilterData.copyTo (oChunk->fData, 0, tempFilterData.getSize());
tempFilterData.reset();
chunkThreadId.compareAndSetValue ((Thread::ThreadID)(nullptr), threadId);
return AAX_SUCCESS;
}
// if the chunk size wasn't good still clear the threadId to allow future attempts
chunkThreadId.compareAndSetValue ((Thread::ThreadID)(nullptr), threadId);
}
return AAX_ERROR_PLUGIN_API_INVALID_THREAD;
}
Then add the chunkThreadId as a member:
// tempFilterData is initialized in GetChunkSize. // To avoid generating it again in GetChunk, we keep it as a member. mutable juce::MemoryBlock tempFilterData; mutable juce::Atomic<Thread::ThreadID> chunkThreadId;
And initililse it in the constructor:
JuceAAX_Processor()
: sampleRate (0)
, lastBufferSize (1 << AAX_eAudioBufferLengthNative_Max) // assume the max of 1024 that is specified by the AAX sdk.
, currentChannelLayoutIdx (0)
, chunkThreadId ((Thread::ThreadID)(nullptr))
{

