InterprocessCommunication + ValueTreeSynchroniser Help


#1

I’m trying to get a bi-directional inter-plugin communication working through the combination of InterprocessCommunication and ValueTreeSynchroniser in a similar fashion to that of the iZotope Mix Tap + Visual Mixer plugins.

ValueTreeSynchroniser requires the tree to listen to on construction whereas I won’t know about the state of the other plugin until the first InterprocessConnection::messageReceived callback.

Whilst the issue is rather niche, could somebody point me in the right direction for how to get around it?

Here’s the code for the device connection + synchroniser, the hub connection + sync code is below it

struct DeviceConnection : public InterprocessConnection,
                          public ValueTreeSynchroniser
{
    DeviceConnection (ValueTree& tree)
    : ValueTreeSynchroniser (tree), stateTree (tree)
    {}
    
    void connectionMade() override
    {
        DBG ("Connected");
        
        lastMessageTime = -1;
        
        sendFullSyncCallback();
    }

    void connectionLost() override
    {
        DBG ("Disconnected");
        
        lastMessageTime = -1;
    }

    void messageReceived (const MemoryBlock &message) override
    {
        DBG ("Message Received");
        
        MemoryInputStream input (message.getData(), message.getSize(), false);

        applyChange (stateTree, input.getData(), input.getDataSize(), nullptr);

        DBG (stateTree.toXmlString());
    }
    
    void stateChanged (const void* encodedChange, size_t encodedChangeSize) override
    {
        DBG ("State Changed");

        if ((int) stateTree.getProperty ("messageTime") > lastMessageTime)
        {
            DBG ("Sending");
            
            MemoryBlock message (encodedChange, encodedChangeSize);
            
            sendMessage (message);
            
            lastMessageTime = (int) stateTree.getProperty ("messageTime");
        }
    }
    
    ValueTree& stateTree;
    int lastMessageTime = -1;
};

Host Connection:

struct HostConnection : public InterprocessConnection,
                        public ValueTreeSynchroniser
{
    HostConnection (ValueTree& t)
    : ValueTreeSynchroniser (t), hubParentState (t)
    {
    }
    
    void connectionMade() override
    {
        DBG ("Connected");
    }

    void connectionLost() override
    {
        DBG ("Disconnected");
        
        hubParentState.removeChild (deviceState, nullptr);
    }

    void messageReceived (const MemoryBlock& message) override
    {
        DBG ("Message Received");
        
        MemoryInputStream input (message.getData(), message.getSize(), false);
        
        // Test if a full sync has been performed
        if (input.readByte() == 2)
        {
            DBG ("FULL SYNC");

            applyChange (deviceState, input.getData(), input.getDataSize(), nullptr);
            hubParentState.appendChild (deviceState, nullptr);
        }
        else
            applyChange (deviceState, input.getData(), input.getDataSize(), nullptr);
    }
    
    void stateChanged (const void* encodedChange, size_t encodedChangeSize) override
    {
        DBG ("STATE CHANGED");
        
        MemoryBlock message (encodedChange, encodedChangeSize);
        sendMessage (message);
    }
    
    ValueTree deviceState;
    ValueTree& hubParentState;
};