Skip to content

WebSocket support #79

@ambv

Description

@ambv

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions