AudioDeviceManager in AudioProcessor

hi, I’d like to pass in a plugin to AudioBuffer what comes from DeviceCallback:

My plugin is designed to be of type input or output and the purpose is to stream audio from another an AudioDevice chosen with an AudioDeviceManager:

So the question is: how to fill audioBuffer from callback inputChannelData if it’s of type input and fill from audioBuffer outputChannelData? I need an iterator that is incremented in callback until samplesBlock*numChannel?

this in processor:

void DevicemanagerinpluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    BufferToPass.setSize(( (inOrOut == Type::input) getNumInputChannels() : getNumOutputChannels() ), 
                         samplesPerBlock, false, true, false);
    
    audioDeviceSetup.bufferSize = samplesPerBlock;
    audioDeviceSetup.sampleRate = sampleRate;
    
    audioDeviceManager.initialise(numOfInChannels, numOfOutChannels, savedState.get() ? savedState.get() : nullptr, false, juce::String(), &audioDeviceSetup);
    
    audioDeviceManager.addAudioCallback(&deviceCallback);
}

void DevicemanagerinpluginAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
    juce::ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();

    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());

    if (inOrOut == Type::input)
    {
        buffer = BufferToPass;
        BufferToPass.clear();
    } else {
        BufferToPass.clear();
        BufferToPass.makeCopyOf(buffer);
    }
}

and in subclass of DeviceCallback:

class DeviceCallback : public juce::AudioIODeviceCallback
    {
    public:
        DeviceCallback(DevicemanagerinpluginAudioProcessor& processor) : audioDeviceProcessor(processor) {}
        ~DeviceCallback() {}
        
        void audioDeviceIOCallbackWithContext (const float *const *inputChannelData, int numInputChannels,  float *const *outputChannelData, int numOutputChannels, int numSamples, const juce::AudioIODeviceCallbackContext &context) override
        {
            if (audioDeviceProcessor.inOrOut == DevicemanagerinpluginAudioProcessor::Type::input)
            {
                // Here I want to fill BufferToPass of audioDeviceProcessor
                // with inputChannelData and numInputChannels
            } else {
                // Here I want to get from BufferToPass data to fill
                // outputChannelData and numOutputChannels
            }
        }
        
        void audioDeviceAboutToStart (juce::AudioIODevice *device) override 
        {
            audioDeviceProcessor.suspendProcessing(false); //?
        }
        
        void audioDeviceStopped () override 
        {
            audioDeviceProcessor.suspendProcessing(true); //?
        }
        
        void audioDeviceError (const juce::String &errorMessage) override 
        {
            audioDeviceProcessor.suspendProcessing(true); //?
        }
        
    private:
        
        DevicemanagerinpluginAudioProcessor& audioDeviceProcessor;
        
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DeviceCallback)
    };

Thank you in advance!

I change my approach:

I created a wrapped processor that needs me to assign something to an AudioProcessorPlayer like this:

class WrappedAudioProcessor    :  public AudioProcessor
{
public:
        
    WrappedAudioProcessor(ExternalAudioIO* o, const BusesProperties& ioLayouts) :   AudioProcessor(ioLayouts),
                                                                                    owner(o) {}
    ~WrappedAudioProcessor() override {}

    void prepareToPlay (double sampleRate, int samplesPerBlock) override { bufferToPass.setSize(getTotalNumOutputChannels(),
                                                                           samplesPerBlock, false,
                                                                           true, false );}
    void reset() override               { bufferToPass.clear(); }
    void releaseResources() override    { bufferToPass.clear(); }
    void processBlock (AudioBuffer<float>& audioBuff, MidiBuffer&) override
    {
        juce::ScopedNoDenormals noDenormals;
        auto totalNumInputChannels  = getTotalNumInputChannels();
        auto totalNumOutputChannels = getTotalNumOutputChannels();

        for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
            audioBuff.clear (i, 0, audioBuff.getNumSamples());
    
        if (!owner) { return; }
    
        if (owner->getType() == ExternalAudioIO::IODeviceType::input)
        {
            bufferToPass.makeCopyOf(audioBuff);
        } else {
            audioBuff.makeCopyOf(bufferToPass);
        }
    }
    //here some standard AudioProcessor functions like  acceptsMidi() ecc...
     
    AudioBuffer<float> bufferToPass;
    
private:

    ExternalAudioIO* owner;
    
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WrappedAudioProcessor)
};

while in my processor:

public:
    enum IODeviceType { input, output };
    //here some standard AudioProcessor functions like  acceptsMidi() ecc...

    void prepareToPlay(double sampleRate, int samplesPerBlock)
    {
        AudioDeviceManager::AudioDeviceSetup audioDeviceSetup {};
        audioDeviceSetup.bufferSize = samplesPerBlock;
        audioDeviceSetup.sampleRate = sampleRate;
    
       deviceManager.initialise(getTotalNumInputChannels(), getTotalNumOutputChannels(), 
       savedState.get() ? savedState.get() : nullptr, false, juce::String(), &audioDeviceSetup);
    }

    void processBuffer (AudioBuffer<float>& buffer, MidiBuffer&)
    {
        juce::ScopedNoDenormals noDenormals;
        auto totalNumInputChannels  = getTotalNumInputChannels();
        auto totalNumOutputChannels = getTotalNumOutputChannels();

        for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
            buffer.clear (i, 0, buffer.getNumSamples());
    
        if (deviceType == IODeviceType::input)
        {
            buffer.makeCopyOf(wrappedAudioProcessor.bufferToPass);
        } else {
            wrappedAudioProcessor.bufferToPass.makeCopyOf(buffer);
        }
    }

    void releaseResources()
    {
        deviceManager.closeAudioDevice();
    }

private:
    IODeviceType deviceType;
    
    bool pair = true;
    
    WrappedAudioProcessor wrappedAudioProcessor;
    std::unique_ptr<juce::XmlElement> savedState;
    
    AudioDeviceManager deviceManager {};
    AudioProcessorPlayer processorPlayer{};

Is it a correct approach? up to now I can send audio data in output (sometimes I can listen some glitches, maybe because processBlocks are not in sync?) but not audio data in input and I don’t know why when I close my app (basically an AudioProcessorGraph) it takes a lot of time to shutdown…

any help is really appreciated, I really urgently need to make this work… :heart::pray:

Here the gui of two plugin types to clarify purposes:

Ok after some tests I noticed that input meter of my plugin doesn’t show me nothing, so the problem is that AudioDeviceManager in input is not capturing nothing … But The thing is stranger … If I open the audioDeviceSelectorComponent of the standaloneApp that host my plugin (the basic standalone app given by juce) I can notice that Audio in input is not captured (for any device type and any channel active) … stranger and stranger … If I chose another audioDevice type in input in the combobox name is not updated, while the “active output channels” yes. If I change the input device type both combobox of device type are changed show input device type name and the “active output channels” shows me the channels of the last audio device available (while “active input channels” are right)… In demorunner or audioPluginHost the behaviour of audioDeviceSelectorComponent is right, but if I create another plugin app from scratch the behaviour is the same I expose above… this really goes me mad…

(my plugin in output works fine)