in Source/AUBase.cpp [1228:1337]
OSStatus AUBase::DoRender(AudioUnitRenderActionFlags& ioActionFlags,
const AudioTimeStamp& inTimeStamp, UInt32 inBusNumber, UInt32 inFramesToProcess,
AudioBufferList& ioData)
{
const auto errorExit = [this](OSStatus error) {
AUSDK_LogError(" from %s, render err: %d", GetLoggingString(), static_cast<int>(error));
SetRenderError(error);
return error;
};
OSStatus theError = noErr;
[[maybe_unused]] const DenormalDisabler denormalDisabler;
try {
AUSDK_Require(IsInitialized(), errorExit(kAudioUnitErr_Uninitialized));
if (inFramesToProcess > mMaxFramesPerSlice) {
static UInt64 lastTimeMessagePrinted = 0;
const UInt64 now = HostTime::current();
if (static_cast<double>(now - lastTimeMessagePrinted) >
HostTime::frequency()) { // not more than once per second.
lastTimeMessagePrinted = now;
AUSDK_LogError("kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=%u, "
"mMaxFramesPerSlice=%u",
static_cast<unsigned>(inFramesToProcess),
static_cast<unsigned>(mMaxFramesPerSlice));
}
return errorExit(kAudioUnitErr_TooManyFramesToProcess);
}
AUSDK_Require(!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(),
errorExit(kAudio_ParamError));
auto& output = Output(inBusNumber); // will throw if non-existant
if (ASBD::NumberChannelStreams(output.GetStreamFormat()) != ioData.mNumberBuffers) {
AUSDK_LogError(
"ioData.mNumberBuffers=%u, "
"ASBD::NumberChannelStreams(output.GetStreamFormat())=%u; kAudio_ParamError",
static_cast<unsigned>(ioData.mNumberBuffers),
static_cast<unsigned>(ASBD::NumberChannelStreams(output.GetStreamFormat())));
return errorExit(kAudio_ParamError);
}
const unsigned expectedBufferByteSize =
inFramesToProcess * output.GetStreamFormat().mBytesPerFrame;
for (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) {
AudioBuffer& buf = ioData.mBuffers[ibuf]; // 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; "
"ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
static_cast<unsigned>(inFramesToProcess),
static_cast<unsigned>(output.GetStreamFormat().mBytesPerFrame),
expectedBufferByteSize, ibuf, 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;
}
}
if (WantsRenderThreadID()) {
mRenderThreadID = std::this_thread::get_id();
}
if (mRenderCallbacksTouched) {
AudioUnitRenderActionFlags flags = ioActionFlags | kAudioUnitRenderAction_PreRender;
mRenderCallbacks.foreach ([&](const RenderCallback& rc) {
(*static_cast<AURenderCallback>(rc.mRenderNotify))(rc.mRenderNotifyRefCon, &flags,
&inTimeStamp, inBusNumber, inFramesToProcess, &ioData);
});
}
theError =
DoRenderBus(ioActionFlags, inTimeStamp, inBusNumber, output, inFramesToProcess, ioData);
SetRenderError(theError);
if (mRenderCallbacksTouched) {
AudioUnitRenderActionFlags flags = ioActionFlags | kAudioUnitRenderAction_PostRender;
if (theError != noErr) {
flags |= kAudioUnitRenderAction_PostRenderError;
}
mRenderCallbacks.foreach ([&](const RenderCallback& rc) {
(*static_cast<AURenderCallback>(rc.mRenderNotify))(rc.mRenderNotifyRefCon, &flags,
&inTimeStamp, inBusNumber, inFramesToProcess, &ioData);
});
}
// The vector's being emptied
// because these events should only apply to this Render cycle, so anything
// left over is from a preceding cycle and should be dumped. New scheduled
// parameters must be scheduled from the next pre-render callback.
if (!mParamEventList.empty()) {
mParamEventList.clear();
}
} catch (const OSStatus& err) {
return errorExit(err);
} catch (...) {
return errorExit(-1);
}
return theError;
}