Udp - tcp connection

Hi,

I’d like to do by code a thing I do on both windows and Mac through os interface: connect two pc creating local wireless network without using router and LAN cable.

I’m trying to do 2 standalone app: one that transmit some data to the another opened in another pc.

How can I do? There’s something in juce suitable for this purpose?

Yes, you could take a look at JUCE: InterprocessConnection Class Reference
and JUCE: InterprocessConnectionServer Class Reference

hope that helps!

2 Likes

Have a look at the code for the NetworkingDemo and the OSCDemo (which uses UDP networking) in the DemoRunner project (bundled with JUCE), and if that doesn’t suffice, then I’d suggest looking at Gin::networking utility classes - I’ve just discovered those myself and am finding Gin to be quite the boost …

https://figbug.github.io/Gin/

1 Like

Really thank you! Yes I just look at osc, but transmission is too slow for my purpose… Now I check the link, really thank you!

I’m trying to understand how this works by basic steps… for now I’m testing with 2 pc one with IP 192.168.178.36 and another with IP 192.168.178.36.
On both I created a project with the same code, on Component.h:

class Server : public InterprocessConnectionServer
{
 public:
    
    Server() {}
    ~Server() { stop(); }
    
    InterprocessConnection* createConnectionObject() override { return process; }
    
    void addProcess(InterprocessConnection* p) { process = p; }
    
private:
    
    InterprocessConnection* process;
};

class MainComponent  : public juce::Component, private InterprocessConnection
{
public:
    //==============================================================================
    MainComponent();
    ~MainComponent() override;

    //==============================================================================
    void paint (juce::Graphics&) override;
    void resized() override;

    void connectionMade() override { AlertWindow::showMessageBoxAsync(MessageBoxIconType::InfoIcon, "Connected", "Connected"); }
    void connectionLost() override { AlertWindow::showMessageBoxAsync(MessageBoxIconType::InfoIcon, "Disonnected", "Disonnected"); }
    void messageReceived (const MemoryBlock& message) override  { AlertWindow::showMessageBoxAsync(MessageBoxIconType::InfoIcon, "MessageReceived", "MessageReceived"); }
    
private:
    Server server {};
    
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

and on Component.cpp:

MainComponent::MainComponent() : InterprocessConnection{}
{
    setSize (600, 400);
    server.addProcess(this);
    server.beginWaitingForSocket(1010, "192.168.178.36"); //on other project it is 5002, "192.168.178.24"
    
    connectToSocket("192.168.178.36", 5002, 10); //on other project it is 1010, "192.168.178.36"
}

MainComponent::~MainComponent()
{
    disconnect();
}

void MainComponent::paint (juce::Graphics& g) { }
void MainComponent::resized()  { }

The alert boxes are not showed me (I tried also to connect a LAN cable even if it’s not my aim)… can you help me to understand the right way to use those class by some simple example code?

On my final project I’d like to have from one side a simple GUI project that show me in a combobox a list of possible pc (by IP? don’t know) that are waiting messages form it and, after having selected one or more of them, start sending some type of messages. On other side another simple GUI app loaded in another PC (or more PCs) that share’s his IP (? or something other that identifies it?) that after connection start waiting messages from the previous app…

Really thank you for you’re help networking and connections are a very black hole for me…

The concept is that one is the Server (inherits from InterprocessConnectionServer) and the other / others are the clients, which inherit from InterprocessConnection.

You also need to create your own subclass of InterprocessConnection on the server side that represents a client-connection for the createConnectionObject() function, so you specify what to do on messageReceived() etc.
You can’t just use the base InterprocessConnection class!

so TLDR:

server(IPCS) listens for connections, a client(IPC) connects, the server creates a connection/client-object (IPC) that communicates with the client on the other side.

The following is a shortened header only version to explain the concept, I think you can fill in the rest :slight_smile:

In the Server app:

Client.h (This is NOT in the client app, but a representation of a connected client for the server)

class Client : public juce::InterprocessConnection
{
public:
    Client();
   ~Client();
 
    void connectionMade() override;
    void connectionLost() override;
    void messageReceived(const juce::MemoryBlock& message) override;
    // Implement your desired behaviour for those functions
    // e.g. what to do when a client sends a message to the server
    [...]
}

Server.h

#include "Client.h"

class Server : public juce::InterprocessConnectionServer
{
public: 
   Server() { beginWaitingForSocket(yourPort); };
   ~Server() { stop(); };

   InterprocessConnection * createConnectionObject () { return clients.add(new Client()); };

private:

  juce::OwnedArray<Client> clients;
}

Then on the other PC / the client application you might have:

class ServerConnection : public juce::InterprocessConnection
{
public:
   ServerConnection()    {  connectToSocket(serverIP, yourPort, 3000);    }

   void connectionMade() override;
   void connectionLost() override;
   void messageReceived (const juce::MemoryBlock &message) override;
    // implement your desired behaviour
   // e.g. what to do when the server sends a message to this client
   [...]
}

Hope this helps you to understand the base concept and the parts involved!

That said you wrote you wanted more speed, but TCP with its handshake might be slower than OSC in the end, but thats depends also on the amount and frequency of data you are sending.

1 Like

You’re really so kind… Now it’s clear!

At the end I’m testing with DatagramSocket because I’d like to send the BufferAudio without adding latency to the one created by the buffer rate chosen :blush::pray:

No worries, I got stuck at the same problem :wink:
I think ithe documentation isn’t perfectly clear how the createConnectionObject() function should be used.

At the end I’m testing with DatagramSocket because I’d like to send the BufferAudio without adding latency to the one created by the buffer rate chosen

So you want to send Audio Data with this? Just be to clear, you can’t “stream” or send realtime audio with this. If this is what you want to do, take a look at products like Audinates Dante or AVB.

Hope that helps!

1 Like

really thank you… but why not? so … my algorithms now are not well done, but if each time I get in the processBlock of a plugin sender I can call this socket.write(addressToSend, port, &buffer, theBufferSize); and catch this in a plugin receiver with socket.read(&newBuffer, theBufferSize, true); and then pass this buffer in processBlock of the receiver calling buffer.makeCopyOf(newBuffer);… This is the idea, how to synch it to make it works is another thing :blush: I wanna get exactly this behaviour:

Well I’m neither an expert in C++ nor network audio, so I can’t give you the most scientific explanation,
but sending TCP data in the audio thread is a big no no.
Writing to a socket is a blocking operation, so you can’t predict how long that function call will take,
which will result in audio dropouts.

You need to do the sending from another thread and add some buffer/latency to account for the time it takes to send and receive the data. (like they say : “with minimal latency.” → is still more than no latency).
And making it work with such low latencies is probably no simple task either.

I saw you made some other posts with these “beginner questions” (which is absolutley fine, I’m one aswell and I know the feeling when you have a good idea and just want to make it happen asap :wink: ).
But I would suggest taking a step back and read up on C++, threads and networking before trying to achieve such complex tasks.

Hope that helps!

1 Like

You’re right, I’m working step by step while I’m documenting about all, but using DatagramSocket (that is what i’m using now) I’m using UDP protocol, not TCP, that’s what I get in doc…

The same applies for sending UDP, you shouldn’t do that in the audio thread!

1 Like

Yes, I suppose that, the idea I wrote you before was only to explain the logic.
In my project now I create a class Sender that inherit thread and do the “write” to socket. In process block I copy only the audio buffer to my Sender and thisone each cycle evaluate: if buffer is the same of previous sent - > DON’T SEND else - >SEND

What do you think about? If not in processBlock where I can get the buffer to expose to my Sender?

Well that sounds better in theory, but again, these things are really no easy feed and multithreading and concurrency can get quite complicated - especially with a realtime thread involved, so I can’t tell you excactly how you should do it without a deeper dive into it :slight_smile:

For these kind of questions my go-to ressource is the great talk by Fabian Renn-Giles & Dave Rowland from ADC19 ‘Realtime-101’ :

Maybe this will guide you into the right direction!

1 Like

You’re really really kind. Thank you for your time and you’re patience :pray:

1 Like