/*! @file AudioUnitSDK/AUInputElement.h @copyright © 2000-2021 Apple Inc. All rights reserved. */ #ifndef AudioUnitSDK_AUInputElement_h #define AudioUnitSDK_AUInputElement_h #include #include namespace ausdk { /*! @class AUInputElement @brief Implements an audio unit input element, managing the source of input from a callback or connection. */ class AUInputElement : public AUIOElement { public: using AUIOElement::AUIOElement; // AUElement override OSStatus SetStreamFormat(const AudioStreamBasicDescription& fmt) override; [[nodiscard]] bool NeedsBufferSpace() const override { return IsCallback(); } void SetConnection(const AudioUnitConnection& conn); void SetInputCallback(AURenderCallback proc, void* refCon); [[nodiscard]] bool IsActive() const noexcept { return mInputType != EInputType::NoInput; } [[nodiscard]] bool IsCallback() const noexcept { return mInputType == EInputType::FromCallback; } [[nodiscard]] bool HasConnection() const noexcept { return mInputType == EInputType::FromConnection; } OSStatus PullInput(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp, AudioUnitElement inElement, UInt32 nFrames); OSStatus PullInputWithBufferList(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp, AudioUnitElement inElement, UInt32 nFrames, AudioBufferList& inBufferList); protected: void Disconnect(); private: enum class EInputType { NoInput, FromConnection, FromCallback }; EInputType mInputType{ EInputType::NoInput }; // if from callback: AURenderCallback mInputProc{ nullptr }; void* mInputProcRefCon{ nullptr }; // if from connection: AudioUnitConnection mConnection{}; }; inline OSStatus AUInputElement::PullInputWithBufferList(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp, AudioUnitElement inElement, UInt32 nFrames, AudioBufferList& inBufferList) { OSStatus theResult = noErr; if (HasConnection()) { // only support connections for V2 audio units theResult = AudioUnitRender(mConnection.sourceAudioUnit, &ioActionFlags, &inTimeStamp, mConnection.sourceOutputNumber, nFrames, &inBufferList); } else { // kFromCallback: theResult = (mInputProc)(mInputProcRefCon, &ioActionFlags, &inTimeStamp, inElement, nFrames, &inBufferList); } if (mInputType == EInputType::NoInput) { // defense: the guy upstream could have disconnected // it's a horrible thing to do, but may happen! return kAudioUnitErr_NoConnection; } #if !TARGET_OS_IPHONE || DEBUG if (theResult == noErr) { // if there's already an error, there's no point (and maybe some harm) // in validating. if (ABL::IsBogusAudioBufferList(inBufferList) & 1) { return kAudioUnitErr_InvalidPropertyValue; } } #endif return theResult; } } // namespace ausdk #endif // AudioUnitSDK_AUInputElement_h