One of the main reasons to use the OSC protocol, besides the obvious control we gain through it, was the ability to use it over a network. This, in theory at least, would allow us to run all parts of the application on separate devices as needed.
Up until now, the controller application was developed to automatically send all OSC commands to hardcoded ports on the same PC. While a minor improvement was that the ports are now being listed in the application, obviously that still doesn't make it easy to understand the status of the connection.
With recent additions, the controller application now has a similar device enumeration and selection as the sensor part of it does. This means that on startup the application will scan around in the network looking for OSC services running waiting for data for it, then list them all. This way, the user can just decide which device is supposed to be controlled without having to enter an IP address (because entering a seemingly random bunch of numbers isn't very user friendly, is it?), only having to click connect to be ready to go!
All devices will be listed by their names and IP addresses just to be double sure that they're the right devices. If a device isn't actually meant to receive OSC, or becomes unavailable, or if there's no device for any of the services to begin with, the application will continue running.
Even if there is no device selected at all, the application can still connect fine to the sensors to monitor sensor data.
For internal tests and debugging it can even simulate sensor data without being connected to a sensor device. However, this most likely won't make it into the final build, unless it is deemed useful for testing the services.
Now for the boring technical part. How is this achieved? Why did it take so long? What makes it special?
All this can be answered quite simply, or rather, quite complicated: OSC uses UDP, which is a connectionless protocol. It sends a packet and doesn't care (or even know) whether it arrives or not, and doesn't expect a response either. This causes complications when trying to figure out which devices on the same network support our services.
So what do we do about it? We make smart use of certain properties of networks and firewalls. When a PC receives a UDP package on a port that is blocked by a firewall (or generally not open), it will respond asking us to close the connection. This way we can sort out which PCs on the network do not support it.
But how does that tell us which PCs do support it? Simple: If we receive no such response and just time out waiting for one, there's most likely an OSC service running on the other side - which is simply designed not to respond.
But what if we try to do that to a device on the network that doesn't even exist? Won't that time out too? Yes, it would. And that is a problem. So how do we prevent that?
One approach is just to make a list of devices on the network in general, before checking for OSC on specific ports. One way to do that is to ping them. Ping is designed to respond, so if we don't get a response, there's no device there.
So with this first we have a list of all devices on the local network (by knowing which IPs are allowed in it and ping sweeping all of those), then we go through each of those and try to access their OSC ports. If the response times out, it should be a valid device. And worst case, if this fails (which it can, depending on network and device settings), we just have an extra device in the dropdown list that doesn't do any harm.
Now, doing a ping sweep and then checking specific ports with the intention of a timeout - wouldn't that take up a ton of time? Yes, as it turns out. Nonetheless, the application does this in less than a fraction of a second. This was achieved by doing all of this in parallel using .NET 5.0's async task system. This took a while to figure out because this is a WPF application which messes a lot with the task pool, which resulted in deadlocks on initial attempts.
A solution to that can be found on Justin Lam's blog (https://www.justinmklam.com/posts/2018/02/ping-sweeper/).
The blog post also happens to be about ping sweeping in particular rather than just async tasks in WPF. So all that was left to come up with rather than just research was the OSC service scan, since that's not something the typical developer would do, so no one ever wrote about that.
With this all working, up next is connecting the final sensor device to this and tweaking parameters for the applications that are going to receive them, and hopefully improve and automate some interpolation of certain sensor types that have low refresh rates, all while combining certain sensor data to more useful data for Ableton/Max, Resolume and Unreal Engine 4.
Comentarios