in Source/AUBase.cpp [1420:1556]
OSStatus AUBase::DoProcessMultiple(AudioUnitRenderActionFlags& ioActionFlags,
const AudioTimeStamp& inTimeStamp, UInt32 inFramesToProcess, UInt32 inNumberInputBufferLists,
const AudioBufferList** inInputBufferLists, UInt32 inNumberOutputBufferLists,
AudioBufferList** ioOutputBufferLists)
{
const auto errorExit = [this](OSStatus error) {
AUSDK_LogError(
" from %s, processmultiple err: %d", GetLoggingString(), static_cast<int>(error));
SetRenderError(error);
return error;
};
OSStatus theError = noErr;
[[maybe_unused]] const DenormalDisabler denormalDisabler;
try {
if (CheckRenderArgs(ioActionFlags)) {
AUSDK_Require(IsInitialized(), errorExit(kAudioUnitErr_Uninitialized));
AUSDK_Require(inFramesToProcess <= mMaxFramesPerSlice,
errorExit(kAudioUnitErr_TooManyFramesToProcess));
AUSDK_Require(!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(),
errorExit(kAudio_ParamError));
for (unsigned ibl = 0; ibl < inNumberInputBufferLists; ++ibl) {
if (inInputBufferLists[ibl] != nullptr) { // NOLINT
const auto& input = Input(ibl); // will throw if non-existant
const unsigned expectedBufferByteSize =
inFramesToProcess * input.GetStreamFormat().mBytesPerFrame;
if (ASBD::NumberChannelStreams(input.GetStreamFormat()) !=
inInputBufferLists[ibl]->mNumberBuffers) { // NOLINT
AUSDK_LogError("inInputBufferLists[%u]->mNumberBuffers=%u, "
"ASBD::NumberChannelStreams(input.GetStreamFormat())=%u; "
"kAudio_ParamError",
ibl, static_cast<unsigned>(inInputBufferLists[ibl]->mNumberBuffers),
static_cast<unsigned>(
ASBD::NumberChannelStreams(input.GetStreamFormat())));
return errorExit(kAudio_ParamError);
}
for (unsigned ibuf = 0;
ibuf < inInputBufferLists[ibl]->mNumberBuffers; // NOLINT
++ibuf) {
const AudioBuffer& buf = inInputBufferLists[ibl]->mBuffers[ibuf]; // NOLINT
if (buf.mData != nullptr) {
if (buf.mDataByteSize < expectedBufferByteSize) {
// the buffer is too small
AUSDK_LogError(
"%u frames, %u bytes/frame, expected %u-byte buffer; "
"inInputBufferLists[%u].mBuffers[%u].mDataByteSize=%u; "
"kAudio_ParamError",
static_cast<unsigned>(inFramesToProcess),
static_cast<unsigned>(input.GetStreamFormat().mBytesPerFrame),
expectedBufferByteSize, ibl, ibuf,
static_cast<unsigned>(buf.mDataByteSize));
return errorExit(kAudio_ParamError);
}
} else {
// the buffer must exist
return errorExit(kAudio_ParamError);
}
}
} else {
// skip NULL input audio buffer list
}
}
for (unsigned obl = 0; obl < inNumberOutputBufferLists; ++obl) {
if (ioOutputBufferLists[obl] != nullptr) { // NOLINT
const auto& output = Output(obl); // will throw if non-existant
const unsigned expectedBufferByteSize =
inFramesToProcess * output.GetStreamFormat().mBytesPerFrame;
if (ASBD::NumberChannelStreams(output.GetStreamFormat()) !=
ioOutputBufferLists[obl]->mNumberBuffers) { // NOLINT
AUSDK_LogError("ioOutputBufferLists[%u]->mNumberBuffers=%u, "
"ASBD::NumberChannelStreams(output.GetStreamFormat())=%u; "
"kAudio_ParamError",
obl, static_cast<unsigned>(ioOutputBufferLists[obl]->mNumberBuffers),
static_cast<unsigned>(
ASBD::NumberChannelStreams(output.GetStreamFormat())));
return errorExit(kAudio_ParamError);
}
for (unsigned obuf = 0;
obuf < ioOutputBufferLists[obl]->mNumberBuffers; // NOLINT
++obuf) {
AudioBuffer& buf = ioOutputBufferLists[obl]->mBuffers[obuf]; // NOLINT
if (buf.mData != nullptr) {
// only care about the size if the buffer is non-null
if (buf.mDataByteSize < expectedBufferByteSize) {
// if the buffer is too small, we cannot render safely.
// kAudio_ParamError.
AUSDK_LogError(
"%u frames, %u bytes/frame, expected %u-byte buffer; "
"ioOutputBufferLists[%u]->mBuffers[%u].mDataByteSize=%u; "
"kAudio_ParamError",
static_cast<unsigned>(inFramesToProcess),
static_cast<unsigned>(output.GetStreamFormat().mBytesPerFrame),
expectedBufferByteSize, obl, obuf,
static_cast<unsigned>(buf.mDataByteSize));
return errorExit(kAudio_ParamError);
}
// Some clients incorrectly pass bigger buffers than
// expectedBufferByteSize. We will generally set the buffer size at the
// end of rendering, before we return. However we should ensure that no
// one, DURING rendering, READS a potentially incorrect size. This can
// lead to doing too much work, or reading past the end of an input
// buffer into unmapped memory.
buf.mDataByteSize = expectedBufferByteSize;
}
}
} else {
// skip NULL output audio buffer list
}
}
}
if (WantsRenderThreadID()) {
mRenderThreadID = std::this_thread::get_id();
}
if (NeedsToRender(inTimeStamp)) {
theError = ProcessMultipleBufferLists(ioActionFlags, inFramesToProcess,
inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists,
ioOutputBufferLists);
} else {
theError = noErr;
}
} catch (const OSStatus& err) {
return errorExit(err);
} catch (...) {
return errorExit(-1);
}
return theError;
}