WebSocket Protocol
Complete message schema for the SkyTalk WebSocket relay — PTT events, floor control behavior, presence, GPS, and text messages.
WebSocket Protocol
Connection
The JWT is verified on the HTTP upgrade request. Invalid tokens receive a 1008 Policy Violation close. Once connected, the client must send JOIN_TALKGROUP to start receiving messages for a talkgroup.
Message Format
All messages are UTF-8 JSON. Both directions use the same structure.
Client → Server Messages
JOIN_TALKGROUP
Subscribe to a talkgroup's message stream. Triggers a PRESENCE broadcast to all room members (including the joining client).
LEAVE_TALKGROUP
Unsubscribe from a talkgroup. Triggers a PRESENCE broadcast with the updated member list.
PTT_START
Signals the start of a PTT transmission. Fan-out to all other talkgroup members. The timestamp is used by receiver clients for floor arbitration.
| Field | Type | Description |
|---|---|---|
talkgroup | UUID string | Target talkgroup |
sender | UUID string | Sending device UUID |
timestamp | integer | GPS epoch milliseconds — used for floor arbitration |
seq | integer | Sequence number for this PTT session |
PTT_AUDIO
An encrypted audio chunk. Does not carry talkgroup — the server routes by sessionId (set at PTT_START). This saves ~30 bytes per chunk at 22 kbps.
| Field | Type | Description |
|---|---|---|
sessionId | 4-byte integer | Maps to talkgroup via server's session map (set at PTT_START) |
seq | integer | Session sequence number |
chunk | integer | Chunk index within this PTT press |
data | base64 string | AES-GCM-256 encrypted Opus audio. IV (12B) prepended to ciphertext. |
PTT_END
Signals end of PTT transmission. Fan-out to talkgroup. Server cleans up sessionId mapping.
TEXT_MSG
Text message fan-out. Delivered to all other talkgroup members.
GPS_UPDATE
Pushes a GPS fix. Written to the database and fanned out to all talkgroups the sender has joined (for moving map).
Server → Client Messages
PRESENCE
Broadcast to all room members when any client joins, leaves, or disconnects. Lists all currently connected user IDs in the talkgroup.
All other message types (PTT_START, PTT_AUDIO, PTT_END, TEXT_MSG, GPS_UPDATE) are fanned out unchanged to all talkgroup members except the sender.
Floor Control Behavior
The server does not send FLOOR_GRANT or FLOOR_DENY. It fans out PTT_START messages only.
Clients run the arbitration algorithm independently:
- Receive
PTT_STARTfrom another device - If two
PTT_STARTmessages arrive within 50 ms → collision - Lower GPS timestamp wins; tiebreaker: lexicographically smaller UUID
- Loser stops transmitting
See Floor Control → for the full algorithm.
Self-Echo Prevention
The server does not send messages back to the socket that originated them. A device sending PTT_START does not receive its own PTT_START back. This applies to all message types.
Close Codes
| Code | Meaning |
|---|---|
1008 | Policy Violation — JWT missing or invalid |
1000 | Normal closure |