3.0 KiB
Lumi Companion Protocol v1
Status: experimental. The protocol is versioned independently from Lumi core, the server plugin, companion core, and companion transcription plugin.
Trust boundaries
The OBS bridge accepts only same-user named-pipe clients and speaks only the local IPC subset. The companion owns pairing and connects to Lumi over TLS WebSockets. Lumi authenticates a device before accepting a WebSocket upgrade. The bridge never receives a Lumi device credential and never connects to the network.
Server connection
- Endpoint:
wss://<lumi-host>/plugins/lumi_transcription/live - Header:
Authorization: LumiDevice <device-id>.<device-secret> - Maximum structured message: 64 KiB.
- Maximum binary audio message: 6,464 bytes (64-byte header plus up to 200 ms of PCM).
- The client sends
hellofirst. Lumi replies withhello_ackor closes with an application error. - Protocol v1 supports
pcm_s16le; codec negotiation is still explicit so Opus can be added later. - Heartbeats use
ping/pong. A new connection is a new session unlessresume_session_idnames a resumable session owned by that device.
Structured messages use the envelope in schemas/envelope.schema.json. Supported client events are hello, ping, source_update, obs_state, start, stop, and ack. Server events are hello_ack, pong, status, caption, metric, and error.
Binary PCM frame
All integers are little-endian. The fixed header is 64 bytes:
| Offset | Size | Meaning |
|---|---|---|
| 0 | 4 | ASCII LACP |
| 4 | 1 | protocol version (1) |
| 5 | 1 | flags: active 0x01, muted 0x02 |
| 6 | 2 | header bytes (64) |
| 8 | 4 | sequence number |
| 12 | 8 | monotonic capture timestamp, microseconds |
| 20 | 16 | session UUID bytes |
| 36 | 16 | OBS source UUID bytes |
| 52 | 4 | sample rate (16000) |
| 56 | 2 | channels (1) |
| 58 | 2 | PCM bits (16) |
| 60 | 4 | payload bytes |
The payload is mono signed 16-bit little-endian PCM. Receivers reject malformed sizes and unsupported audio formats. Sequence gaps are reported; out-of-order frames are discarded. Every queue drops obsolete data rather than blocking a capture thread.
Local OBS IPC
Windows transport is a per-user named pipe named Lumi.Companion.ObsBridge.v1.<user-sid-hash>. Messages are length-prefixed (32-bit little-endian), capped at 64 KiB for JSON and 6,464 bytes for audio, and begin with a v1 handshake. The bridge accepts only this allowlist: hello, select_sources, caption, delivery_state, shutdown_notice, and PCM frames. It cannot execute arbitrary commands.
Caption events are revision-aware. Consumers retain the greatest revision for each (session_id, caption_id) and discard older revisions, including after reconnect.
Compatibility
Protocol v1 requires companion capability transcription.capture.v1 and server capability transcription.server.v1. OBS delivery is separately negotiated as obs.caption.native.v1; its absence keeps test-mode simulation available but blocks live delivery.