OSStatus AUBase::DoProcessMultiple()

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