OSC over TCP IP

Nicolas Bazoge's icon

Hi all,
I would like to send OSC from Max in TCP IP but I can't find how to do it.
I tried with the Sadam library but from what I understand, the objects only allow to transmit binary data and not OSC messages.
Strangely, I find very few resources or posts about this on the forums.
Would someone please tell me how to do this?

Roman Thilenius's icon

not sure if it helps here, but you can use UDP for OSC, too.

then your choice might fall on [udpsend]?

Nicolas Bazoge's icon

I usually use OSC via UDP but this time the application I want to control remotely requires me to use TCP IP protocol.

Source Audio's icon

insert atoi between your OSC message and sadam.tcpSender.

P.S. as alternative
mxj net.tcp.send
but ... you are better off without java.

Andy Maskell's icon

If you need OSC mesaage encoding and decoding, you could possibly try something like this:

replacing the [sadam.udpClient] with [sadam.tcpClient]. Can't say for certain that it will work though!!!

Source Audio's icon

you better not overcomplicate ...
I will repeat - this is all it needs
(mxj here only for demonstration that message gets sent correctly)


Nicolas Bazoge's icon

Thank you but I'm looking to send OSC messages over TCP/IP, not binary data.

Jan M's icon

As far as I understand the OSC protocol it is inherently based on UDP. Basically an extension to UDP. if you cannot send UDP directly and. binary data is not an option my knowledge doesn’t suffice how to do it.

TCP is a quite flexible and and powerful protocol though. Maybe there is a way tunneling UDP via TCP - but that’s above my networking knowledge and it most probably would require some configuration and/or technology outside Max.

My assumption is that you are looking for a way to send OSC via the internet? Is that correct? In that case you could send UDP directly and configure the router on the receiving end to open a port for UDP. would that be an option?

Source Audio's icon

max udpsend & receive are free of OSC syntax rules, you can use plain text.
Same applies to tcp objects.

But, if receiver side is limited to parsing CNMAT OSC packets,
for TCP one would have to encode packets according to what receiver side
expects, OSC 1.0 or 1.1
You might check cnmat OSC & odot stuff to form messages and send using sadam.tcpSender

Nicolas Bazoge's icon

That's exactly the point. The software I'm trying to control with Max requires formatting the data to the OSC 1.0 standard.
I found a pdf document from their website describing how the OSC should be integrated. Here is an interesting extract in relation with what you said:
" The preferred method for transmitting and receiving OSC packets is over a TCP connection. The app will listen for incoming TCP connections on Port 3032. When using TCP, each OSC packet begins with a 4-byte uint32 specifying the size of the OSC content that directly follows. This is part of the OSC specification. (ex: <4-bytes: osc packet size=65 bytes><65-bytes, osc packet data>). "

I'm not sure how to format such a message in Max from a simple OSC text message sent by a [message] object but I'll dig. If you have an example to speed up my tests, I will be very grateful.

Source Audio's icon

here is one example using slip encoded messages.
check difference between odot and OpenSoundControl
when it comes to negative int values.
Also odot sent floats are ignored in slipOSC/OpenSoundControl

Max Patch
Copy patch and select New From Clipboard in Max.


cnmat externals and odot packages are both arm compatible

Source Audio's icon

"prefered" means UDP not excluded, or ?

check o.downcast in odot, cnmat stuff is mostly uninformative
and explained in complicated way...

would it cost that much to post what that software is, that
you try to send messages to ?

Nicolas Bazoge's icon

That's a lighting software named Eos from ETC. I am currently developing a free Max application called TwisterEos (https://en.nolaskey.com/twistereos) to control this software with the Midi Fighter Twister controller.
I'm currently using UDP and everything works fine, but for reasons of robustness and ease of configuration at startup, I'd like to try using TCP/IP, even if it may generate a little latency.
I didn't know this ODOT library, thanks for this and for your example patch.

Source Audio's icon

EOS can use OSC 1.1 slip

Nicolas Bazoge's icon

Yes Eos can use both (OSC 1.0 and 1.1).
I haven't yet looked at the main differences between the two and which one would be better, but since I also use a remote control application (on a tablet and smartphone) that runs on OSC 1.0, I would like to be able to stay on this version of the OSC protocol.
- Is there an object equivalent to [slipOSC] that formats messages in OSC 1.0?
- Moreover, for my application (TwisterEos) I need to send OSC to Eos but also to receive it. Therefore should I use a tcpClient object, or a tcpSender + a tcpReceiver ?

Source Audio's icon

It gets more and more compicated, that means you are also using UDP
from that remote app.

odot package has external named o.downcast, which claims to
produce bundles conforming to OSC 1.0 specs.
You simply need to try if you need odot or OpenSoundControl.
I guess you did some tests, or is this only theoretic talk ?

There is another option - ETCLabs OSCrouter that can convert between all that...

about sadam objects, no idea if it serves you better to use
simple sender and receiver, or client / server ?
depends on the compete configuration and all units in the network.
Honestly, I have no idea.

Nicolas Bazoge's icon

The remote application (OSCRFR) works with TCP/IP - OSC 1.0. That's why I would like my application (TwisterEos) to work via this protocol and this version of OSC as well.

For the moment I have only tried with the sadam library which I know a little bit, not yet with the ODOT library that I don't know at all.
Thanks to your examples and advices, I succeeded in making TwisterEos communicate with Eos in TCP in a bidirectional way, but only in OSC1.1 and only by using the sadam.tcpClient object.
When I use the sadam.tcpSender and sadam.tcpReceiver objects, I have a socket connection problem. When I monitor the incoming messages in Eos, it shows me a connection to the socket and immediately after a disconnection. Only one OSC message seems to get through from time to time (highlighted in yellow in the screenshot below). I have not been able to solve this problem.
I succeeded with the sadam.tcpClient object because it has a "connect" or "disconnect" option message, which allowed me to create a stable socket opening. The sadam.tcpSender and sadam.tcpReceiver objects do not have this option and I don't know how to keep the socket open.
That's where I am for now, I'll keep digging. Thanks for the help you already gave me, it helped me a lot to move forward.

Andy Maskell's icon

I've been following this thread with interest because I would dearly love to simplify the method that I posted earlier. Unfortunately, I have to use UDP to transmit and receive OSC messages to the mixers that I am interfacing to and, to date, the method I posted is the only method that I have found to work after some 8 months of intensive research, trial and error. It is true that OSC was first intended to be used with UDP but a number of manufacturers are now switching to using OSC over TCP/IP because of the inherent weaknesses of UDP packets being lost without warning.

My problem, and I agree with @Nicholas Bagoze, that the methods and formats used by all these objects in Max is poorly described and it is a nightmare trying to find an appropriate solution.

@SourceAudio's suggestion of simply "ASCIIfying" the OSC command strings absolutely does NOT work. The OSC command strings MUST be reformatted into the correct data format for a remote unit to receive and interpret them and the same is required in reverse when any returned OSC bundles are received. These bundles contain data length values, a text string, a variable number of data type identifier flags and any number of subsequent data blobs all separated by pairs of null bytes. It is that translation that is sadly missing in all this.

The Max [udpsend] and [udpreceive] objects do provide the translation, which is great, but sadly many, many people have found that, for some reason, [udpreceive] fails to work as expected in multiple different scenarios. In my case, [udpreceive] simply cannot bind to a port that is already is use by a sender or receiver within Max or even external to Max, even though there is absolutely nothing that should prevent this, hence my solution to use [udpsend] and [udpreceive] to perform the translation and then use the Sadam objects to do the actual communication, as they do bind successfully to any port, whether already in use or not.

I have tried the method that @Nicholas has given above (and, indeed, I tried similar methods myself last year) and sadly that does not work with my mixers.

In my opinion, this whole problem would be solved completely, and there are threads relating to these issues going back for as long as the objects have been in Max, if @Cycling '74 would:

1) Recognise that there is need to modify the [udpreceive] object such that it will function correctly in situations that clearly work in numerous other scenarios, applications and devices, such as binding correctly to UDP ports that are already in use, adding the ability to open and close UDP ports, adding the ability to request the OS to allocate available ports, etc.

2) That the code that undertakes the translation processes from Max text to fully formatted OSC binary bundles and back again is separated out into two additional, separate objects that we can then use successfully with other objects in the o.dot, Sadam, and other communication packages.

Source Audio's icon

@Andy
udpsend and udprecive are not a problem here.
The topic is tcp, and it is working by sending ascii bytes,
same as other communication protocols do, in addition :
If you have to use OSC, then you either learn how to form
strings an send raw bytes, or use what is arround, but CNMAT left OSC enthusiasts in the dark when it comes to tcp.
They invented OSC, but did not provide sender or receiver software,

Actually it makes me wonder why so many manufacturers jumped
into OSC boat, even worse, why so many stick twith OSC 1.0 even that it has been abandoned by CNMAT more than 15 years ago ?
----
It is not true that sadam s/r externals can bind to allready used udp
or tcp port.
The rule is one protocol/port - one app.
Maybe you could post some links to software that can share
same UDP receive ports using same IP address with other apps?

here few examples that have nothing to do with max

you can forget that udpreceive will ever be able to bind
to allready used port.
-----------
Now back to the problem - OSC 1.0 TCP <-> OSC 1.1 TCP
SLIP encoded strings from OSC 1.1 can be stripped
by removing 1st 17 bytes and the last one (ascii 192)
remaining probem when using odot is default float 64 instead of float 32.
for that one has to use o.downcast external.
and slip encoding stream, either using slipOSC or o.slipencode/decode.
here one example, showing received OSC messages using both protocols
not bundles, only single messages

probem is that slipOSC does not accept plain OSC message 1.0, but wants to see a bundle.
On the other side, OSC1.1 message contains no size bytes
but starts straight after 192 with / (ascii 47)
At the end, in max one should be able to link all that into
usable configuration, in first pace if it is known which software needs
1.0 or 1.1 and what kind of OSC messages are in use.