-
Notifications
You must be signed in to change notification settings - Fork 33
Description
Web browsers don't support communication via UDP, citing security reasons. Vendors direct developers to use WebSockets instead.
There is a case for adding WebSocket support to serialosc
to allow Web apps to communicate with Monome devices. serialosc
is the de facto standard for Monome devices, I'd say almost all PC and Mac users connecting their Grids and Arcs use it, because it's the "required" driver listed in the docs and it opens up support to the most end-user software. The only major platform missing at the moment is Web browsers.
Proof of concept
I wrote a WebSocket <-> UDP bridge for serialosc
in Python:
https://github.com/ambv/aiotone/blob/master/aiotone/serialosc_ws.py
It works well with pymonome running on Chrome with minimal changes:
https://mastodon.social/@ambv/113906782489634159
A bridge is inferior to direct support in serialosc
since it introduces latency and a point of failure, plus it's not trivial to install for others, if they even know that they need to install anything on top of serialosc
when they visit a Web app. An update to serialosc
that the users can upgrade to (with homebrew
on the Mac) seems like a much better proposition.
Design choices
WebSocket support would use nanomsg
that Norns already depends on for ws-wrapper, which is used successfully to expose Norns output in Maiden. It's a known quantity and it's been in successful use for many years now requiring no maintenance since 2021 and really only minimal maintenance since its introduction in 2018.
There are a few design decisions to make.
One daemon or two?
The first approach would be to make an additional WS daemon shipped with serialosc
. This would require additional handling of the running service during installation (like launchd
integration on macOS), and would present challenges with handling the USB devices non-exclusively between the two daemons.
The better approach IMO would be add an additional port (say, 12001) to the existing daemon that would handle WebSocket connections. In this world there is still only one process handling USB communication, and WebSockets only become a different transport to achieve the same result.
One WebSocket or many?
Unlike in UDP, there is a persistent connection for a WebSocket. Therefore, it might be tempting to allow a client to deal with all communication for all devices they want from that one connection. This would require slight changes of the OSC protocol.
The alternative is to do what UDP does today. The default port 12001 would be a WebSocket for discovery and handling of connections/disconnections, while separate dynamically opened ports would be WebSockets for bi-directional communication with a particular connected device. This case doesn't require any changes to the OSC protocol, although a few details would become irrelevant like passing the return host
and port
. The server would reply on the open WebSocket, no need to specify the return address. The docs could just specify that those values are ignored, or should be 0 0 for a WebSocket connection.
I'm leaning towards Option 2 here, because it makes it easier to adopt existing serialosc
client libraries to WebSockets, making WS just a new "transport" that's an alternative for UDP, but which still handles the same serialosc
protocol.
Text or binary WS frames?
My proof-of-concept bridge exclusively uses binary frames and it works great. There's human-readable introspection of the frames in Chrome Dev Tools anyway.
Rejected Alternatives
The alternative solution for Web browsers is to reimplement the serial protocol for a given Monome device and handle it via WebUSB directly. This is an inferior proposition since it requires reimplementing the protocol, as well as the killer features of serialosc
like seamless handling of disconnections and reconnections, and support for multiple devices of the same type connected at the same time. Worse yet, a user of such a Web app would have to disable serialosc
for the time of using the Web app. This seems like a deal breaker. It also makes it impossible to use one Monome device with a Web app and another Monome device with software that expects serialosc
.
We can also wait for Grid and Arc to support class-compliant USB MIDI, but I'm not sure when this is going to be finalized, what support will historical devices have here, and how this will play with serialosc
. This is a future design from my perspective, whereas WebSocket support can be added today.
Help offer
If you decide to pursue this, I'm happy to contribute the WebSocket server code to serialosc
to the design of your choice.