Skip to content

Commit

Permalink
Removed some locking from CoreAudio.
Browse files Browse the repository at this point in the history
  • Loading branch information
jules committed Oct 22, 2013
1 parent e4e58ad commit 2682871
Showing 1 changed file with 125 additions and 126 deletions.
251 changes: 125 additions & 126 deletions modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,7 @@ class CoreAudioInternal : private Timer
bufferSize (512),
numInputChans (0),
numOutputChans (0),
callbacksAllowed (true),
numInputChannelInfos (0),
numOutputChannelInfos (0)
callbacksAllowed (true)
{
jassert (deviceID != 0);

Expand Down Expand Up @@ -199,9 +197,17 @@ class CoreAudioInternal : private Timer
tempOutputBuffers[i] = audioBuffer + count++ * tempBufSize;
}

struct CallbackDetailsForChannel
{
int streamNum;
int dataOffsetSamples;
int dataStrideSamples;
};

// returns the number of actual available channels
void fillInChannelInfo (const bool input)
StringArray getChannelInfo (const bool input, Array<CallbackDetailsForChannel>& newChannelInfo) const
{
StringArray newNames;
int chanNum = 0;
UInt32 size;

Expand All @@ -212,7 +218,7 @@ class CoreAudioInternal : private Timer

if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size)))
{
HeapBlock <AudioBufferList> bufList;
HeapBlock<AudioBufferList> bufList;
bufList.calloc (size, 1);

if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList)))
Expand All @@ -237,82 +243,35 @@ class CoreAudioInternal : private Timer
name = String::fromUTF8 (channelName, (int) nameSize);
}

if (input)
if ((input ? activeInputChans : activeOutputChans) [chanNum])
{
if (activeInputChans[chanNum])
{
inputChannelInfo [numInputChannelInfos].streamNum = i;
inputChannelInfo [numInputChannelInfos].dataOffsetSamples = (int) j;
inputChannelInfo [numInputChannelInfos].dataStrideSamples = (int) b.mNumberChannels;
++numInputChannelInfos;
}

if (name.isEmpty())
name << "Input " << (chanNum + 1);

inChanNames.add (name);
}
else
{
if (activeOutputChans[chanNum])
{
outputChannelInfo [numOutputChannelInfos].streamNum = i;
outputChannelInfo [numOutputChannelInfos].dataOffsetSamples = (int) j;
outputChannelInfo [numOutputChannelInfos].dataStrideSamples = (int) b.mNumberChannels;
++numOutputChannelInfos;
}

if (name.isEmpty())
name << "Output " << (chanNum + 1);

outChanNames.add (name);
CallbackDetailsForChannel info = { i, (int) j, (int) b.mNumberChannels };
newChannelInfo.add (info);
}

if (name.isEmpty())
name << (input ? "Input " : "Output ") << (chanNum + 1);

newNames.add (name);
++chanNum;
}
}
}
}

return newNames;
}

void updateDetailsFromDevice()
Array<double> getSampleRatesFromDevice() const
{
stopTimer();

if (deviceID == 0)
return;

const ScopedLock sl (callbackLock);
Array<double> newSampleRates;
String rates;

AudioObjectPropertyAddress pa;
pa.mScope = kAudioObjectPropertyScopeWildcard;
pa.mElement = kAudioObjectPropertyElementMaster;

UInt32 isAlive;
UInt32 size = sizeof (isAlive);
pa.mSelector = kAudioDevicePropertyDeviceIsAlive;
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &isAlive))
&& isAlive == 0)
return;

Float64 sr;
size = sizeof (sr);
pa.mSelector = kAudioDevicePropertyNominalSampleRate;
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &sr)))
sampleRate = sr;

UInt32 framesPerBuf;
size = sizeof (framesPerBuf);
pa.mSelector = kAudioDevicePropertyBufferFrameSize;
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &framesPerBuf)))
{
bufferSize = (int) framesPerBuf;
allocateTempBuffers();
}

bufferSizes.clear();

pa.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
pa.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
UInt32 size = 0;

if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size)))
{
Expand All @@ -321,33 +280,42 @@ class CoreAudioInternal : private Timer

if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ranges)))
{
bufferSizes.add ((int) (ranges[0].mMinimum + 15) & ~15);
static const double possibleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 };

for (int i = 32; i < 2048; i += 32)
for (int i = 0; i < numElementsInArray (possibleRates); ++i)
{
for (int j = size / (int) sizeof (AudioValueRange); --j >= 0;)
{
if (i >= ranges[j].mMinimum && i <= ranges[j].mMaximum)
if (possibleRates[i] >= ranges[j].mMinimum - 2 && possibleRates[i] <= ranges[j].mMaximum + 2)
{
bufferSizes.addIfNotAlreadyThere (i);
newSampleRates.add (possibleRates[i]);
rates << possibleRates[i] << ' ';
break;
}
}
}

if (bufferSize > 0)
bufferSizes.addIfNotAlreadyThere (bufferSize);
}
}

if (bufferSizes.size() == 0 && bufferSize > 0)
bufferSizes.add (bufferSize);
if (newSampleRates.size() == 0 && sampleRate > 0)
{
newSampleRates.add (sampleRate);
rates << sampleRate;
}

JUCE_COREAUDIOLOG ("rates: " + rates);
return newSampleRates;
}

sampleRates.clear();
const double possibleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 };
String rates;
Array<int> getBufferSizesFromDevice() const
{
Array<int> newBufferSizes;

pa.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
AudioObjectPropertyAddress pa;
pa.mScope = kAudioObjectPropertyScopeWildcard;
pa.mElement = kAudioObjectPropertyElementMaster;
pa.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
UInt32 size = 0;

if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size)))
{
Expand All @@ -356,59 +324,98 @@ class CoreAudioInternal : private Timer

if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ranges)))
{
for (int i = 0; i < numElementsInArray (possibleRates); ++i)
{
bool ok = false;
newBufferSizes.add ((int) (ranges[0].mMinimum + 15) & ~15);

for (int i = 32; i < 2048; i += 32)
{
for (int j = size / (int) sizeof (AudioValueRange); --j >= 0;)
if (possibleRates[i] >= ranges[j].mMinimum - 2 && possibleRates[i] <= ranges[j].mMaximum + 2)
ok = true;

if (ok)
{
sampleRates.add (possibleRates[i]);
rates << possibleRates[i] << ' ';
if (i >= ranges[j].mMinimum && i <= ranges[j].mMaximum)
{
newBufferSizes.addIfNotAlreadyThere (i);
break;
}
}
}

if (bufferSize > 0)
newBufferSizes.addIfNotAlreadyThere (bufferSize);
}
}

if (sampleRates.size() == 0 && sampleRate > 0)
{
sampleRates.add (sampleRate);
rates << sampleRate;
}
if (newBufferSizes.size() == 0 && bufferSize > 0)
newBufferSizes.add (bufferSize);

JUCE_COREAUDIOLOG ("sr: " + rates);
return newBufferSizes;
}

inputLatency = 0;
outputLatency = 0;
UInt32 lat;
size = sizeof (lat);
int getLatencyFromDevice (AudioObjectPropertyScope scope) const
{
UInt32 lat = 0;
UInt32 size = sizeof (lat);
AudioObjectPropertyAddress pa;
pa.mElement = kAudioObjectPropertyElementMaster;
pa.mSelector = kAudioDevicePropertyLatency;
pa.mScope = kAudioDevicePropertyScopeInput;
if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat) == noErr)
inputLatency = (int) lat;
pa.mScope = scope;
AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat);
return (int) lat;
}

pa.mScope = kAudioDevicePropertyScopeOutput;
size = sizeof (lat);
void updateDetailsFromDevice()
{
stopTimer();

if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat) == noErr)
outputLatency = (int) lat;
if (deviceID == 0)
return;

// this collects all the new details from the device without any locking, then
// locks + swaps them afterwards.
AudioObjectPropertyAddress pa;
pa.mScope = kAudioObjectPropertyScopeWildcard;
pa.mElement = kAudioObjectPropertyElementMaster;

UInt32 isAlive;
UInt32 size = sizeof (isAlive);
pa.mSelector = kAudioDevicePropertyDeviceIsAlive;
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &isAlive)) && isAlive == 0)
return;

Float64 sr;
size = sizeof (sr);
pa.mSelector = kAudioDevicePropertyNominalSampleRate;
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &sr)))
sampleRate = sr;

UInt32 framesPerBuf = bufferSize;
size = sizeof (framesPerBuf);
pa.mSelector = kAudioDevicePropertyBufferFrameSize;
AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &framesPerBuf);

Array<int> newBufferSizes (getBufferSizesFromDevice());
Array<double> newSampleRates (getSampleRatesFromDevice());

inputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeInput);
outputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeOutput);
JUCE_COREAUDIOLOG ("lat: " + String (inputLatency) + " " + String (outputLatency));

inChanNames.clear();
outChanNames.clear();
Array<CallbackDetailsForChannel> newInChans, newOutChans;
StringArray newInNames (getChannelInfo (true, newInChans));
StringArray newOutNames (getChannelInfo (false, newOutChans));

// after getting the new values, lock + apply them
const ScopedLock sl (callbackLock);

bufferSize = (int) framesPerBuf;
allocateTempBuffers();

inputChannelInfo.calloc ((size_t) numInputChans + 2);
numInputChannelInfos = 0;
sampleRates.swapWith (newSampleRates);
bufferSizes.swapWith (newBufferSizes);

outputChannelInfo.calloc ((size_t) numOutputChans + 2);
numOutputChannelInfos = 0;
inChanNames.swapWith (newInNames);
outChanNames.swapWith (newOutNames);

fillInChannelInfo (true);
fillInChannelInfo (false);
inputChannelInfo.swapWith (newInChans);
outputChannelInfo.swapWith (newOutChans);
}

//==============================================================================
Expand Down Expand Up @@ -675,7 +682,7 @@ class CoreAudioInternal : private Timer
{
for (int i = numInputChans; --i >= 0;)
{
const CallbackDetailsForChannel& info = inputChannelInfo[i];
const CallbackDetailsForChannel& info = inputChannelInfo.getReference(i);
float* dest = tempInputBuffers [i];
const float* src = ((const float*) inInputData->mBuffers[info.streamNum].mData)
+ info.dataOffsetSamples;
Expand Down Expand Up @@ -720,7 +727,7 @@ class CoreAudioInternal : private Timer

for (int i = numOutputChans; --i >= 0;)
{
const CallbackDetailsForChannel& info = outputChannelInfo[i];
const CallbackDetailsForChannel& info = outputChannelInfo.getReference(i);
const float* src = tempOutputBuffers [i];
float* dest = ((float*) outOutputData->mBuffers[info.streamNum].mData)
+ info.dataOffsetSamples;
Expand All @@ -739,9 +746,9 @@ class CoreAudioInternal : private Timer
}
else
{
for (int i = jmin (numOutputChans, numOutputChannelInfos); --i >= 0;)
for (int i = jmin (numOutputChans, outputChannelInfo.size()); --i >= 0;)
{
const CallbackDetailsForChannel& info = outputChannelInfo[i];
const CallbackDetailsForChannel& info = outputChannelInfo.getReference(i);
float* dest = ((float*) outOutputData->mBuffers[info.streamNum].mData)
+ info.dataOffsetSamples;
const int stride = info.dataStrideSamples;
Expand Down Expand Up @@ -803,15 +810,7 @@ class CoreAudioInternal : private Timer
int numInputChans, numOutputChans;
bool callbacksAllowed;

struct CallbackDetailsForChannel
{
int streamNum;
int dataOffsetSamples;
int dataStrideSamples;
};

int numInputChannelInfos, numOutputChannelInfos;
HeapBlock <CallbackDetailsForChannel> inputChannelInfo, outputChannelInfo;
Array<CallbackDetailsForChannel> inputChannelInfo, outputChannelInfo;
HeapBlock <float*> tempInputBuffers, tempOutputBuffers;

//==============================================================================
Expand Down

0 comments on commit 2682871

Please sign in to comment.