Latency Measurement
Oden Control Pipeline (OCP) reports several latency-related values. Use this page to verify that the latency loop is closed, understand what the operator should see, and decide whether a fault points at networking, video metadata, the vehicle-side TCP integration, or an operator-side client.
The important distinction is that the operator-side numbers are health indicators, while the High Latency fault is raised by the Streamer-side timestamp loop.
| Value | Where you see it | What it means |
|---|---|---|
|
|
A lightweight Oden com-channel ping from operator to vehicle and back. It is useful for network health, but it is not the video latency loop. |
|
|
An operator-control-message timestamp returned by the Streamer feedback message.
It shows that OCP control and feedback messages are flowing.
It can be |
OCP timestamp-loop latency |
Vehicle-side |
The Streamer-side measurement used for the |
How the timestamp loop works
The latency loop does not require synchronized clocks between the vehicle computer and the operator computer. OCP uses a Streamer-side elapsed-time clock and protects the timestamp with MAC values.
Streamer OCP elapsed clock
-> OcpControlMessage over vehicle TCP
-> vehicle integration copies ack fields into VehicleResponseMessage
-> Streamer embeds ack fields as video frame metadata
-> Player extracts metadata from the Remote Streamer
-> operator-side OCP or client returns latest ack fields
-> control message reaches Streamer
-> Streamer validates MAC and computes elapsed_ms - returned_ack_time
The external values you must preserve are:
ack_time-
A
u64elapsed-milliseconds timestamp generated by Streamer-side OCP. ack_time_mac-
A
u32MAC forack_time. OCP randomizes the Streamer-side key on startup.
Do not edit, reinterpret, scale, round, or regenerate either field.
Operator-side TCP clients and plugins should copy ack_time to ack_time_returned and ack_time_mac to ack_time_mac_returned.
The OCP operator sender performs the internal return MAC calculation before sending the control message back to the Streamer.
Message paths and ports
| Path | Default | Latency role |
|---|---|---|
Vehicle-side TCP |
|
Streamer OCP sends |
Operator-side TCP |
|
Optional external operator client receives |
Webview messages |
|
Webviews receive vehicle feedback and can send operator-side user data.
The injected |
Plugin shared data |
|
Custom operator-side plugins read feedback and publish client data. Plugins must copy the timestamp fields manually. |
Oden com-channel messages |
|
Internal OCP transport for control, feedback, and ping measurements. |
Video metadata |
Streamer frame metadata / SEI |
Carries the returned vehicle-side |
Both TCP APIs use a 4-byte little-endian length prefix followed by UTF-8 JSON.
Messages larger than 16 KB are dropped.
By default, TCP servers bind only to localhost.
Set ocp_tcp_allow_remote only when a TCP client must connect from another host, and protect that port at the network boundary.
Configure the measurement
OCP plugin parameters are passed at startup with --plugin-param.
oden-streamer --plugin-param latency_limit 750
| Parameter | Default | Use |
|---|---|---|
|
|
Vehicle-side TCP server port on the Streamer. |
|
|
Operator-side TCP server port on OdenVR / Player. |
|
unset |
Binds OCP TCP servers to |
|
|
Threshold in milliseconds for the Streamer-side |
These are the OCP settings that usually matter for latency measurement. For the overall OCP model, see Oden Control Pipeline overview.
Validate a basic setup
Use this flow when OCP should handle gamepad input and no custom operator-side TCP or plugin client is involved.
-
Enable the OCP global plugin in Oden Streamer and OdenVR / Player.
-
Start the Streamer output and connect the Player so video is visible.
-
Start the vehicle integration and connect it to the Streamer TCP server, normally
127.0.0.1:4000. -
In every vehicle response, copy
ack_timeandack_time_macfrom the latestOcpControlMessage.{ "ack_time": 123456, "ack_time_mac": 987654, "vehicle_user_data": { "user_data": {} } } -
On the operator station, open the OCP plugin GUI or read
ocp_vehicle_user_data. -
Confirm that
ping_latency_msis finite,message_latency_roundtripbecomes non-null,ack_timechanges over time, andreceiver_faultdoes not containHigh LatencyorLatency Loop Not Closed.
With no external client data source, OCP extracts the timestamp from video metadata and echoes it back internally. No JavaScript, operator plugin, or player-side TCP client is required.
Add operator-side data safely
Only one operator-side client data source may send OCP client data in a session. The first source that sends data becomes the locked source. If OCP later receives client data from another source, it logs an error, stops all client data communication, and requires a restart.
- Webview
-
Use
sendNamedUserMessage("ocp_client_user_data", payload). The injectedOdenLayoutClientstores the latestack_timeandack_time_macfromocp_vehicle_user_dataand injects them into each matchingclient_user_dataentry. If no custom JavaScript sends OCP client data, the webview client auto-echoes timestamps withuser_data: null. - Player-side TCP
-
Read
ack_timeandack_time_macfromVehicleOcpShared.vehicle_feedback. Return them asack_time_returnedandack_time_mac_returnedin the matching vehicle entry. - Custom operator plugin
-
Read
vehicle_ocpshared data. Publishclient_ocpshared data withack_time_returned,ack_time_mac_returned, optionaluser_data, and optionalocp_disable_gamepad.
For a TCP or plugin client, send the latest timestamp for the same vehicle name that received it:
{
"active_vehicle": "vehicle_a",
"client_user_data": {
"vehicle_a": {
"user_data": {
"mode": "work"
},
"ocp_disable_gamepad": false,
"ack_time_returned": 123456,
"ack_time_mac_returned": 987654
}
}
}
In multi-vehicle sessions, return timestamp fields for each vehicle you include in client_user_data.
Set active_vehicle to the vehicle that should receive OCP gamepad input.
Read operator feedback
A webview can display the values the operator needs with the Oden JavaScript SDK:
const client = getOrCreateOdenLayoutClient();
client.registerUserMessageCallback("ocp_vehicle_user_data", (payload) => {
for (const [vehicleName, feedback] of Object.entries(payload.vehicle_feedback ?? {})) {
console.log(vehicleName, {
ping: feedback.ping_latency_ms,
messageRoundtrip: feedback.message_latency_roundtrip,
ackTime: feedback.ack_time,
senderFaults: feedback.sender_fault,
receiverFaults: feedback.receiver_fault,
});
}
});
For operator UIs, show both fault arrays and at least these values:
-
ping_latency_msfor network health. -
message_latency_roundtripfor OCP control/feedback message health. -
receiver_faultfor Streamer-side faults, especiallyHigh LatencyandLatency Loop Not Closed. -
sender_faultfor operator-side faults, especiallyInput Lost,No Feedback Data, andVehicle Control Disabled. -
ack_timewhen diagnosing whether video metadata is arriving.
Do not treat ping_latency_ms or message_latency_roundtrip as the same value that raises High Latency.
The high-latency decision is made on the Streamer from the validated ack_time loop.
OCP GUI field guide
The OCP plugin GUI is available from the engineering sidebar when the plugin is enabled.
On OdenVR / Player:
- Operator Latency
-
Round-trip time from operator to vehicle and back for OCP message feedback. It may be stale when feedback is lost.
- Ping Latency
-
Lightweight network ping from operator to vehicle and back.
- Last Timestamp
-
Last Streamer-side
ack_timereceived from video metadata. - Controller
-
Last local controller input.
- Vehicle Data
-
Latest vehicle-side user data repeated from feedback.
- Missing Cameras
-
Cameras whose drop detector reports missing frames. An unnamed 2D video appears as
Unknown Camera; inputs with drop detection disabled are ignored. - Faults
-
Active OCP faults for the operator and vehicle path.
- Client Data
-
Operator-side data being sent into OCP and forwarded to the Streamer side.
On Oden Streamer:
- Ack Time
-
Timestamp values OCP adds to outgoing frames for latency measurement.
- Faults
-
Active receiver faults on the Streamer side.
- Controller Commands
-
Last control data sent over the vehicle-side TCP connection, including fault state.
- Vehicle Userdata
-
Last vehicle data received from the vehicle-side TCP client.
Troubleshoot symptoms
| Symptom | What to check |
|---|---|
|
No vehicle-side TCP client is connected to the Streamer OCP server.
Start the vehicle integration, verify the port, and remember that the default bind address is |
|
Streamer OCP has not received operator control messages for more than 1000 ms. Check the Player connection, Remote Streamer mapping, Fleet active vehicle state, and OCP plugin state on both sides. |
|
Operator OCP is not receiving Streamer feedback messages. Check the video/control connection first, then check Streamer-side OCP faults and logs. |
|
Streamer OCP found a monitored camera whose valid-frame timestamp is too old. Check the camera input, the Output Alignment children, and the camera drop detector. Cameras with drop detection disabled are not reported in this list. |
|
The Streamer frame loop is taking too long. Check CPU/GPU load, encoder load, blocking plugins, and whether the Streamer is overloaded. |
|
No gamepad input is available while OCP expects to forward gamepad input.
Connect a gamepad or set |
|
This vehicle is not the active control target.
In multi-vehicle sessions, send |
|
Timestamp validation failed.
Usually |
|
The timestamp loop is valid, but the latest returned timestamp is older than |
|
The operator side reported a sender fault to the Streamer.
Read the same vehicle’s |
|
The operator is not receiving valid video metadata.
Confirm the vehicle integration returns |
|
The Oden com-channel ping/pong path is unhealthy. Check Remote Streamer connection state, packet loss, route, firewall, relay path, and whether the vehicle is still connected. |
Client data stops after it was working |
Look for an OCP GUI error saying client data was received from another source. Restart Oden after removing the duplicate source. An open webview can auto-echo timestamps and become the webview source. |
|
OCP’s internal control-thread queue is delayed. Check CPU load, Streamer frame time, blocking plugin work, and application logs. |
Delivery checklist
Before handing over an OCP integration:
-
Vehicle TCP connects on the intended
tcp_portand reconnects cleanly. -
Every
VehicleResponseMessagecopiesack_timeandack_time_macunmodified. -
Only one operator-side client data source sends
ocp_client_user_dataorclient_ocp. -
Multi-vehicle operator data uses vehicle names consistently and sets
active_vehicle. -
Operator UI shows
ping_latency_ms,message_latency_roundtrip,sender_fault, andreceiver_fault. -
High LatencyandLatency Loop Not Closedare absent during a realistic driving or operating test.