docs: replace ASCII art with Mermaid packet-beta diagrams in protocol.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
199
docs/protocol.md
199
docs/protocol.md
@@ -28,16 +28,14 @@ flowchart TD
|
|||||||
|
|
||||||
Every message on the wire is a frame:
|
Every message on the wire is a frame:
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+------------------+------------------------+--------------------+
|
packet-beta
|
||||||
| message_type: u16 | payload_length: u32 | payload: bytes ... |
|
0-15: "message_type"
|
||||||
+------------------+------------------------+--------------------+
|
16-47: "payload_length"
|
||||||
2 bytes 4 bytes payload_length bytes
|
48-79: "payload …"
|
||||||
```
|
```
|
||||||
|
|
||||||
Total header size: **6 bytes**.
|
Total header size: **6 bytes**. `payload_length` is the byte count of the payload only — it does not include the 6-byte header itself.
|
||||||
|
|
||||||
`payload_length` is the byte count of the payload only — it does not include the 6-byte header itself.
|
|
||||||
|
|
||||||
A node that does not recognise `message_type` can skip the frame by consuming exactly `payload_length` bytes and discarding them. This allows relays and future nodes to forward or ignore unknown message types without understanding their structure.
|
A node that does not recognise `message_type` can skip the frame by consuming exactly `payload_length` bytes and discarding them. This allows relays and future nodes to forward or ignore unknown message types without understanding their structure.
|
||||||
|
|
||||||
@@ -69,22 +67,21 @@ Values not listed are reserved. A node receiving an unknown type must skip the p
|
|||||||
|
|
||||||
### `VIDEO_FRAME` (0x0001)
|
### `VIDEO_FRAME` (0x0001)
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+---------------+----------------------------------------------+
|
packet-beta
|
||||||
| stream_id: u16 | frame data (compressed, codec per stream_open) |
|
0-15: "stream_id"
|
||||||
+---------------+----------------------------------------------+
|
16-47: "frame data …"
|
||||||
2 bytes payload_length - 2 bytes
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`stream_id` identifies which video stream this frame belongs to. The codec is established at stream open time (see [Stream Lifecycle](#stream-lifecycle)) and does not appear in every frame.
|
`stream_id` identifies which video stream this frame belongs to. The codec is established at stream open time (see [Stream Lifecycle](#stream-lifecycle)) and does not appear in every frame.
|
||||||
|
|
||||||
### `CONTROL_REQUEST` (0x0002)
|
### `CONTROL_REQUEST` (0x0002)
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+------------------+----------------+---------------------------+
|
packet-beta
|
||||||
| request_id: u16 | command: u16 | command-specific fields |
|
0-15: "request_id"
|
||||||
+------------------+----------------+---------------------------+
|
16-31: "command"
|
||||||
2 bytes 2 bytes remaining bytes
|
32-63: "command-specific …"
|
||||||
```
|
```
|
||||||
|
|
||||||
`request_id` is chosen by the sender and echoed in the matching `CONTROL_RESPONSE`. It is used to correlate responses to requests when multiple requests are in flight simultaneously.
|
`request_id` is chosen by the sender and echoed in the matching `CONTROL_RESPONSE`. It is used to correlate responses to requests when multiple requests are in flight simultaneously.
|
||||||
@@ -103,11 +100,11 @@ Values not listed are reserved. A node receiving an unknown type must skip the p
|
|||||||
|
|
||||||
### `CONTROL_RESPONSE` (0x0003)
|
### `CONTROL_RESPONSE` (0x0003)
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+------------------+---------------+---------------------------+
|
packet-beta
|
||||||
| request_id: u16 | status: u16 | response-specific fields |
|
0-15: "request_id"
|
||||||
+------------------+---------------+---------------------------+
|
16-31: "status"
|
||||||
2 bytes 2 bytes remaining bytes
|
32-63: "response-specific …"
|
||||||
```
|
```
|
||||||
|
|
||||||
`request_id` matches the originating request. `status` values:
|
`request_id` matches the originating request. `status` values:
|
||||||
@@ -122,11 +119,11 @@ Values not listed are reserved. A node receiving an unknown type must skip the p
|
|||||||
|
|
||||||
### `STREAM_EVENT` (0x0004)
|
### `STREAM_EVENT` (0x0004)
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+---------------+------------------+---------------------------+
|
packet-beta
|
||||||
| stream_id: u16 | event_code: u8 | event-specific fields |
|
0-15: "stream_id"
|
||||||
+---------------+------------------+---------------------------+
|
16-23: "event_code"
|
||||||
2 bytes 1 byte remaining bytes
|
24-55: "event-specific …"
|
||||||
```
|
```
|
||||||
|
|
||||||
`event_code` values:
|
`event_code` values:
|
||||||
@@ -144,12 +141,14 @@ Before video frames can flow, a stream must be opened. This establishes the code
|
|||||||
|
|
||||||
### Opening a Stream (`STREAM_OPEN` request)
|
### Opening a Stream (`STREAM_OPEN` request)
|
||||||
|
|
||||||
The sender issues a `CONTROL_REQUEST` with command `STREAM_OPEN`:
|
```mermaid
|
||||||
|
packet-beta
|
||||||
```
|
0-15: "request_id"
|
||||||
+------------------+------------------+-----------------+------------------+-------------------+----------------+
|
16-31: "command = 0x0001"
|
||||||
| request_id: u16 | command: u16 | stream_id: u16 | format: u16 | pixel_format: u16 | origin: u16 |
|
32-47: "stream_id"
|
||||||
+------------------+------------------+-----------------+------------------+-------------------+----------------+
|
48-63: "format"
|
||||||
|
64-79: "pixel_format"
|
||||||
|
80-95: "origin"
|
||||||
```
|
```
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
@@ -163,10 +162,11 @@ The receiver responds with `CONTROL_RESPONSE`. On `status = OK` the stream is op
|
|||||||
|
|
||||||
### Closing a Stream (`STREAM_CLOSE` request)
|
### Closing a Stream (`STREAM_CLOSE` request)
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+------------------+------------------+-----------------+
|
packet-beta
|
||||||
| request_id: u16 | command: u16 | stream_id: u16 |
|
0-15: "request_id"
|
||||||
+------------------+------------------+-----------------+
|
16-31: "command = 0x0002"
|
||||||
|
32-47: "stream_id"
|
||||||
```
|
```
|
||||||
|
|
||||||
After a close response, no further `VIDEO_FRAME` messages should be sent for that `stream_id`.
|
After a close response, no further `VIDEO_FRAME` messages should be sent for that `stream_id`.
|
||||||
@@ -225,10 +225,14 @@ Node discovery uses UDP multicast. The wire format is a standard transport frame
|
|||||||
|
|
||||||
Sent periodically by every node and immediately on startup.
|
Sent periodically by every node and immediately on startup.
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+----------------------+------------+-----------------+------------------+-------------------+------------------+
|
packet-beta
|
||||||
| protocol_version: u8 | site_id: u16 | tcp_port: u16 | function_flags: u16 | name_len: u8 | name: bytes |
|
0-7: "protocol_version"
|
||||||
+----------------------+------------+-----------------+------------------+-------------------+------------------+
|
8-23: "site_id"
|
||||||
|
24-39: "tcp_port"
|
||||||
|
40-55: "function_flags"
|
||||||
|
56-63: "name_len"
|
||||||
|
64-95: "name …"
|
||||||
```
|
```
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
@@ -273,10 +277,10 @@ The gateway assigns a distinct non-zero `site_id` to each side and rewrites `sit
|
|||||||
|
|
||||||
`str8` — a length-prefixed UTF-8 string, not NUL-terminated on the wire:
|
`str8` — a length-prefixed UTF-8 string, not NUL-terminated on the wire:
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+------------+-------------------+
|
packet-beta
|
||||||
| length: u8 | bytes: length × u8 |
|
0-7: "length"
|
||||||
+------------+-------------------+
|
8-39: "bytes (≤ 255) …"
|
||||||
```
|
```
|
||||||
|
|
||||||
Maximum string length is 255 bytes.
|
Maximum string length is 255 bytes.
|
||||||
@@ -293,26 +297,17 @@ All requests follow the `CONTROL_REQUEST` frame format (request_id + command + c
|
|||||||
|
|
||||||
**Response** on status `OK`:
|
**Response** on status `OK`:
|
||||||
|
|
||||||
```
|
Repeated `media_count` times (u16):
|
||||||
+-------------------+
|
|
||||||
| media_count: u16 |
|
- `path` str8, `driver` str8, `model` str8, `bus_info` str8
|
||||||
+-------------------+
|
- `vnode_count` u8, then repeated `vnode_count` times:
|
||||||
× media_count:
|
- `path` str8, `entity_name` str8
|
||||||
+------------+------------+-----------+-------------+-----------------+
|
- `entity_type` u32, `entity_flags` u32, `device_caps` u32
|
||||||
| path: str8 | driver:str8| model:str8| bus_info:str8| vnode_count: u8 |
|
- `pad_flags` u8, `is_capture` u8
|
||||||
+------------+------------+-----------+-------------+-----------------+
|
|
||||||
× vnode_count:
|
Then repeated `standalone_count` times (u16):
|
||||||
+------------+-----------------+------------------+-------------------+------------------+----------------+------------------+
|
|
||||||
| path: str8 | entity_name:str8| entity_type: u32 | entity_flags: u32 | device_caps: u32 | pad_flags: u8 | is_capture: u8 |
|
- `path` str8, `name` str8
|
||||||
+------------+-----------------+------------------+-------------------+------------------+----------------+------------------+
|
|
||||||
+----------------------+
|
|
||||||
| standalone_count: u16 |
|
|
||||||
+----------------------+
|
|
||||||
× standalone_count:
|
|
||||||
+------------+------------+
|
|
||||||
| path: str8 | name: str8 |
|
|
||||||
+------------+------------+
|
|
||||||
```
|
|
||||||
|
|
||||||
`device_caps` carries `V4L2_CAP_*` bits from `VIDIOC_QUERYCAP` (using `device_caps` if `V4L2_CAP_DEVICE_CAPS` is set, otherwise `capabilities`). Notable bits: `0x00000001` = `VIDEO_CAPTURE`, `0x00800000` = `META_CAPTURE`.
|
`device_caps` carries `V4L2_CAP_*` bits from `VIDIOC_QUERYCAP` (using `device_caps` if `V4L2_CAP_DEVICE_CAPS` is set, otherwise `capabilities`). Notable bits: `0x00000001` = `VIDEO_CAPTURE`, `0x00800000` = `META_CAPTURE`.
|
||||||
|
|
||||||
@@ -322,28 +317,38 @@ All requests follow the `CONTROL_REQUEST` frame format (request_id + command + c
|
|||||||
|
|
||||||
**Request**:
|
**Request**:
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+--------------------+
|
packet-beta
|
||||||
| device_index: u16 |
|
0-15: "request_id"
|
||||||
+--------------------+
|
16-31: "command = 0x0004"
|
||||||
|
32-47: "device_index"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Response** on status `OK`:
|
**Response** on status `OK` — repeated `count` times (u16):
|
||||||
|
|
||||||
|
Fixed prefix per control:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
packet-beta
|
||||||
|
0-31: "id"
|
||||||
|
32-39: "type"
|
||||||
|
40-71: "flags"
|
||||||
```
|
```
|
||||||
+---------------+
|
|
||||||
| count: u16 |
|
Followed by `name` str8, then the fixed suffix:
|
||||||
+---------------+
|
|
||||||
× count:
|
```mermaid
|
||||||
+---------+---------+----------+------------+----------+---------+----------+-------------+-----------------+------------------+
|
packet-beta
|
||||||
| id: u32 | type: u8 | flags: u32 | name: str8 | min: i32 | max: i32 | step: i32 | default: i32 | current: i32 | menu_count: u8 |
|
0-31: "min"
|
||||||
+---------+---------+----------+------------+----------+---------+----------+-------------+-----------------+------------------+
|
32-63: "max"
|
||||||
× menu_count:
|
64-95: "step"
|
||||||
+------------+------------+------------------+
|
96-127: "default_val"
|
||||||
| index: u32 | name: str8 | int_value: i64 |
|
128-159: "current_val"
|
||||||
+------------+------------+------------------+
|
160-167: "menu_count"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Followed by `menu_count` menu items. Each menu item: `index` u32, then `name` str8, then `int_value` i64.
|
||||||
|
|
||||||
`type` values match `V4L2_CTRL_TYPE_*`:
|
`type` values match `V4L2_CTRL_TYPE_*`:
|
||||||
|
|
||||||
| Value | Type |
|
| Value | Type |
|
||||||
@@ -364,28 +369,34 @@ Menu items may have non-contiguous `index` values (gaps where the driver returns
|
|||||||
|
|
||||||
**Request**:
|
**Request**:
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+--------------------+------------------+
|
packet-beta
|
||||||
| device_index: u16 | control_id: u32 |
|
0-15: "request_id"
|
||||||
+--------------------+------------------+
|
16-31: "command = 0x0005"
|
||||||
|
32-47: "device_index"
|
||||||
|
48-79: "control_id"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Response** on status `OK`:
|
**Response** on status `OK`:
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+-------------+
|
packet-beta
|
||||||
| value: i32 |
|
0-15: "request_id"
|
||||||
+-------------+
|
16-31: "status"
|
||||||
|
32-63: "value"
|
||||||
```
|
```
|
||||||
|
|
||||||
### `SET_CONTROL` (0x0006)
|
### `SET_CONTROL` (0x0006)
|
||||||
|
|
||||||
**Request**:
|
**Request**:
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
+--------------------+------------------+-------------+
|
packet-beta
|
||||||
| device_index: u16 | control_id: u32 | value: i32 |
|
0-15: "request_id"
|
||||||
+--------------------+------------------+-------------+
|
16-31: "command = 0x0006"
|
||||||
|
32-47: "device_index"
|
||||||
|
48-79: "control_id"
|
||||||
|
80-111: "value"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Response** — no extra fields beyond request_id and status.
|
**Response** — no extra fields beyond request_id and status.
|
||||||
|
|||||||
Reference in New Issue
Block a user