# Oden Docs (latest) - Full Text > Learn about and set up the Oden teleoperation system. Single-document concatenation of the Oden documentation for LLM ingestion. Each page is delimited by a horizontal rule. Source: https://docs.voysys.dev/llms-full.txt Table of contents: https://docs.voysys.dev/llms.txt --- # Oden Docs Learn about and set up the Oden teleoperation system. Last validated: 2026-05-25 Oden is the Voysys software stack for low-latency remote operation of vehicles and machines. Oden has multiple components: the vehicle-side Oden Streamer, the operator-side OdenVR (Player), and the cloud fleet management system Bifrost. [What is Oden?](start/understand-oden.md) Get a brief introduction to Oden [Get Started](start/index.md) Install Oden and follow the quickstart to get started. [Stream Video and Audio](configure/index.md) Explore how to setup cameras, configure video and audio streaming. [Control a Vehicle](integrate/index.md) Learn how to control a vehicle using the available APIs. [Network Configuration](operate/network-configuration.md) Network link configuration. [Plugin API](integrate/plugin-api.md) Native plugins, C/C++/Rust SDK docs, and plugin messaging. [Supervise Many Vehicles](operate/index.md) Fleet supervision, multiple vehicles, monitoring, diagnostics, and troubleshooting. [Technical Reference](reference/index.md) Field-by-field reference for entities, settings, and subsystems. [Software Downloads](releases/downloads.md) Installers and release notes. ## Using these docs with LLM agents To make this site easier to feed to ChatGPT, Claude, Cursor, or any other LLM agent, every page is published in machine-readable form alongside the HTML: - [`llms.txt`](https://docs.voysys.dev/llms.txt) — a structured table of contents with direct links to every page in Markdown. - [`llms-full.txt`](https://docs.voysys.dev/llms-full.txt) — the entire documentation concatenated into a single Markdown document, ready for one-shot ingestion. - Any individual page is also available as Markdown: replace `.html` with `.md` in the URL (for example, [`/start/quickstart.md`](https://docs.voysys.dev/start/quickstart.md)). Point your agent at `llms.txt` first so it can fetch only the pages it needs, or hand it `llms-full.txt` when you want the whole context in one go. --- # Get Started Start using Oden from the portal-first flow, or fall back to manual installation and license activation. Last validated: 2026-05-05 Start here when you are setting up Oden for the first time. The preferred flow is portal-first: sign up or login to your Voysys portal account, create the vehicle/operator setup there, then use the installer and project configuration. ## Start using Oden - [What is Oden?](understand-oden.md) - get a brief intro to Oden. - [Quickstart](quickstart.md) - use the intended flow for a first vehicle-to-operator stream. - [Vehicle installation](vehicle-installation.md) - install the vehicle-side Streamer. - [Operator side](operator-side.md) - install OdenVR and sign in. - [Projects and web configurations](projects-and-web-configurations.md) - understand project configuration and operator layouts. ## Manual fallback The portal flow should be the normal path for new users. - [Manual installer reference](install-oden.md) - [Manual license activation](activate-licenses.md) - [Deployment](../operate/deployment.md) --- # What is Oden? Understand the main Oden products and the fleet connection model. Last validated: 2026-05-19 Oden is the Voysys software stack for remote operation of vehicles and machines. The vehicle side captures and encodes video, the operator side receives and displays it, and Bifrost coordinates fleet sessions when vehicles are managed through the Voysys cloud. ## Products and roles | Part | Role | | --- | --- | | Oden Streamer | Runs on the vehicle computer. It captures camera/video inputs, renders the Streamer scene, encodes output video, sends audio, and manages the vehicle-side network links. | | Oden Fleet Streamer | The same as Oden Streamer but includes the Fleet Client and Oden Control Pipeline plugins and a systemd service for headless operation. | | OdenVR | Runs on the operator computer. It receives the Streamer output, renders the operator view, and embeds the webview operator UI. | | Oden Dome Player | A Player variant for projection-dome installations. The same as OdenVR but with support for large scale dome rendering using multiple projectors. Contact Voysys for more information. | | Bifrost | Voysys fleet management. It tracks online vehicles, authenticates operators and vehicles, manages teleoperation sessions, and relays network traffic using our global network when needed. | In the docs, **Player** means OdenVR or Oden Dome Player. ## Fleet architecture The Streamer and Player both connect to Bifrost. The operator selects a vehicle by fleet name. Bifrost creates the session and sends connection information (including per-session encryption keys) to the Player and Streamer. When the connection is established, network traffic starts through a relay and then moves to peer-to-peer path if possible. Each network link carries video, audio, and data over the same connection. Typical flow: 1. The vehicle starts Oden Fleet Streamer and authenticates with Bifrost. 2. The operator starts the Player and authenticates with Bifrost. 3. The Player requests the online vehicle list. 4. The operator selects a vehicle. 5. Fleet Client configures the Player `Remote Streamer` entity with network links matching the Streamer project. 6. The Streamer starts output and the Player receives video, audio, and data. For the first connection steps, see [Oden Quickstart](quickstart.md) and [Connect Player and Streamer](connect-player-and-streamer.md). --- # Oden Quickstart Get a first Oden vehicle-to-operator session working through the portal-first flow. Last validated: 2026-05-25 This quickstart gets one vehicle-side Streamer online and one operator-side OdenVR session connected. The first stream can use a test source, so you don’t need a real camera to verify the path. For manual installer and license-key flows, see [Vehicle Installation](vehicle-installation.md) and [Operator Side](operator-side.md). ## Prerequisites Before you start, make sure you have: - A Voysys portal account. - One vehicle computer for Oden Fleet Streamer (can be the same as the operator computer). - One operator computer for OdenVR. - NVIDIA GPU with hardware video encoding on the Streamer. - Internet access from both machines during first setup. For platform, driver, and package details, see [Install Oden](install-oden.md). ## Steps 1. Create a new portal project. In the Voysys portal, create a project at [https://portal.voysys.dev/projects](https://portal.voysys.dev/projects). Leave it with the default values for now. 2. Add a new vehicle Go to the Vehicles tab ([https://portal.voysys.dev/vehicles\_admin](https://portal.voysys.dev/vehicles_admin)) and click "Add Vehicle". Give it a name and assign your newly created project. Click the "Show install command" button and copy it. 3. Install the vehicle side. Run the command on the vehicle computer. After installation, check the Streamer service: ```shell sudo systemctl status oden-streamer.service ``` For manual installation, see [Vehicle Installation](vehicle-installation.md). 4. Install the operator side. Download and install OdenVR on the operator computer. Start OdenVR and sign in when prompted. For manual Player license activation, see [Operator Side](operator-side.md). 5. Open the vehicles control page The OdenVR webview should list the vehicle once the vehicle-side Streamer is online. If you aren’t seeing the portal page, hit CTRL+H then go to the "Webview" tab in the left sidebar. There, check that the url is [https://portal.voysys.dev/vehicles](https://portal.voysys.dev/vehicles) 6. Connect to the vehicle. Select the vehicle and connect. 7. Verify video. You should see live video in OdenVR. If the vehicle is online but no video appears, press CTRL+H and open the Remote Streamer stats and check bandwidth, round-trip time, and packet loss. ## Manual first-stream fallback If you are not using the portal flow, use the manual path: - [Install Oden](install-oden.md) - [Activate Licenses](activate-licenses.md) - [First Vehicle Stream](first-vehicle-stream.md) - [Connect Player and Streamer](connect-player-and-streamer.md) ## Expected Success The quickstart is complete when: - The vehicle appears online in the portal or operator page. - The Player manages to connect to a vehicle. - A video appears in OdenVR. - The video streams live from the Streamer. - Remote Streamer stats show traffic from the Streamer to the Player. If the Streamer does not appear online, check that the vehicle install command finished, the service is running, and the vehicle computer can reach the portal/fleet service. If the vehicle appears online but video does not update, verify the Streamer video input first with the test source, then check Remote Streamer stats for packet loss or network reachability. ## Next Steps - [Control a Vehicle](../integrate/ocp-quickstart.md) - [Vehicle installation](vehicle-installation.md) - [Operator side](operator-side.md) - [Projects and web configurations](projects-and-web-configurations.md) - [Configure a real video input](../configure/camera-inputs.md) - [Configure network links](../operate/network-configuration.md) --- # Vehicle Installation Install Oden Streamer or Oden Fleet Streamer on the vehicle side. Last validated: 2026-05-05 Install the vehicle side from the Voysys portal whenever possible. The portal-generated command can include the right product, customer binding, vehicle role, and license context for that vehicle. ## Preferred portal flow 1. Open the Voysys portal and sign in. 2. Create or select the project and vehicle type for the deployment. 3. Add a vehicle or vehicle computer. 4. Copy the generated Linux install command for that vehicle. 5. Run the command on the vehicle computer. 6. Start or restart the Streamer service. 7. Confirm that the vehicle appears online in the portal. The generated command is the preferred path because it avoids copying a license key by hand and reduces the chance of installing the wrong product or JetPack package. The vehicle-side package is normally Oden Fleet Streamer for fleet-connected deployments. It includes the Fleet Client and Oden Control Pipeline plugins and can run as `oden-streamer.service`. ## Manual fallback Use manual installation when the portal flow is unavailable or when Voysys support asks you to install a specific package. 1. Download the package from [Software Downloads](../releases/downloads.md). 2. Choose the product and platform carefully. 3. Verify the `.sha256` file when available. 4. Install the package. 5. Activate the Streamer license manually. 6. Configure the Streamer project. 7. Start `oden-streamer.service` if the vehicle should run unattended. Manual install details: - [Manual installer reference](install-oden.md) - [Manual license activation](activate-licenses.md) - [Deployment](../operate/deployment.md) ## Jetson package choice On NVIDIA Jetson, the package must match the installed JetPack version. Check the target device with: ```shell cat /etc/nv_tegra_release ``` Do not install a package built for a different JetPack version. For the current package patterns and product support matrix, see [NVIDIA Jetson](install-oden.md#nvidia-jetson). --- # Operator Side Install OdenVR for the operator station and understand portal login and license fallback options. Last validated: 2026-05-25 The operator side normally runs OdenVR. For dome installations, the operator/display side may run Oden Dome Player instead. ## Preferred portal flow 1. Open the Voysys portal and sign in. 2. Download OdenVR for the operator computer. 3. Install OdenVR. 4. Start OdenVR. 5. Sign in through the portal-backed login flow when prompted. 6. Open the assigned operator page or web controls for your account. 7. Connect to the vehicle that has been assigned to you. In the self-serve flow, the operator should not need to paste a license key manually. Access is tied to the portal account, the project, and the vehicle/operator assignment. ## Enterprise login flows Enterprise customers can use custom login and assignment flows. That may include customer-hosted web pages, organization-specific identity provider behavior, or a dedicated operator interface. Those flows are gated enterprise features because they affect authentication, authorization, project hosting, and operational safety. Talk to Voysys before designing a custom operator login path. ## Manual license fallback Some deployments use product licenses directly on the operator computer. Use this path when the setup is not portal-login based: 1. Download OdenVR from [Software Downloads](../releases/downloads.md). 2. Install OdenVR. 3. Activate the Player license from the GUI or terminal. 4. Open the Player project. 5. Connect to the Streamer. See [Activate Licenses](activate-licenses.md) for manual activation and revoke steps. --- # Projects and Web Configurations Understand Oden project files, portal projects, and web-based operator configurations. Last validated: 2026-05-25 Oden has two related configuration layers. Web configurations Portal-backed or customer-hosted web projects that drive operator UI, vehicle selection, video layout, widgets, and control panels through Oden’s webview integration. Oden project files `.vproj` files loaded by Streamer and Player. They contain scenes, entities, camera inputs, stream settings, network links, plugins, and application settings. For new users, it’s preferred to use web configurations that the portal owns. For the detailed project model, see [Projects and Scenes](../configure/projects-and-scenes.md). ## Web-based operator layouts Web-based operator layouts use the Oden WebView and JavaScript SDK. The web page creates DOM regions for video, widgets, gauges, maps, and/or controls. Oden draws the actual video surfaces over those regions. For details, see: - [Project configuration](../configure/project-configuration.md) - [Player Layout](../configure/player-layout.md) - [Webview and JavaScript SDK](../integrate/webview-sdk.md) ## Gated enterprise features Non-web-login usage, custom web-page hosting, and customer-specific authentication flows are enterprise features. --- # Install Oden Install Oden Streamer, Oden Fleet Streamer, OdenVR, or Oden Dome Player. Last validated: 2026-05-26 Installers are available at [releases.voysys.dev](https://releases.voysys.dev). For more information, see [Software Downloads](../releases/downloads.md). For Streamer, prefer to use the install command that Voysys Portal generates for you as that will automatically activate your license as well. Choose the product you need, then choose the installer for your system. Download the matching `.sha256` file if you want to verify the installer before installing. ## Requirements and support Minimum practical hardware for both Streamer and Player machines: - Modern CPU with at least 4 cores. - 8 GB RAM or more. - Modern GPU (NVIDIA is recommended) Use the latest GPU drivers. GPU vendor support: | Platform | NVIDIA | AMD | Intel graphics | | --- | --- | --- | --- | | Windows 10/11 x64 | Supported | Supported | Supported | | Ubuntu 20.04 - 26.04 x64 | Supported | Supported | Supported | | NVIDIA Jetson | Supported | Not applicable | Not applicable | NVIDIA Jetson devices such as AGX Xavier, Xavier NX, Orin, and Thor are supported for embedded vehicle setups when the installed JetPack version matches the downloaded package. Product support by platform: | Platform | Oden Streamer | Oden Fleet Streamer | OdenVR | Oden Dome Player | | --- | --- | --- | --- | --- | | Windows 10/11 x64 | Supported | Supported | Supported | Supported | | Ubuntu 20.04, 22.04, or 24.04 x64 | Supported | Supported | Supported | Supported | | Jetson JetPack 4.6 arm64 | Supported | Supported | Not built for this JetPack | Not built for Jetson | | Jetson JetPack 5.1, 6.1, or 7.1 arm64 | Supported | Supported | Supported | Not built for Jetson | ## Windows Oden Windows installers are `.msi` packages for Windows 10/11 x64. Install GPU drivers Go to [NVIDIA Driver Downloads](https://www.nvidia.com/Download/index.aspx) and install the latest driver for your GPU. Install Oden 1. Open [releases.voysys.dev](https://releases.voysys.dev). 2. Go to the version you want to install. 3. Download the Windows installer for your product. 4. Run the `.msi` installer and follow the instructions. You can also install from PowerShell: ```powershell msiexec /i .\OdenVR_latest.msi ``` Replace `OdenVR_latest.msi` with the installer you downloaded. ## Ubuntu Oden Ubuntu installers are `.deb` packages for x64 Ubuntu. Current x64 release packages use the universal `_amd64.deb` filename and are built to run on Ubuntu 20.04 and newer. ### Install the latest release Run the installer script and choose a product when prompted: ```shell curl -fsSL https://releases.voysys.dev/install.sh | sh ``` Or pass the product role directly: ```shell curl -fsSL https://releases.voysys.dev/install.sh | sh -s -- fleet-streamer curl -fsSL https://releases.voysys.dev/install.sh | sh -s -- vr ``` ### Install a downloaded package Open a terminal in the download directory and install the `.deb` package with `apt-get`. The leading `./` is required. ```shell sha256sum -c oden-vr_latest_amd64.deb.sha256 sudo apt-get install ./oden-vr_latest_amd64.deb ``` Replace `oden-vr_latest_amd64.deb` with the package you downloaded. ### GPU drivers For NVIDIA GPUs on Ubuntu, install the latest `nvidia-driver-$VERSION` package, e.g. `sudo apt install nvidia-driver-595`. ### Noninteractive Fleet Streamer service install The `.deb` installer prompts for the EULA. Oden Fleet Streamer also asks whether to install, enable, and start the `oden-streamer.service` systemd service. The service is not installed by default. Pre-seed debconf when you want a fully noninteractive Fleet Streamer install that enables the service: ```shell echo "oden-streamer oden-streamer/accept-eula boolean true" | sudo debconf-set-selections echo "oden-streamer oden-streamer/install-services boolean true" | sudo debconf-set-selections sudo DEBIAN_FRONTEND=noninteractive apt-get install ./oden-fleet-streamer_*.deb ``` For a noninteractive Fleet Streamer package install without installing the boot service, pre-seed `install-services` as `false`: ```shell echo "oden-streamer oden-streamer/accept-eula boolean true" | sudo debconf-set-selections echo "oden-streamer oden-streamer/install-services boolean false" | sudo debconf-set-selections sudo DEBIAN_FRONTEND=noninteractive apt-get install ./oden-fleet-streamer_*.deb ``` Use the service-enabled variant only when the vehicle computer should start Streamer automatically on boot. Manage the service with `systemctl`: ```shell sudo systemctl status oden-streamer.service sudo systemctl restart oden-streamer.service sudo systemctl enable oden-streamer.service sudo systemctl disable oden-streamer.service ``` ## NVIDIA Jetson Jetson installers are arm64 `.deb` packages. The package filename includes the Ubuntu version and JetPack version, and it must match the JetPack version on the target device. Check the Jetson L4T release: ```shell cat /etc/nv_tegra_release ``` Install the downloaded package from a terminal: ```shell sha256sum -c oden-streamer_latest_arm64_20.04_jetpack_5.1.deb.sha256 sudo apt-get install ./oden-streamer_latest_arm64_20.04_jetpack_5.1.deb ``` Replace the filename with the product and JetPack package you downloaded. Do not install a package built for a different JetPack version. For Fleet Streamer service installation and service management, use the same debconf and `systemctl` commands as on Ubuntu. --- # Activate Licenses Activate, refresh, and revoke Oden licenses from the GUI or terminal. Last validated: 2026-05-25 Streamer and Player (unless activated per-session via the Portal) must be activated before use. Activation binds the license to the current computer. You need internet access when you activate a license or revoke a license. > **NOTE** > Activation contacts the Voysys license server and sends information that identifies the computer. This is required so the license can be tied to the machine. ## Before you start Make sure you have: - The license key from Voysys. - Internet access to `[https://license.voysys.se](https://license.voysys.se)`. - The Oden application installed on the computer where it will be used. - `sudo` or root access if you are activating a headless Streamer service installation. ## Activate from the GUI Use the GUI when you can open the application normally. 1. Start Oden. 2. Open **Help**  **Enter license key**. If Oden already has a key but is not activated, use **Help**  **Enter new license key**. 3. Paste the license key exactly as provided, including hyphens. 4. Press **Ok**. 5. Wait for the status text in the top bar to clear or change. ![activate license](_images/activate_license.png) Figure 1. License activation menu ![license textbox](_images/license_textbox.png) Figure 2. Enter license key If activation succeeds, Oden stores the key and the activated license data for that application. Restart Oden after the first activation so all licensed features are loaded with the new license state. To check the current license later, open **Help**  **License Info**. ## Activate from the terminal Use terminal activation for headless systems, remote machines, scripted setup, or systems where the GUI is unavailable. On Linux, use the installed command name: ```shell oden-vr --activate ``` ```shell oden-streamer --activate ``` The command prints `Activated successfully` when activation is complete. If the application already has a saved key, Oden refuses to overwrite it unless you explicitly add `--force`: ```shell oden-streamer --activate --force ``` Prefer revoking the old key before replacing it. Use `--force` only when you are intentionally replacing the saved key on the same computer. ## Headless Streamer and services For Oden Fleet Streamer installations: ```shell sudo oden-streamer --activate sudo systemctl restart oden-streamer.service ``` ## Move a license to another computer A license can only be activated on one computer at a time. Before using the same license key on another computer, revoke it on the current computer while that computer still has internet access. From the GUI: 1. Open **Help**  **Revoke current license**. 2. Press **Ok**. 3. Wait for the status text to report that revocation succeeded. ![revoke license](_images/revoke_license.png) Figure 3. Revoke license From the terminal: ```shell oden-vr --revoke ``` ```shell oden-streamer --revoke ``` After successful revocation, activate the license on the new computer. > **IMPORTANT** > Do not uninstall or wipe the old computer before revoking the license if you plan to reuse the same key. If the old computer is no longer available, contact Voysys support. ## Offline operation Oden does not require a continuous internet connection after a successful activation. It does require internet access again before the activated period expires. For offline deployments: - Activate the license while the machine is online. - Open **Help**  **License Info** and check **Activated To**. - Plan a maintenance window before that date to reconnect the machine and let Oden refresh the activation. - Revoke the license before decommissioning or replacing the computer. Oden shows a warning when the license is close to expiry. If a saved key exists and the license is near expiry, Oden attempts to refresh it automatically when the license server is reachable. ## Troubleshooting `Unable to connect to license server` Check internet access, DNS, firewall, proxy, and whether `[https://license.voysys.se](https://license.voysys.se)` is reachable from the computer. `License key was not recognized by the server` Check that the key was pasted correctly, including hyphens. `License key has already been activated on another computer` Revoke the license on the other computer first, then activate it again on this computer. `License not valid for this application` The license does not include the product you are trying to run. Check **Help**  **License Info** or contact Voysys to confirm which applications the key allows. `License has expired` or `License key has expired on the server` The license period has ended or the local activation was not refreshed in time. Reconnect the computer to the internet and run activation again. If the message remains, contact Voysys. `License is revoked` The local license data has been marked as revoked. Activate with a current license key. ## Where Oden stores license data Oden stores the saved key and activated license data per application. The files are named `key.conf` and `license2.lic`. Common application config roots are `%LOCALAPPDATA%\oden` on Windows and `$HOME/.config/oden` on Linux. Typical per-application roots include: | Application | Windows | Linux | | --- | --- | --- | | OdenVR | `C:\ProgramData\OdenVR\` | `$HOME/.config/oden/OdenVR/` | | OdenVRDev | `C:\ProgramData\OdenVRDev\` | `$HOME/.config/oden/OdenVRDev/` | | Oden Dome Player | `C:\ProgramData\Oden Dome Player\` | `$HOME/.config/oden/Oden_Dome_Player/` | | Oden Streamer / Oden Fleet Streamer | `C:\ProgramData\Oden Streamer\` | `$HOME/.config/oden/Oden_Streamer/` | For root-run Linux services, activate with `sudo` so `key.conf` and `license2.lic` are stored where the service process can read them. For project and application config context, see [Projects and Scenes](../configure/projects-and-scenes.md). --- # First Vehicle Stream Add a first video input, start Oden Streamer output, and verify the stream. Last validated: 2026-05-04 This page walks through a minimal Streamer setup: open or create the Streamer project, add one camera or video input, start the Streamer output, and verify that OdenVR receives the outgoing stream. ## Prerequisites - Oden Streamer is installed on the vehicle computer. - OdenVR is installed on the operator computer. - The vehicle and operator computers can reach each other over the configured network. - You know which video input to use, for example `GStreamer Pipeline`, `RTSP`, or `V4L2`. > **TIP** > If you do not have the real camera available yet, use `Test Source` as the first input. It verifies the project, encoder, and network path before camera-specific settings are added. ## Open The Streamer Project The Streamer project stores the vehicle-side scene, video inputs, network settings, and output settings. 1. Start Oden Streamer on the vehicle computer. 2. Open an existing project with **File**  **Open…​**. The default vehicle project is commonly stored at `/opt/oden-streamer/oden-vehicle-config.vproj`. 3. For a new first-stream project, configure the initially opened project and save it with **File**  **Save As…​**. 4. Save later changes with **File**  **Save** or Ctrl+S. If Oden Streamer normally runs as a service, stop the service before editing the project locally: ```console sudo systemctl stop oden-streamer.service sudo oden-streamer /opt/oden-streamer/oden-vehicle-config.vproj ``` After saving and closing Oden Streamer, start the service again: ```console sudo systemctl start oden-streamer.service ``` For remote project editing through OdenVR, add a `Streamer Configurator` entity in a Player project that already contains a `Remote Streamer` entity, then connect to the Streamer GUI from that entity. See [Projects and Scenes](../configure/projects-and-scenes.md) for project editing and configurator mode. ## Add A Camera Or Video Input 1. In Oden Streamer, select the `Root Entity` in the scene graph. 2. Add a video entity with **Edit**  **Add Child Entity**  **2D Video**. 3. Select the new `2D Video` entity. 4. In the entity settings, open the `Input` section. 5. Choose the input type that matches the camera or source: - `GStreamer Pipeline`: Use this for a custom GStreamer source, including shared GPU-memory pipelines on Jetson. Paste the pipeline in the `GStreamer Pipeline` settings and press `Start`. - `RTSP`: Use this for an IP camera or RTSP server. Set `Url`, choose the incoming `Codec`, enable `Video`, add credentials if required, and press `Start`. - `V4L2`: Use this for supported Linux camera devices. Select `Device`, `Pixel Format`, `Resolution`, and `Frame Rate`. - `Test Source`: Use this as a known-good placeholder while validating the first stream path. 6. Confirm that the `Texture` preview in the input settings updates. See [Camera Inputs](../configure/camera-inputs.md) for input-specific settings and [Player Layout](../configure/player-layout.md) for 2D video layout behavior. ## Set The Stream Output 1. Open the Streamer sidebar tab `Output`. 2. If the output is stopped, configure the basic encoder settings: - `Resolution`: Set the encoded output size. Start with a conservative value such as 1280 x 720 while validating the first stream. - `Frame Rate`: Set the outgoing frame rate. Match the camera frame rate when possible. - `Target Bitrate`: Set the encoder bitrate target, or the maximum bitrate when `Bandwidth Control` is enabled. - `Codec`: Use `HEVC (H.265)` unless the receiving system requires another codec. - `Sync to Video`: Enable this and select the primary camera source when low latency matters. - `Use FEC`: Enable Forward Error Correction on links with packet loss. 3. Press `Start` in the `Output` tab. 4. While streaming, confirm that the `Output` tab shows the current resolution, codec, bitrate, and frame-rate graphs. 5. Save the project with **File**  **Save**. See [Bitrate Control and Auto Video Packing](../configure/stream-settings.md) for output settings. ## Verify The Outgoing Stream 1. Start OdenVR on the operator computer. 2. Open the connect menu and select the vehicle. 3. Confirm that the Player project contains a `Remote Streamer` entity. 4. Select the `Remote Streamer` entity and check the received video. 5. In the `Remote Streamer` stats, verify: - `Bandwidth` is above zero while the Streamer output is running. - `Round Trip Time` is updating. - `Packet Loss` stays at zero or an acceptable value for the network. - The video image changes when the camera view changes. 6. If no video appears, check the Streamer first: the input preview must update and the `Output` tab must be running before troubleshooting OdenVR. See [Connect Player and Streamer](connect-player-and-streamer.md) and [Network](../configure/network.md). ## First-Stream Troubleshooting No input preview The issue is before streaming. Check the selected input type, camera URL or device, codec, credentials, and whether the input has been started. Output will not start Check that the encoder supports the selected `Resolution`, `Frame Rate`, and `Codec`. Try a lower resolution and bitrate. OdenVR connects but receives no video Confirm that the Streamer `Output` tab is running and that the Player has a `Remote Streamer` entity connected to the same vehicle. High packet loss or unstable video Lower `Target Bitrate`, enable `Use FEC`, and check the network link settings on both Streamer and Player. --- # Connect Player and Streamer Connect OdenVR or Oden Dome Player to Oden Streamer through fleet management or direct network links. Last validated: 2026-05-05 OdenVR receives video, audio, and feedback from Oden Streamer through a Remote Streamer entity. In this page, Player means OdenVR or Oden Dome Player. There are two common ways to establish that connection: - A fleet-managed connection, where Oden Fleet Streamer and the Fleet Client plugin ask Bifrost to set up the session and network links. - A local or direct connection, where you configure the Player and Streamer network links yourself. Use the fleet-managed path for deployed vehicles. Use the direct path for lab setups, local testing, or networks where the Player receive port is reachable from the Streamer. ## Fleet-managed connection The fleet-managed path requires Oden Fleet Streamer on the vehicle side and the Fleet Client plugin on the Player side. The Fleet Client handles the vehicle list, connection request, relay setup, encryption keys, and peer-to-peer transition when available. 1. Start Oden Fleet Streamer on the vehicle. If it was installed as a service, make sure the service is running. 2. Start OdenVR on the operator station. 3. Enable the **Fleet Client** plugin. If the project uses Oden Control Pipeline or a web UI, enable those plugins as well. 4. Open the connection menu in the Player. 5. Select an online vehicle and press **Connect**. When the connection is accepted, the fleet plugin either loads the project assigned to that vehicle or creates a Remote Streamer entity for the session. The plugin then configures the Remote Streamer network links and the corresponding Streamer links. Plugin checklist before the first fleet connection: - On the operator side, enable **Fleet Client** before selecting a vehicle. - Enable **Oden Control Pipeline** when the Player project should send control values or receive vehicle faults. - Enable **Webview** when the operator workflow uses the portal UI or a project webview. - Vehicle-side Oden Fleet Streamer installations normally include the Fleet Client and OCP pieces needed by the Streamer side. If a vehicle is online but control, status, or web UI behavior is missing, check that the matching plugins are enabled and that the license/auth state is valid on both sides. The same flow can be controlled from a web view by sending named user messages: ```javascript const odenClient = getOrCreateOdenLayoutClient(); odenClient.sendNamedUserMessage("fleet_list_vehicles", {}); odenClient.sendNamedUserMessage("fleet_connect", { vehicle_name: "vehicle_name" }); odenClient.sendNamedUserMessage("fleet_disconnect", { vehicle_name: "vehicle_name" }); ``` Use the vehicle `name` from `fleet_online_vehicles`, not the vehicle `id`. See [Webview and JavaScript SDK](../integrate/webview-sdk.md) for the full webview API. ## Local or direct connection In a direct connection, the Streamer initiates traffic and the Player listens. By default, a Remote Streamer entity creates a receiver link on port `47000`, and a Streamer network link sends to `127.0.0.1:47000`. For two computers on the same network, replace `127.0.0.1` with the Player computer’s reachable IP address. The Player firewall and network route must allow incoming traffic on the configured receive port. On the Player 1. Start OdenVR. 2. Open or create a Player project. 3. Add a **Remote Streamer** entity if the project does not already contain one. 4. In the Remote Streamer entity, open **Network**. 5. Use one link in **Receiver** mode. 6. Set **Receive Port** to `47000`, or choose another free UDP port. On the Streamer 1. Start Oden Streamer. 2. Open the Streamer project that captures and outputs the video. 3. In the Streamer sidebar, open **Network**. 4. Use one link in **Sender** mode. 5. Set **Destination Addr.** to the Player address: `127.0.0.1` for same-computer testing, or the Player IP address for another computer. 6. Set **Destination Port** to the Player **Receive Port**. 7. Open **Output** and press **Start**. When packets arrive, the Remote Streamer entity shows video and network statistics. If no video appears, verify that the Streamer output is started, that the Player receive port matches the Streamer destination port, and that the Player address is reachable from the Streamer. ## Which path to choose | Path | Use when | | --- | --- | | Fleet-managed | The vehicle is registered in Bifrost, Oden Fleet Streamer is installed, and operators should connect by vehicle name. | | Local/direct | The Streamer and Player are on the same computer or on a network where the Streamer can send directly to the Player receive address and port. | For detailed network settings, see [Network](../configure/network.md). For Remote Streamer diagnostics, see [Connection or no remote stream](../operate/troubleshooting.md#connection-or-no-remote-stream). For Streamer output settings, see [Bitrate Control and Auto Video Packing](../configure/stream-settings.md). --- # Stream Video and Audio Configure camera inputs, layouts, stream settings, etc. Last validated: 2026-05-25 Use this section when the vehicle is installed and you need to decide what video and audio Oden should send, how the operator should see it, and how much bandwidth the system should use. ## Stream setup - [Camera Inputs](camera-inputs.md) - add camera inputs - [Project configuration](project-configuration.md) - choose between portal configuration, webview `OdenVideo`, and native Oden entities. - [Bitrate control and Auto Video Packing](stream-settings.md) - tune encoder settings, bandwidth control, FEC, and Oden’s visible-video auto packing. - [Audio Streaming](audio.md) - configure vehicle-to-operator or two-way audio. - [Latency and Latency Measurement](../integrate/latency-measurement.md) - understand the control pipeline latency loop and related operator diagnostics. ## Display and calibration - [Stitching and Calibration](stitching-and-calibration.md) - combine cameras, calibrate camera rigs, and align output. - [VR](vr.md) - configure HMD output and headset-oriented layouts. - [Multiple monitors](multiple-monitors.md) - set up wide operator stations and spanning fullscreen. - [Dome projection](dome-projection.md) - configure Oden Dome Player and projector calibration. ## Advanced detail - [Advanced Video Features](advanced-video-features.md) covers output alignment, virtual cameras, color/keying, inference, and hardware decoding. - [Projects and Scenes](projects-and-scenes.md) covers low-level `.vproj` editing and scene entities. --- # Camera Inputs Add and tune camera or video inputs in Oden Streamer. Last validated: 2026-05-25 Camera inputs are configured on video entities in Oden Streamer. Use this page when you need to add a camera, choose the correct input type, or tune the capture settings. ## Choose an input type Pick the input type from the source you need to receive. Some entries are only shown when the current Oden build includes the required feature or SDK. | Task | Input type in Oden | Use when | Key settings | | --- | --- | --- | --- | | Receive an IP camera | RTSP | The camera exposes an `rtsp://` stream. | `URL`, `Codec`, `Username`, `Password` | | Receive RTP video | RTP | A sender transmits H.264, H.265, or MJPEG over UDP to Oden. | `Port`, `Codec` | | Use a custom GStreamer pipeline | GStreamer Pipeline | You already know the GStreamer source pipeline or need a source not covered by a simpler input. | `Pipeline` | | Receive SRT | SRT | A sender uses SRT and the build includes GStreamer SRT support. | SRT connection settings, `HW Decode`, `Codec`, pipeline latency | | Use a USB webcam on Linux | V4L2 | The camera appears as a Video4Linux2 device. | `Device`, `Pixel Format`, `Resolution`, `Frame Rate`, `Controls` | | Use a Windows capture device | Direct Show | The camera or capture card is exposed through Windows DirectShow. | `Device Name`, `Resolution`, `Pixel Format`, `Capture Rate`, `Frame Rate` | | Use FLIR or Point Grey cameras | FLIR (Spinnaker) | The camera is supported by the Spinnaker SDK. | `Device`, `Resolution`, `Pixel Format`, `Auto Frame Rate`, exposure, gain, white balance | | Use GigE Vision cameras | GigE | The camera is discovered on the network as a GigE Vision device. | Camera selection, pixel format, access mode, capture type, GenICam settings | | Use USB3 Vision cameras | USB3 | The camera is a USB3 Vision device and the internal USB3 capture feature is available. | `Allow Slow Cameras`, camera selection, GenICam settings | | Use Lucid Arena cameras | Lucid (Arena) | The camera is supported by Lucid Arena. | `Auto Reconnect`, device or `IP`, size, pixel format, frame rate, exposure | | Use IDS cameras | IDS | The build includes IDS support. | Camera serial, capture rate, exposure, gain, white balance, AOI | | Use Jetson CSI cameras | Argus | The streamer runs on NVIDIA Jetson with Argus support. | `Camera`, `Mode`, exposure, gain, AWB, denoise, edge enhance, camera crop | | Capture the desktop | Display Capture | You need a monitor or application output as a video source. | `Cursor`, `Monitor` | | Use a generated placeholder | Test Source | You need a known signal while configuring layouts or encoders. | `Resolution`, `Pattern` | | Use an image as video | Image | You need a static `.png`, `.jpg`, or `.jpeg` source. | Image file | | Reuse another Oden video stream | Clone Stream | Another entity already receives the source and you want to display or process it again. | `Follow Video`, `Focus Region`, sync settings, `Copy To Texture`, hard crop | | Receive NDI | NDI | The source is published on the network with NDI. | `Source`, `Quality` | | Receive Spout on Windows | Spout | Another Windows application shares a GPU texture through Spout. | `Source`, `Use Alpha Channel`, `Log Spout Messages` | | Play a file or URL through FFmpeg | File, HLS, RTMP, or FFmpeg | The source is a media file, HLS playlist, RTMP stream, or custom FFmpeg input. | `URL`, `Input Format`, `HW Acceleration`, `Live Source`, `Loop`, `Auto Start` | | Use a plugin capture | Plugin video capture | A loaded Oden plugin registers its own video capture type. | Plugin-defined options | ## Add an input 1. Open the video entity that should receive the camera. 2. Expand **Input** or **Inputs**. 3. If the entity has no input, select **Add Input**. 4. In **Type**, choose the source type from the table above. 5. Configure the source-specific fields. 6. Start the input if it has a **Start** button. 7. Confirm that **Texture** shows a live preview and that the input header reports the expected resolution and frame rate. 8. Set **Id** to a stable, meaningful name and color. > **TIP** > Keep input names consistent with the physical camera layout, for example `front_left`, `front_center`, and `rear`. This makes later camera-rig, crop, and stream troubleshooting easier. ## Configure common input behavior Every active video input can show a texture preview. Hover the preview for a larger view, or pop it out if you need to inspect focus or exposure while changing settings. Most input types also expose image-transfer, crop, vignetting, delay, and visibility controls after the capture-specific fields. Use those controls after the camera is receiving frames. - Use **Delay** only to align inputs that are consistently offset from each other. - Use **Crop** or **Crop and Vignetting** for display and calibration adjustments. - Use **Save texture** when you need a still image for support, calibration checks, or documentation. - Use **Visible In Eye** only for stereo setups where a source should appear in one eye. ## Configure network cameras ### RTSP Use **RTSP** for IP cameras that expose a direct RTSP URL. 1. Set **Type** to **RTSP**. 2. Set **Codec** to match the camera stream. 3. Enter the stream **URL**, for example `rtsp://192.168.0.20:8554/live`. 4. Enter **Username** and **Password** if the camera requires credentials. 5. Enable or disable video and audio receive options when the build exposes separate controls for them. 6. Select **Start**. If the stream does not start, verify the codec first. The dedicated RTSP and RTP inputs are NVDEC-based in the code, so they are only available in builds with the NVIDIA decode path enabled. When using the GStreamer RTSP path, use **Convert To Raw GStreamer Pipeline** after the simple RTSP setup works if you need to inspect or customize the generated pipeline. ### RTP Use **RTP** when another process sends encoded video directly to a UDP port. 1. Set **Type** to **RTP**. 2. Select the incoming **Codec**. 3. Set **Port** to the UDP port used by the sender. 4. Select **Start**. If you need RTP with a GStreamer mux, choose **RTP (GStreamer)** instead and set **Listen Port**, **Codec**, and **Mux**. ### GStreamer Pipeline Use **GStreamer Pipeline** when you need full control over the receive pipeline. Oden sends the pipeline into `odenvideosink`; you can include `! odenvideosink processing-deadline=0` yourself or let Oden append it. 1. Set **Type** to **GStreamer Pipeline**. 2. Enter the source pipeline in **Pipeline**. 3. Enable **HW Decode** only when the pipeline receives encoded video that should be decoded by Oden. 4. Set **Codec** when **HW Decode** is enabled. 5. Open **Advanced** if you need startup coordination or sink timing. 6. Select **Start**. Use **Exclusive Start** when several pipelines compete for camera, decoder, or network resources during project load. Lower **Exclusive Start Priority** values start earlier, and **Exclusive Start Duration** controls the spacing between starts. For live sources, keep **Sync On Sink** disabled unless you need the GStreamer timestamps to control presentation. For prerecorded or buffered sources, enabling **Sync On Sink** can make playback timing more stable. You can also use GStreamer when a camera feed must be shared with another process before it enters Oden. On Jetson, use zero-copy IPC when available so the camera frames stay in GPU memory. For example, a camera process can publish frames through `nvunixfdsink`, and Oden Streamer can receive them through a GStreamer Pipeline input using `nvunixfdsrc`. On JetPack 5, the `nvunixfd` plugin is bundled with the Streamer installer. On JetPack 6 and newer, install DeepStream or build `voysys/nvunixfd` and place the plugin `.so` in the GStreamer plugin path. ```shell gst-launch-1.0 -e -v videotestsrc is-live=true pattern=smpte ! \ video/x-raw,format=NV12,width=1280,height=720,framerate=30/1 ! \ nvvidconv ! \ "video/x-raw(memory:NVMM),format=UYVY,width=1280,height=720,framerate=30/1" ! \ nvunixfdsink socket-path=/tmp/nvunixfd.sock ``` ```shell nvunixfdsrc socket-path=/tmp/nvunixfd.sock buffer-timestamp-copy=true ! \ video/x-raw(memory:NVMM),format=UYVY,width=1280,height=720,framerate=30/1 ``` Disable `HW Decode` for this pipeline because the data is raw GPU memory, not encoded video. On JetPack 6 and newer, the source build path is: ```shell git clone https://github.com/voysys/nvunixfd.git cd nvunixfd make sudo cp ./*.so /usr/lib/aarch64-linux-gnu/gstreamer-1.0/ ``` If the Streamer runs in Docker, the same GStreamer plugin must be available inside the container. Bake it into the image or mount the `.so` from the host. ROS and ROS 2 can work for proof-of-concept testing, but they add latency and Oden does not ship built-in ROS capture support. Avoid ROS as the production video path unless the added latency has been accepted for the deployment. ### SRT Use **SRT** when the camera or gateway sends SRT through GStreamer. Set the SRT connection mode and address fields, choose the codec, and start the input. In **Advanced**, increase **Pipeline Latency** if the connection is unstable. ## Configure local capture devices ### V4L2 on Linux 1. Set **Type** to **V4L2**. 2. Select the **Device**. 3. Select **Pixel Format**. 4. Select or enter **Resolution**. 5. Select or enter **Frame Rate**. 6. Select **Start**. Use **Advanced** when the device needs non-default open behavior: - **Blocking Mode** waits for frames and can help cameras that fail with non-blocking reads. - **Retry Until Success** keeps trying to connect when the camera may not be ready at startup. - **Use Custom Path** lets you enter a path such as `/dev/v4l/by-id/` or another V4L2 node. - **Enable Timeouts** and **Max Timeouts** control how many read timeouts are tolerated before the capture stops. After the input starts, open **Controls** to tune camera-specific V4L2 controls such as exposure, brightness, contrast, or menu selections. Use **Reset All Settings** if the camera controls need to return to their defaults. ### Direct Show on Windows 1. Set **Type** to **Direct Show**. 2. Select **Device Name**. 3. Select **Resolution**. 4. Select **Pixel Format**. 5. Select the available **Capture Rate** range. 6. Set **Frame Rate** when the selected range allows it. 7. Leave **Retry** enabled if the device may disconnect and reconnect. Use **Rescan Devices** after plugging in a new capture device. Use **Rescan And Show All Devices** only when a device is hidden by the recommended-device filter. > **NOTE** > If Oden has a dedicated input for a source, prefer that over Direct Show. The Direct Show UI explicitly warns against using it for sources such as NDI and DeckLink when a better dedicated path exists. ## Configure industrial cameras ### FLIR (Spinnaker) 1. Set **Type** to **FLIR (Spinnaker)**. 2. Enable **Try to Reconnect** if the camera may be unplugged or powered late. 3. Select **Rescan Devices** or **Rescan Devices and Interfaces** if the camera is missing. 4. Select **Device**. 5. Select **Resolution** or enable **Custom Resolution** and set **Width** and **Height**. 6. Select **Pixel Format**. 7. Use **Auto Frame Rate** unless you need to force a lower rate. 8. Select **Start**. Use **Advanced** for sensor tuning: - **Center Image**, **Offset X**, and **Offset Y** control where a reduced image area is read from the sensor. - **Binning** reduces transmitted data while using a larger part of the sensor. - **Auto Exposure**, **Exposure Time**, **Gain**, and **Auto Exposure Limits** control brightness and frame-rate behavior. - **Auto WB**, **Red Balance**, and **Blue Balance** control white balance. - **Buffer Count** should normally stay at its default unless support asks you to change it. - **Reset on Startup** and **Reset Camera** are recovery tools for cameras stuck in a bad state. ### GigE Vision 1. Set **Type** to **GigE**. 2. Select the discovered camera. 3. Select the pixel format and start the input. 4. Open **Network Settings** when packet loss, multicast, or adapter selection needs tuning. Important GigE settings: - **Access Mode** controls whether Oden opens the camera exclusively or monitors an existing stream. - **Multicast Interface IP** selects the local interface for multicast. - **Capture Type** chooses the packet capture backend: socket, pcap, or Oden filter driver when available. - **Restart On Stall** lets Oden reconnect when frame delivery stops. - **Frame Completion** controls how incomplete frames are handled. - **Camera Settings** exposes GenICam controls and a device reset command. ### USB3 Vision Use **USB3** for USB3 Vision devices in internal builds that include USB3 capture. Install UsbDk on Windows if Oden reports that it is missing. Select the camera, configure GenICam settings, and start the input. Enable **Allow Slow Cameras** only for devices that cannot meet the expected USB3 throughput. ### Lucid (Arena) 1. Set **Type** to **Lucid (Arena)**. 2. Leave **Auto Reconnect** enabled for deployed systems. 3. Select **Rescan Devices** if the camera is missing. 4. Select a discovered device or enter the camera **IP**. 5. Set **Width** and **Height**. 6. Select **Pixel Format**. 7. Use **Auto Frame Rate** or set **Frame Rate** manually. 8. Open **Advanced** for offsets, exposure, gain, white balance, and buffer count. 9. Select **Start**. ### Argus on Jetson Use **Argus** for NVIDIA Jetson camera modules. Select the **Camera**, select the sensor **Mode**, and start the input. After the camera starts, tune auto exposure, exposure time, analog and digital gain, exposure compensation, AWB mode, white-balance gain, saturation, optical black, antibanding, denoise, and edge enhance as needed. Use **Camera Crop** before start when the sensor mode supports cropping. ## Configure utility inputs ### Clone Stream Use **Clone Stream** when one source needs to be reused in another entity. Select the source in **Follow Video**. Enable **Focus Region** when the clone should expose a smaller focus area for packing or monitoring. Enable **Copy To Texture** when you need independent filtering or hard crop on the clone. Without **Copy To Texture**, the clone uses the original source texture. Use **Hard Crop** only when the clone should produce a physically cropped texture instead of only reporting a focus region. ### Display Capture Use **Display Capture** to capture a monitor. On Windows, **Cursor** controls whether the pointer is included and **Monitor** selects the display. On Linux, Oden uses an X11 GStreamer capture pipeline. ### Test Source Use **Test Source** to verify layout, packing, encoding, and network output before connecting real cameras. Set **Resolution** and **Pattern**. Some static patterns can trigger drop detection, so disable drop-sensitive checks when intentionally using a static pattern. Use **Encoder Test** when you need a harder-to-encode generated source. It renders a colorful noise-based sphere and exposes settings such as noise amount, noise frequency, and animation speed. The extra detail is useful when checking encoder quality, bitrate control, and packet-loss behavior. ### Image Use **Image** for static visual checks. Select a `.png`, `.jpg`, or `.jpeg` file. Alpha is supported for formats that carry transparency. ### File, HLS, RTMP, and FFmpeg Use the FFmpeg-backed inputs for prerecorded files, HLS playlists, RTMP streams, or custom FFmpeg input strings. Set `URL` to the file path or stream URL, set `Input Format` when auto-detection is not enough, and choose hardware acceleration only when the deployed GPU and driver have been validated. Enable `Live Source` for sources that should be treated as realtime. Enable `Loop` for prerecorded files used as repeatable tests. Enable `Auto Start` when the source should start as soon as the project opens. ### NDI and Spout Use **NDI** for network NDI sources. Select the source and set **Quality**. Use **Spout** on Windows for GPU texture sharing from another application. Select **Source**, then set **Use Alpha Channel** and **Log Spout Messages** only when needed. Open **Info** to inspect whether the transfer path stays on the GPU or goes through CPU memory. Spout is a same-machine Windows GPU sharing path, so validate that the sending application and Oden run on the same GPU when avoiding CPU copies matters. ## Project-file names In `.vproj` files, the input backend is stored in the `capture` group as `impl`. The value is the snake\_case form of the C++ input enum. | Oden UI name | `.vproj` `impl` | Notes | | --- | --- | --- | | No Input | `unspecified` | | | GStreamer Pipeline, RTP (GStreamer), RTSP (GStreamer), SRT, Display Capture, Test Source | `gstreamer` | The subtype is stored in `gui_settings.type` as `pipeline`, `rtp`, `rtsp`, `srt`, `screencap`, or `video_test_src`. | | RTSP | `rtsp` | Dedicated NVDEC-based RTSP input. | | RTP | `rtp` | Dedicated NVDEC-based RTP input. | | FFmpeg, File, HLS, RTMP | `ffmpeg` | The subtype is selected by `input_format` and related FFmpeg settings. | | V4L2 | `v4l2` | Linux only. | | Direct Show | `dshow` | Windows only. | | FLIR (Spinnaker) | `spinnaker` | | | GigE | `gig_e` | | | USB3 | `usb3` | Internal USB3 capture builds only. | | Lucid (Arena) | `lucid` | | | IDS | `ids` | | | Argus | `argus` | Jetson only. | | Clone Stream | `clone` | | | NDI | `ndi` | | | Spout | `spout` | Windows only. | | Image | `image` | | | Encoder Test | `encoder_test` | | | OpenVR | `open_vr` | | | Plugin video capture | `plugin` | Uses plugin `type_id`, `type_name`, and plugin-defined options. | ```libconfig capture : { impl : "gstreamer"; pipeline : "videotestsrc is-live=true ! video/x-raw,width=1280,height=720,framerate=30/1"; use_nvdec : false; }; ``` Prefer changing inputs in the Oden UI when possible. When editing `.vproj` files directly, keep the `impl` value, subtype fields, stream width, stream height, and codec settings consistent with the selected source. ## Troubleshoot an input Use this checklist when an input does not show a live texture. 1. Confirm the input type is available in the current build. If a build does not include the required feature or SDK, Oden replaces the invalid input with **No Input**. 2. Confirm the camera is visible to the operating system or SDK. Use **Rescan Devices** where available. 3. Confirm codec and pixel format. For encoded network sources, a codec mismatch is a common reason for a black or missing texture. 4. Lower the resolution or frame rate. This helps isolate bandwidth, USB, decoder, or camera exposure limits. 5. Check whether the source is live before Oden starts. Use reconnect settings such as **Retry**, **Retry Until Success**, **Try to Reconnect**, or **Auto Reconnect** for deployed systems. 6. For GStreamer, convert a simplified input to a raw pipeline only after it works. Then inspect or modify the generated pipeline. 7. Save a texture once frames arrive. Use that still image to verify orientation, crop, exposure, and calibration outside the live system. --- # Project Configuration Choose portal-managed configuration, native Oden project layout, or webview video layout. Last validated: 2026-05-25 Use this page when you need to decide how the operator layout and vehicle project should be configured. ## Preferred portal configuration For new projects, the preferred path is portal-managed configuration. The portal lets you create the vehicle/operator setup, choose the layout, and setup the camera inputs without configuring `.vproj` files in the Oden GUI. That portal configuration can drive: - Which controls, gauges, and widgets appear. - Which web project or operator page opens. - Which video regions are visible to the operator. ## Native Oden project layout Use native `.vproj` configuration when you need direct control over scene entities. This is the fully flexible path. Native layout tools include: Entity positions Place 2D video, images, text, models, webviews, and other entities directly in the scene. Project Settings Store startup scene, view, auto video packing, and other project-specific behavior. For the detailed low-level model, see [Projects and Scenes](projects-and-scenes.md) and [Player Layout](player-layout.md). ## Webview OdenVideo layouts Use webview layout when the operator UI is a web app. The web page creates DOM elements for video regions, and Oden draws video into those regions. In React or plain HTML, the core idea is: ```html
``` ```javascript const odenClient = getOrCreateOdenLayoutClient(); odenClient.registerVideo("front-camera", document.getElementById("front-camera")); ``` For multi-vehicle layouts, use `vehicle_name:stream_name` so Oden can map the DOM region to the correct Remote Streamer. See [Webview and JavaScript SDK](../integrate/webview-sdk.md) for the SDK details. --- # Bitrate Control and Auto Video Packing Configure encoder, bitrate, FEC, bandwidth control, and visible-video auto packing. Last validated: 2026-05-25 Use the Streamer `Output` settings to choose what Oden encodes and how it adapts to the network. These settings affect the outgoing video stream received by the Player `Remote Streamer` entity. ## Open The Output Settings 1. Start Oden Streamer and open the Streamer project. 2. Open the sidebar tab `Output`. 3. If the stream is running and you need to change encoder-only settings such as `Resolution`, `Frame Rate`, or `Codec`, press `Stop` first. 4. Change the settings, then press `Start`. 5. Confirm that the `Output` header shows the expected resolution, frame rate, and bitrate while streaming. ## Set Resolution Use `Resolution` to set the encoded output size. Oden renders the current Streamer output or output-alignment result into this resolution before encoding. Higher resolutions preserve more detail but increase encoder load, decoder load, and required bitrate. 1. In `Output`, choose `Resolution`. 2. Start with a conservative value when validating a new vehicle, for example `1280x720` or `1920x1080`. ## Set Frame Rate Use `Frame Rate` to control how often Oden sends encoded frames when `Sync to Video` is disabled. Match the main camera frame rate when possible. 1. Make sure `Sync to Video` is disabled. 2. Open the `Frame Rate` section. 3. Choose one of the listed rates or use a custom frame rate. Use lower frame rates when the link cannot sustain the required bitrate or when operator latency is less important than image quality. ## Choose Codec The `Codec` setting is inside `Encoder Settings`. 1. Stop output if it is running. 2. Open `Encoder Settings`. 3. Choose `HEVC (H.265)` for the normal low-latency Streamer path. 4. Choose `H.264` only when the receiving system or hardware path requires it. 5. Choose `AV1` only on builds and hardware where the option is available. 6. Press `Start` and verify that the `Output` panel reports the selected codec. On Jetson systems, Oden warns when `H.264` is selected because `HEVC (H.265)` is the preferred low-latency codec. ## Set Bitrate Use `Target Bitrate` for a fixed target. When `Bandwidth Control` is enabled, `Target Bitrate` acts as the maximum bitrate Oden tries to use. 1. Set `Resolution` and `Frame Rate` first. 2. Set `Target Bitrate` high enough for the selected resolution, but below the reliable bandwidth of the link. 3. If the Player shows packet loss or unstable video, lower `Target Bitrate`. 4. If the image is stable but compression artifacts are visible, increase `Target Bitrate` gradually. When Auto Video Packer is used, prefer `Per Megapixel Bitrate` instead of a fixed `Target Bitrate`. It scales the active target with the current packed output resolution. `Per MP Bitrate Cap` limits the resulting bitrate. > **TIP** > `Per Megapixel Bitrate` is normalized to 30 fps. At higher frame rates, the effective bitrate is higher; at lower frame rates, it is lower. ## Use Bandwidth Control Enable `Bandwidth Control` when the network bandwidth varies or when the Streamer should react to Player feedback. It requires feedback from a Player-side `Remote Streamer` entity. 1. Open the `Bandwidth Control` section. 2. Enable `Enable`. 3. Leave `Target Usage` near the default `50%` unless measured testing shows that the link can safely run closer to saturation. It is deliberately below 100% so there is room for feedback, retransmission, FEC, audio, control data, and short network changes. 4. Keep `Auto Mode Switch` disabled for normal tuning. 5. Enable `Auto Mode Switch` only when the link can become very constrained and Oden should switch between regulator modes. 6. Watch the `Current Mode`, `Channel Usage`, `Bytes In Flight`, `Round Trip Time`, and `Wanted Bitrate` graphs while testing. With `Auto Mode Switch` enabled, the regulator modes can change `Resolution Scale`, `Frames to skip`, and `Max Packet Size`. The default modes are `High(Default)`, `Medium`, and `Low`. Use the default `Regulator Preset` unless a project-specific network test shows that a different preset is needed. Use `Save Coded Data To File` only for encoder debugging or support captures. It writes the encoded bitstream to the selected path and can consume disk space quickly. ## Use FEC Enable `Use FEC` when the link has packet loss but still has enough bandwidth for redundant packets. FEC can stabilize video, but it increases bandwidth usage and may push total traffic above `Target Bitrate`. 1. Enable `Use FEC`. 2. Set `FEC Amount` to the extra packet percentage to send. 3. Set `Min extra packets` to the minimum number of FEC packets Oden should send. 4. Leave `DFEC Bad Link Fade` unchanged unless you are tuning dynamic FEC behavior from measured link data. 5. Test from the Player and check whether packet loss artifacts decrease. Oden sends the larger result of `FEC Amount` and `Min extra packets`. If FEC makes congestion worse, lower `Target Bitrate`, lower `FEC Amount`, or disable FEC and fix the network link first. ## Sync To Video Enable `Sync to Video` when low latency to a primary camera is more important than a fixed output frame cadence. Oden synchronizes output to the selected video source and uses that source as the timing reference. 1. Enable `Sync to Video`. 2. Open `Sync`. 3. Select the primary camera in `Source`. 4. Set `Max Fps` to cap the synchronized output rate. 5. Set `Min Fps` to the lowest allowed synchronized output rate. 6. Leave `Delay` at `0 us` unless you need a measured post-sync delay. Choose the main driving camera as `Source` when one camera dominates the operator task. For projects that switch between forward and reverse driving cameras, change the sync source together with the active camera layout through the SDK or project logic. > **NOTE** > When `Sync to Video` is enabled, the manual `Frame Rate` section is hidden. Use `Max Fps` and `Min Fps` to bound the synchronized rate instead. ## Low-latency display settings Output settings are only part of end-to-end latency. For the lowest operator display latency, also check the Player and operating-system display setup. - Run the monitor at its maximum refresh rate. - Use native `Fullscreen` on the Player when possible. Windowed and composited modes can add display latency. - Disable VSync unless a project-specific display setup requires it. - Use NVIDIA Surround when several monitors must behave as one large display surface. - On Linux vehicle computers, run Streamer with `--headless` when the GUI is not needed. - Enable `Sync to Video` and select the primary camera when camera-to-display latency matters more than a fixed frame cadence. For deployed Player display settings, see [Player display setup](../operate/deployment.md#player-display-setup). ## Validate Changes 1. Start output. 2. On the Player, connect to the vehicle and select the `Remote Streamer` entity. 3. Check that `Bandwidth`, `Round Trip Time`, and `Packet Loss` match the expected network behavior. 4. In the Streamer `Output` panel, check the current resolution, codec, bitrate, and frame-rate graphs. 5. Save the project when the settings are stable. See also [First Vehicle Stream](../start/first-vehicle-stream.md) and [Connect Player and Streamer](../start/connect-player-and-streamer.md). --- # Audio Configure one-way and two-way audio streaming. Last validated: 2026-05-25 Oden audio streaming is configured in the Streamer `Output` panel and in the Player `Remote Streamer` entity. Use `Send` on the side with the microphone and `Receive` on the side with the speakers. ## Configure vehicle audio to the operator Use this for the common one-way setup where the Streamer sends vehicle audio to the Player. 1. On the Streamer, open `Output`. 2. Open `Audio Streaming`. 3. In `Send`, enable `Auto Start` if the microphone should start when the project opens. 4. Enable `Use Default` or select the capture `Device`. When the build exposes `Capture Source`, use `System` for normal operating-system audio devices and a project-specific source only when that source has been validated. 5. Keep `Period` at `10.0 ms, 480 frames` when using `Audio Processing`. 6. Keep `Mode` as `VBR` unless a fixed audio bitrate is required. 7. Set `Target Bitrate`; the default `64 kbps` is enough for most speech and ambient audio. 8. Select `Start Sending`. 9. On the Player, select the `Remote Streamer` entity. 10. Open `Audio`. 11. In `Receive`, enable `Auto Start` if playback should start when the project opens. 12. Select `Start Receiving`. 13. Adjust `Volume` while receiving. The receiver uses the default audio playback device. Change the operating-system default output device before starting Oden when the wrong speakers are used. ## Configure two-way audio Use two-way audio when the operator must talk back to the vehicle. 1. Configure vehicle-to-operator audio as above. 2. On the Player `Remote Streamer` entity, open `Audio`. 3. In `Send`, select the operator microphone and select `Start Sending`. 4. On the Streamer, open `Output` then `Audio Streaming`. 5. In `Receive`, select `Start Receiving`. 6. Test both directions separately before enabling `Auto Start` on both sides. Two-way audio uses the same network links as video. If one direction works and the other does not, check the responder ports, firewall rules, and link mode on both projects. ## Tune audio processing Open `Audio Processing` on the sending side. - Enable `Audio Processing` for microphone audio where echo, noise, or level changes are expected. - Set `Echo Cancellation` to `Moderate` first; raise it only if speaker echo remains. - Set `Noise Suppression` to `Low` first; higher values can make machinery or speech sound unnatural. - Increase `Compression Gain` only when the microphone is consistently too quiet. > **NOTE** > Audio processing requires `Period` to be `10.0 ms, 480 frames`. Oden shows a warning when audio processing is enabled with another period. ## Tune receive stability Use these settings when playback is choppy or the network reorders packets. 1. Increase `Receive Buffer` first; the default is `90 ms`. Larger values tolerate jitter but add latency. 2. Enable `Reorder Buffer` only when packet reordering is suspected. 3. Increase `Reorder Packets` gradually from the default `5`. 4. Increase `Max Invalid Packets In A Row` only when streams restart or reorder heavily and valid audio is rejected. Invalid packets are usually packets that are too old for the current audio timeline. 5. Re-test with `Show Stats` enabled and watch period, decode time, and bitrate. Prefer fixing network loss and jitter before adding large audio buffers. ## Linux audio setup On Linux, Oden uses PulseAudio and normally follows the desktop user’s default audio input and output devices. Configure those devices in the operating system sound settings before starting Oden. The default audio latency is `10 ms`. If a Linux setup needs a different PulseAudio latency, set `PULSE_LATENCY_MSEC` before launching the application: ```shell PULSE_LATENCY_MSEC=20 oden-vr ``` If Player or Streamer is intentionally running as `root`, PulseAudio may need to run system-wide. That is a system administration choice with security tradeoffs; prefer running the Player as a normal user unless the deployment requires root. For the upstream PulseAudio guidance, see [PulseAudio system-wide mode](https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/SystemWide/). --- # Latency Measurement Measure and troubleshoot OCP latency from the operator station. Last validated: 2026-05-25 Oden Control Pipeline (OCP) reports several latency-related values. | Value | Where you see it | What it means | | --- | --- | --- | | `ping_latency_ms` | `ocp_vehicle_user_data.vehicle_feedback..ping_latency_ms` and the OCP operator GUI as `Ping Latency` | 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. | | `message_latency_roundtrip` | `ocp_vehicle_user_data.vehicle_feedback..message_latency_roundtrip` and the OCP operator GUI as `Operator Latency` | An operator-control-message timestamp returned by the Streamer feedback message. It shows that OCP control and feedback messages are flowing. It can be `null` before feedback arrives and can look stale when feedback is lost. | | OCP timestamp-loop latency | Vehicle-side `telemetry.latency`, plus `receiver_fault` values such as `High Latency` or `Latency Loop Not Closed` | The Streamer-side measurement used for the `High Latency` fault. It follows the vehicle TCP response, video metadata path, operator echo, and return control message. | ## How the timestamp loop works OCP uses a Streamer-side elapsed-time clock and protects the timestamp with MAC values. ```none Streamer OCP elapsed clock -> OcpControlMessage over vehicle TCP -> vehicle integration copies ack fields -> Streamer embeds ack fields as video frame metadata -> Player extracts metadata from the video stream -> 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 `u64` elapsed-milliseconds timestamp generated by Streamer-side OCP. `ack_time_mac` A `u32` MAC for `ack_time`. OCP randomizes the Streamer-side key on startup. 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 | `127.0.0.1:4000` | Streamer OCP sends `OcpControlMessage` to the vehicle integration. The integration returns `VehicleResponseMessage` with `ack_time` and `ack_time_mac`. | | Operator-side TCP | `127.0.0.1:4001` | Optional external operator client receives `VehicleOcpShared` feedback and sends `ClientOcpShared` data. If used, it must return the latest timestamp fields. | | Webview messages | `ocp_vehicle_user_data` and `ocp_client_user_data` | Webviews receive vehicle feedback and can send operator-side user data. The injected `OdenLayoutClient` automatically echoes timestamps. | | Plugin shared data | `vehicle_ocp` and `client_ocp` | Custom operator-side plugins read feedback and publish client data. Plugins must copy the timestamp fields manually. | | Oden com-channel messages | `CONTROL_COMMAND_ID`, `FEEDBACK_MESSAGE_ID`, `PING_MESSAGE_ID`, `PONG_MESSAGE_ID` | Internal OCP transport for control, feedback, and ping measurements. | | Video metadata | Streamer frame metadata / SEI | Carries the returned vehicle-side `ack_time` and `ack_time_mac` from Streamer video output to the operator-side Remote Streamer. | 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`. ```shell oden-streamer --plugin-param latency_limit 750 ``` | Parameter | Default | Use | | --- | --- | --- | | `tcp_port` | `4000` | Vehicle-side TCP server port on the Streamer. | | `ocp_player_tcp_port` | `4001` | Operator-side TCP server port on OdenVR / Player. | | `ocp_tcp_allow_remote` | unset | Binds OCP TCP servers to `0.0.0.0` instead of `127.0.0.1`. | | `latency_limit` | `500` | Threshold in milliseconds for the Streamer-side `High Latency` fault. Increase it only when the measured end-to-end control path is acceptable for the vehicle. | These are the OCP settings that usually matter for latency measurement. For the overall OCP model, see [Oden Control Pipeline overview](ocp-overview.md). ## Validate a basic setup Use this flow when OCP should handle gamepad input and no custom operator-side TCP or plugin client is involved. 1. Enable the OCP global plugin in Oden Streamer and OdenVR / Player. 2. Start the Streamer output and connect the Player so video is visible. 3. Start the vehicle integration and connect it to the Streamer TCP server, normally `127.0.0.1:4000`. 4. In every vehicle response, copy `ack_time` and `ack_time_mac` from the latest `OcpControlMessage`. ```json { "ack_time": 123456, "ack_time_mac": 987654, "vehicle_user_data": { "user_data": {} } } ``` 5. On the operator station, open the OCP plugin GUI or read `ocp_vehicle_user_data`. 6. Confirm that `ping_latency_ms` is finite, `message_latency_roundtrip` becomes non-null, `ack_time` changes over time, and `receiver_fault` does not contain `High Latency` or `Latency 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 injected `OdenLayoutClient` stores the latest `ack_time` and `ack_time_mac` from `ocp_vehicle_user_data` and injects them into each matching `client_user_data` entry. If no custom JavaScript sends OCP client data, the webview client auto-echoes timestamps with `user_data: null`. Player-side TCP Read `ack_time` and `ack_time_mac` from `VehicleOcpShared.vehicle_feedback`. Return them as `ack_time_returned` and `ack_time_mac_returned` in the matching vehicle entry. For a TCP client, send the latest timestamp for the same vehicle name that received it: ```json { "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: ```javascript 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_ms` for network health. - `message_latency_roundtrip` for OCP control/feedback message health. - `receiver_fault` for Streamer-side faults, especially `High Latency` and `Latency Loop Not Closed`. - `sender_fault` for operator-side faults, especially `Input Lost`, `No Feedback Data`, and `Vehicle Control Disabled`. - `ack_time` when 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. In 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_time` received 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. In 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 | | --- | --- | | `Vehicle Not Responding` | 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 `127.0.0.1`. | | `No Control Messages` | 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. | | `No Feedback Data` | Operator OCP is not receiving Streamer feedback messages. Check the video/control connection first, then check Streamer-side OCP faults and logs. | | `Camera Lost` | 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. | | `Streamer Slow` | The Streamer frame loop is taking too long. Check CPU/GPU load, encoder load, blocking plugins, and whether the Streamer is overloaded. | | `Input Lost` | No gamepad input is available while OCP expects to forward gamepad input. Connect a gamepad or set `ocp_disable_gamepad: true` from the single operator-side client that provides its own controls. | | `Vehicle Control Disabled` | This vehicle is not the active control target. In multi-vehicle sessions, send `active_vehicle`. It is normal for connected but non-active vehicles to report this. | | `Latency Loop Not Closed` | Timestamp validation failed. Usually `ack_time` or `ack_time_mac` was missing, modified, returned for the wrong vehicle, or not copied through an operator-side TCP/plugin client. Also check that a webview, TCP client, and plugin are not all sending OCP client data in the same session. | | `High Latency` | The timestamp loop is valid, but the latest returned timestamp is older than `latency_limit`. Check video transport latency, network congestion, Player decode/display latency, vehicle integration delay, and how often the operator-side client returns fresh timestamps. | | `Operator Station Has Error` | The operator side reported a sender fault to the Streamer. Read the same vehicle’s `sender_fault` array and fix `Input Lost`, `No Feedback Data`, or `Vehicle Control Disabled` first. | | `ack_time` stays `0` or does not change | The operator is not receiving valid video metadata. Confirm the vehicle integration returns `ack_time` and `ack_time_mac`, Streamer output is running, the Player receives the Remote Streamer video, and metadata extraction is enabled for the receive path. If another plugin writes Streamer frame metadata in the same frame, OCP can fail to set its timestamp metadata and will log that failure. | | `ping_latency_ms` is missing, huge, or unstable | 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. | | `Internal Error (1)` | 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_port` and reconnects cleanly. - Every `VehicleResponseMessage` copies `ack_time` and `ack_time_mac` unmodified. - Only one operator-side client data source sends `ocp_client_user_data` or `client_ocp`. - Multi-vehicle operator data uses vehicle names consistently and sets `active_vehicle`. - Operator UI shows `ping_latency_ms`, `message_latency_roundtrip`, `sender_fault`, and `receiver_fault`. - `High Latency` and `Latency Loop Not Closed` are absent during a realistic driving or operating test. See also [Oden Control Pipeline overview](ocp-overview.md), [Vehicle-side control](vehicle-side-control.md), [Operator-side control](operator-side-control.md), [Webview and JavaScript SDK](webview-sdk.md), and [Oden troubleshooting](../operate/troubleshooting.md). --- # Stitching and Calibration Configure stitched video, output alignment, calibration captures, and dome calibration. Last validated: 2026-05-05 Use this page when a project combines several camera views, aligns Streamer output before encoding, or calibrates an Oden Dome Player installation. ## Stitched video workflow Stitched video combines multiple video inputs into one calibrated source. Use it when several cameras must produce one operator view, a dome source, or another composite view before streaming. It can also remove fisheye distortion from a single camera. Use a `Stitched Video` entity when the calibrated rig is created on the Streamer side. On the Player, a received stitched source is selected like another Remote Streamer video source; a plain `2D Video` only displays a flat source and does not run calibration. 1. Add the camera inputs first and confirm every input preview updates. 2. Add a `Stitched Video` entity. 3. Add the input cameras to the stitched video. 4. Capture calibration images with the calibration target visible. 5. Review captured images and marker detection. 6. Run optimization. 7. Check the stitched output for seams, horizon alignment, and field-of-view coverage. 8. Save the project and re-open it before acceptance testing. Use consistent camera names and stable input IDs. Changing input names after calibration makes later troubleshooting harder. ## Stitching controls Use the `Stitching` tab to tune how calibrated cameras are rendered together. Blend Distance Controls how much of the overlap between cameras is visible. `0.0` gives a hard boundary; `1.0` uses the full overlap. Blend Curve Controls how the blended overlap falls off between cameras. Type Selects the render surface, such as sphere, quad, GPU auto, or model when available. Show Stitch Zone Shows where camera feeds meet so blend settings can be adjusted deliberately. For sphere rendering, set the sphere radius near the distance to the objects the operator most often needs to judge. For quad rendering, use `Set As Calibrated Floor` after horizon calibration when the quad should match the calculated floor. GPU auto stitching can be expensive. Tune depth-map size and related quality settings on the target GPU, not on a development workstation. The common GPU auto presets trade depth-map resolution and quality against GPU cost; validate Low, Medium, High, and Ultra on the deployed computer before choosing. Minimum and maximum distance settings constrain the geometry range used by the automatic stitch. Manual geometry regions can override automatic stitching when a local area needs project-specific correction. Layered regions are applied deliberately, and manual overrides take precedence over automatic geometry in the affected area. Use stitch-zone position controls to move blend regions away from operator-critical details where possible. Always validate manual changes at the output resolutions and bandwidth-control resolution scales used in production. ## Calibration capture Calibration quality depends more on capture discipline than on the optimizer. - Use a clean calibration board with known dimensions. Printed markers must be flat, stable, and measured after printing. - Cover the full field of view that operators will use. - Capture enough angles to constrain overlap between neighboring cameras. - Avoid motion blur and overexposure. - Lock camera focus and exposure before the final capture set when possible. - Recalibrate when camera position, lens, focus, resolution, or crop changes. If the stitch looks correct in the center but drifts near an edge, verify that the calibration camera or board actually covered that edge. ## Calibration settings and checks The supplied Voysys calibration board uses the default board settings. If you print or build another board, measure it accurately and update: Square Length Physical width of each square on the calibration board. Cols / Rows Number of marker columns and rows. If the displayed board appears rotated or flipped, verify that columns and rows were not swapped. Fill Ratio How much of each white square is filled by its marker. Dictionary Marker dictionary used for detection. Single-marker settings are used for horizon calibration and calibration checks: Marker Size Physical marker size. Dict Size Dictionary size. Marker Bits Number of bits in each marker dimension. Marker ID Marker identifier inside the dictionary. Use `Check Calibration Using Marker` after calibration. A marker visible to two or more cameras lets Oden compute marker position, residual error, and which cameras saw the marker. Large residuals or one bad captured image set usually mean that capture should be deleted and retaken. Captured image sets can be inspected, deleted, imported, and exported. Use timed capture when one operator needs to collect several captures over a period of time: Count Number of captures. Interval Time between captures. Start Timed Capture Starts the timed sequence. Stored camera calibrations are `.camera` files. Add reusable presets through the application `Camera Calibration` path described in [Projects and Scenes](projects-and-scenes.md). ## Output alignment Use output alignment when the Streamer output should be composed or cropped before encoding. Common cases include selecting a subset of a stitched source, arranging several camera sources, or preparing a stream for a fixed Player layout. 1. Add or select the Streamer-side output alignment entity. 2. Add the video source or sources that should feed the encoded output. 3. Set each source position, size, and crop. 4. Start Streamer output and verify the encoded result on the Player. 5. Save the Streamer project. If a source appears in the local Streamer preview but not on the Player, check both output alignment and [Bitrate Control and Auto Video Packing](stream-settings.md). ## Horizon calibration Horizon calibration rotates stitched video to match the real world when the camera rig is tilted. Use the single ArUco marker on the back side of the calibration board, or print a marker on a flat stable surface. 1. Capture at least three marker observations. More captures usually produce a better result. 2. Press `Calibrate` when the button becomes available. 3. Fine-tune the manual horizon angles if the resulting center is not where the operator needs it. 4. Press `Bake Angle` after validation to bake the horizon angles into the camera rig settings. Use `Show Marker` to inspect detected marker positions. The detected marker rotation is not used by the horizon algorithm, so position quality matters more than visual rotation accuracy. ## Dome calibration prerequisites Dome calibration is an advanced workflow. Allocate time for the first calibration and validate each stage before moving on. Required equipment: - A Windows PC with an NVIDIA GPU; GTX 1080 or newer is strongly recommended. - Projectors connected to the PC. - A calibration camera with 4K or greater resolution when possible. - A high-quality fisheye lens. The dome can only be calibrated over the camera/lens field of view. - A capture card when the calibration camera is HDMI or SDI. - A calibration board for calibrating the calibration camera. ## Dome system setup 1. Connect and power on all projectors. 2. In Windows Display Settings, set multiple monitors to extend the desktop. 3. Configure NVIDIA Surround when the projector layout needs one large display surface. 4. Install Oden Dome Player. 5. Confirm the calibration camera can be received by Oden Dome Player. 6. Set camera focus before starting the final calibration capture. ## Dome calibration procedure 1. Open Oden Dome Player. 2. Set **Application Settings**  **Window Mode** to `Fullscreen`. 3. Restart Oden Dome Player so it enters fullscreen mode. 4. Save the project as `dome_calibration.vproj` or another clear commissioning name. 5. Position the calibration camera at the intended observer head position. 6. Connect the calibration camera. 7. Add a `Stitched Video` entity. 8. Calibrate the calibration camera. 9. Save the project. 10. Set **Application Settings**  **Rendering Mode** to `Dome`. 11. Set **Dome Renderer**  **Calibration**  **Source** to the calibration camera. 12. Start calibration and wait for the projected calibration pattern to finish. 13. Close and reopen the project. 14. Add a calibration sphere entity and verify that the sphere pattern looks non-distorted. 15. Use **Application Settings**  **Dome Renderer** to adjust angles. Use Ctrl+Q first so the view is centered. 16. Add edge blend zones for every overlapping projector pair. 17. Adjust dome border cutoff so projectors do not draw outside the projection surface. 18. Save the production project. For lowest display latency during dome operation, use fullscreen mode and check [low-latency display settings](stream-settings.md#low-latency-display-settings). ## Troubleshooting Calibration does not cover the whole dome Check whether the calibration camera and lens can see the whole area. Anything outside the camera field of view cannot be calibrated by that capture. Projectors show the Windows desktop incorrectly Fix Windows display arrangement and NVIDIA Surround before calibrating in Oden. Stitched source updates but encoded output is wrong Check output alignment, selected source, Streamer output resolution, and Player received stream. Edges look good but center is distorted Review camera calibration and captured board positions. Re-capture with sharper images and wider coverage. For camera setup, see [Camera Inputs](camera-inputs.md). For production display settings, see [Deployment](../operate/deployment.md). --- # VR Configure OdenVR for head-mounted displays and VR operator layouts. Last validated: 2026-05-05 Use VR when the operator needs a head-tracked view, immersive spatial perception, or headset-specific overlays. ## HMD setup 1. Install OdenVR on the operator computer. 2. Install and validate the headset runtime before starting OdenVR. 3. Open the Player `HMD` settings. 4. Select the runtime backend: `Any`, `Oculus`, `OpenVR`, `OpenXR`, or `None`. 5. Confirm that the headset renders the expected scene. 6. Save the Player project when the setup is stable. Tested headset families include Valve Index, HP Reverb G1/G2, and HTC Vive Pro 1/2. Other OpenVR/OpenXR-compatible headsets may work, but validate them with the production GPU, driver, and runtime. `Any` tries the available backends and uses the first one that starts successfully. Use a fixed backend for production once the runtime is known. ## Useful settings Fixed Position Locks HMD position to the origin. Fps Cam Track HMD Makes the monitor view track what the headset user sees. Draw Background Shows the Oden background in the headset. Draw While Inactive Keeps rendering even when the headset is not worn. Draw To Screen Disable screen rendering when only headset output is needed and GPU load must be reduced. Draw Controllers Draws tracked controllers in the scene where supported. HMD Navigation Lets the user move the VR world with both controller triggers or touchpads in OpenVR. Tracking Universe Selects seated or standing OpenVR tracking space. OpenVR Info Shows headset model, reported resolution, frame rate, and tracked device details. Magic Window Advanced support setting for special monitor/HMD coupling workflows. OpenXR Show Calibration Cross Draws per-eye calibration crosses for OpenXR validation. Oculus stats Shows runtime information for Oculus-backed deployments where available. Avoid changing field-of-view factors unless Voysys support has asked for it; non-default FoV can cause operator discomfort. ## Controller inputs Oden exposes supported HMD controllers as joystick inputs named `HMD Controller Left` and `HMD Controller Right`. Controller button and axis indexes can differ by runtime and controller generation. When a project plugin depends on controller input, open the controller settings on the exact production headset, verify the reported button and axis values, then save the remapping with the Player project or deployment profile. For layout details, see [Configure HMD layout](player-layout.md#configure-hmd-layout). --- # Multiple Monitors Configure Oden for wide operator stations, spanning fullscreen, and multi-display layouts. Last validated: 2026-05-05 Use multiple monitors when the operator needs a wide field of view, several persistent camera feeds, or a control-room workstation. ## Display mode Configure display behavior in the Player `Application Settings`. Fullscreen Lowest-latency path for one display. Windowed Fullscreen Useful when the operator station needs a borderless window without exclusive fullscreen. Spanning Fullscreen Use when several monitors should act as one wide display surface. For NVIDIA systems, configure NVIDIA Surround when the operating system should expose several physical monitors as one large display. Validate the display mode before tuning latency or video layout. ## Layout options Use one of these layout approaches: Portal/web layout Preferred for self-serve operator pages and dynamic layouts. Native 2D Video entities Good for fixed camera panels. Flexbox entities Good for rows, columns, and predictable native multi-camera layouts. Webview `OdenVideo` regions Good for dashboards where HTML/CSS controls video placement. See [Project Configuration](project-configuration.md) and [Player Layout](player-layout.md). ## Latency checks For lowest display latency: - Use the monitor’s maximum refresh rate. - Prefer exclusive fullscreen when the station uses one display. - Disable VSync unless the deployment requires it. - Check Oden Remote Streamer stats while the final display mode is active. See [Low-latency display settings](stream-settings.md#low-latency-display-settings). --- # Dome Projection Configure Oden Dome Player and projector dome calibration. Last validated: 2026-05-05 Use dome projection when the operator station is a projector dome rather than a flat monitor or HMD. ## Basic flow 1. Install Oden Dome Player on the dome computer. 2. Connect and arrange the projectors in the operating system. 3. Configure NVIDIA Surround if the projector layout should appear as one large surface. 4. Set Oden Dome Player to fullscreen. 5. Connect the calibration camera. 6. Run dome calibration. 7. Add edge blending and border cutoff. 8. Save the production project. ## Calibration Dome calibration depends on projector layout, camera placement, lens coverage, and the calibration board. Allocate time for the first calibration and validate each stage before moving on. The calibration camera can only calibrate the area it can see. If part of the dome is outside the camera/lens field of view, Oden cannot calibrate that region from the capture. See [Stitching and Calibration](stitching-and-calibration.md) for the full dome procedure. ## Latency Use fullscreen mode for production dome operation. Check [low-latency display settings](stream-settings.md#low-latency-display-settings) before acceptance testing. --- # Advanced Video Features Configure auto video packing, output alignment, video composition, color handling, chroma keying, AI inference, and hardware decoding. Last validated: 2026-05-05 Use this page when a project needs more than a single camera input and a simple encoded output. These features are still configuration tasks, so they live with the rest of the camera, scene, layout, and stream settings. ## Auto Video Packing Auto Video Packing lets the Player report which videos are visible and how much screen space they occupy. The Streamer then scales and packs those video sources into the encoded output so small or hidden feeds do not consume full resolution. Use it when: - A Player layout shows several camera feeds and the visible layout changes at runtime. - The operator UI can show the same source at different sizes. - The Streamer should avoid sending full-resolution video for feeds that are off-screen or visually small. Configure it from the Player project settings: Automatic Video Packing Enables Player-driven packing. Apply Auto Crop Takes viewport crop into account when calculating video size. When disabled, Oden sends the full video source and estimates screen occupation from the visible area instead of cropping the source to that area. Use Fixed Streamer Resolution Keeps the output resolution fixed instead of allowing dynamic output size. Fixed Streamer Resolution The fixed output size used when fixed resolution is enabled. On the Streamer, the `Output` panel shows the current packed output resolution, maximum Streamer resolution, Player screen resolution, and per-video packing data. When Auto Video Packing is enabled, use `Per Megapixel Bitrate` in [Bitrate Control and Auto Video Packing](stream-settings.md) so bitrate follows the dynamic packed resolution. Prefer auto packing over maintaining separate Streamer scenes only to change camera layouts. The screen analyzer also works through Virtual Cameras that are visible in the Player viewport. Per-video packing data includes the original resolution, screen occupation, crop percentage, cropped resolution, downscale factor, scale, and scaled resolution. `Downscale` is a priority multiplier from `0.0` to `1.0`; the default `1.0` keeps normal priority, while lower values tell the packer that the source may be reduced more aggressively. Important limits: - Auto packing supports up to 16 video sources. - Hidden videos are sent at no more than `32x32`. - Showing the same video several times can make that source consume more output resolution. ## Output Alignment Use `Output Alignment` on the Streamer when several 2D videos must be placed precisely inside the encoded output. Make the `2D Video` entities children of the `Output Alignment` entity. The entity sends alignment metadata with the stream so the Player can split the incoming encoded texture back into named sub-streams. The Player can receive: LLTP The complete encoded output texture. Stream A cropped sub-stream corresponding to one aligned video source. Focus Region Composite A region-of-interest stream assembled from one or more focus-region sources. Key settings: Enabled Locks the camera to the output-alignment layout. Keep it enabled while streaming or alignment metadata will be wrong. Snap to Output Adjusts focus-region placement to avoid encoder artifacts. Keep it enabled when using focus regions. Auto-Layout Attempts to place child 2D videos automatically inside the output area. Id The sub-stream identifier shown on the Player side. Position, Scale, Rotation, Mirror Pixel placement and orientation for each source. Per-source settings appear after a child `2D Video` has an active input source. The output coordinate origin is the upper-left corner. Sources may be placed partly outside the encoded output when a project intentionally crops them. Scale can be edited as pixels or percentage while keeping aspect ratio. Rotation is limited to right-angle rotations, and rotation or mirror settings also affect focus-region placement. Output Alignment affects child `2D Video` entities; other child entity types are not remapped into the encoded output. Focus regions are useful when one part of a camera needs more detail than the rest. Use one 2D video as the full source and another clone-stream 2D video as the focus source, then tune `Focus Center` and `Focus Size`. Validate every resolution scale used by bandwidth control, because encoder block boundaries can create artifacts at focus-region edges. ## Video Composition and Virtual Cameras Use `Video Composition` when multiple video inputs should become one larger texture before being cloned or displayed. The composition entity does not display video by itself; clone it into another video input or layout entity. Common settings: Resolution Output texture size. Background RGBA background color for empty areas. Add Source Adds a source video to the composition. The source behaves like a clone of the selected video source. Origin Upper-left pixel position for a source inside the composed texture. Size Pixel size for the source inside the composed texture. Preserve aspect ratio unless the project intentionally stretches the image. Texture preview Shows the composed texture. Save Texture as png Writes the current composed texture to an image file for inspection or support. Use `Virtual Camera` when a scene view should become a video source. Typical uses are extracting a 2D view from stitched video, rendering a subset of the scene, or creating a camera view that can be cloned into a Player layout. Virtual Camera settings to check: Resolution Output texture size. Field of View Camera field of view. Only Render Restricts rendering to entities with matching reference names to reduce load. Set To Current View Copies the current viewport position, rotation, field of view, and resolution into the virtual camera. Keep Aspect Ratio Preserves the configured aspect ratio when the rendered target changes size. Background Sets the virtual camera background. Texture preview and Save Texture Inspect or export the rendered virtual camera texture. Move View to Virtual Camera Moves the viewport to the virtual camera position. It does not change the viewport aspect ratio or field of view. A Virtual Camera does not display anything by itself. Consume it through a `2D Video`, `Clone Stream`, composition, or plugin workflow. ## Color and Keying Oden processes video and color internally with high-precision floating point color. Most camera and output color-format defaults are correct, but some sources expose color-standard choices such as BT.601 or BT.709, reduced or full range. Change them only when the source or display path is known to use a different standard. Common YCbCr choices are SD or HD, reduced or full range, with BT.601 usually matching SD sources and BT.709 usually matching HD sources. Color tools are available on video-oriented entities, including 2D Video and stitched video: Opacity Adjusts texture transparency. Use LUT Applies a `.cube` 3D lookup table. Curve Adjusts contrast and brightness response. Contrast, Brightness, Gain, Hue, Saturation Basic color correction. These controls are post-adjustments in Oden; they do not change camera firmware settings. Use LUTs from grading or calibration tools after basic correction when the same look should be reused across projects. For stitched video, individual per-camera RGB gain controls can be used where exposed to correct camera-to-camera mismatch before applying global corrections. For multi-camera stitched video, a typical color workflow is: 1. Synchronize colors between cameras. 2. Make global corrections until the image is neutral. 3. Apply a 3D LUT for the final look. Chroma Key removes a colored backdrop from a video surface. Tune it in this order: 1. Match the key color to the real backdrop color, including hue. 2. Increase hue and saturation tolerance before increasing value tolerance. 3. Raise `Threshold: Cut` until the backdrop becomes transparent. 4. Adjust `Threshold: Blend` for a smooth edge. 5. Use color correction and `Threshold: Color` to reduce colored fringes on retained objects. Matte and chroma-key settings should be validated on the real camera and lighting setup, not only on a still frame. ## AI Inference Oden can run neural networks through NVIDIA TensorRT when the build and hardware support it. Supported model formats are ONNX and TensorRT engine files. ONNX models are converted to a device-optimized TensorRT engine at runtime, which can take several minutes. Requirements: - NVIDIA GPU on desktop or Jetson. - TensorRT available to the Oden process. - CUDA and cuDNN available when ONNX import/conversion is needed. On Windows, install the TensorRT release supported by the deployed Oden version and make sure the TensorRT `lib` directory is on `PATH`. Inference settings: Add Neural Network Loads an ONNX or TensorRT model. IO Tensors Shows input/output tensors and lets you select a video stream as input. Info Shows network UUID and runtime duration. Manually Trigger Runs inference only when triggered through the plugin API instead of every frame. Use the plugin API to retrieve inference output. For plugin loading and project deployment details, see [Plugins](plugins.md). ## Hardware Decoding Oden supports hardware decoding for H.264/AVC, H.265/HEVC, and MJPEG on supported NVIDIA, Intel, and AMD paths. Current GPU drivers matter; install and validate drivers before diagnosing decode behavior. Hardware decoder settings can appear on supported inputs: Preferred Decoder Selects which GPU decodes when the computer has more than one supported GPU. Restart Oden after changing it. Skip Frame Drops decoded frames to reduce decoder load. This is mainly useful for MJPEG sources running faster than the needed stream frame rate. Decode Device NVIDIA CUDA device ID for NVDEC. FPS Match Matches decode cadence to render cadence where available. Min Queue, Max Queue, Decode Queue Queue sizes that trade latency against stability. Max Dec. Surfaces Number of decode surfaces held by NVDEC. Higher values can improve performance but use more memory. CUDA Buf. Depth Extra CUDA buffering when decoding on a non-default device. For camera-specific hardware decode options, see [Camera Inputs](camera-inputs.md). --- # Projects and Scenes Configure Oden project files, scene graph entities, project settings, application settings, and launch modes. Last validated: 2026-05-05 Use this page when you need to understand what is stored in an Oden project, how to edit a Streamer or Player project, and where the old reference-style settings now fit. ## Project files Oden projects are `.vproj` files using libconfig syntax. They store scenes, entities, inputs, output settings, network links, plugin paths, and project-specific view settings. | Project | Typical owner | Common path | | --- | --- | --- | | Streamer project | Vehicle computer or Fleet Streamer service | `/opt/oden-streamer/oden-vehicle-config.vproj` | | Player project | Operator station or fleet-assigned Player profile | Project-specific path chosen from **File**  **Open…​** | | Application config | Local application instance | Windows: `%LOCALAPPDATA%\oden\oden.conf`; Linux: `$HOME/.config/oden/oden.conf` | Prefer editing projects through the GUI. Edit `.vproj` files directly only for repeatable deployment changes that you can validate in Oden before shipping. ## Edit a Streamer service project When Oden Fleet Streamer runs as `oden-streamer.service`, stop the service before editing the same project in the GUI. ```shell sudo systemctl stop oden-streamer.service sudo oden-streamer /opt/oden-streamer/oden-vehicle-config.vproj sudo systemctl start oden-streamer.service ``` The service runs as `root`, so the project file may be owned by `root`. If saving fails, check ownership and reopen with the required permissions. To edit a headless Streamer remotely, run Streamer with the configurator mode enabled and connect from a Player project that contains both a `Remote Streamer` entity and a `Streamer Configurator` entity. The configurator streams the Streamer GUI to the Player so the project can be edited without a monitor on the vehicle computer. Remote configurator workflow: 1. Start the Streamer with `--headless --configurator` and the project you want to edit. 2. Start the Player and connect to the vehicle. 3. Add a `Streamer Configurator` entity to the Player scene. 4. Select the entity and press the connect button in its `Remote Streamer` section. 5. Edit the Streamer GUI in the streamed configurator window. 6. Save the Streamer project and restart the service when the edited project is used by `oden-streamer.service`. > **NOTE** > Some keyboard shortcuts may not work through the Streamer Configurator window. ## GUI areas Top menu Use `File` to open, save, import, and export project material. Use `Edit` to undo, redo, copy, paste, add, and delete entities. By default, `Paste Entity` replaces pasted video inputs with clone streams to the original inputs. Use Ctrl+Shift+V when you intentionally want to copy the original inputs instead. Use `Window` for fullscreen behavior. Use `Help` for license activation, license info, changelog, manual, and About. Common menu entries: | Menu | Use | | --- | --- | | File | Open, save, and reopen recent projects. Import or export scenes, cameras, and templates when part of a project should be reused. Close the current project or exit the application. | | Edit | Cut, copy, paste, add child entities, and delete selected entities. Many actions show their current keyboard shortcut in the menu. | | Window | Control display mode and fullscreen behavior where the current application exposes those actions. | | Help | Open the changelog, this manual, About, license entry, license information, and license revocation actions. For license workflow details, see [Activate Licenses](../start/activate-licenses.md). | Sidebar `Root Entity` holds the active scene graph. `Scenes` lists scenes in the project. `Raw Recording` records runtime video and scene data for later playback or support. `Network` and `Output` appear on Streamer. `Plugins`, `Com Channels`, `Statistics`, `Project Settings`, and `Application Settings` are shared concepts. The Player also exposes Player-specific settings such as HMD options when those features are available. 3D viewport Hold the left mouse button and use W, A, S, and D to move the viewport camera. Use Q and E to move down and up. Use the home icon or Ctrl+Q to return to the origin. Oden uses a right-handed coordinate system: `-Z` is forward, `+Y` is up, and `+X` is right. Entity positions use meters, rotations use degrees, and scale is unitless. ## Scenes and entities A scene is a tree of entities. The root entity holds child entities such as 2D video, text, models, output alignment, webview-facing video layout, Remote Streamer, and Streamer Configurator entities. Add entities by selecting the intended parent and using `Add Child`. Drag entities in the tree to rearrange them. Parent position, rotation, and scale are applied to child entities, so an empty `Entity` is useful as a grouping node, pivot, or shared transform. For stable projects, place related siblings under a clear shared parent instead of creating deep trees only to move several items together. Common entity choices: | Entity | Use | | --- | --- | | `2D Video` | Show a video input or a received stream in a Player scene. Configure placement, size, curvature, stereo eye visibility, border, chroma key, matte key, and input source. | | `2D Image` | Place a static image in the scene. | | `Text` | Place labels, debug values, or operator hints in a native scene. | | `Model` | Load and inspect a 3D model. Use collision mesh settings only when the project requires interaction or physics-like picking behavior. | | `Flexbox` / `Flexbox Group` | Lay out child entities in rows or columns using web-style flex concepts. Use it for native multi-camera layouts when a webview is not controlling placement. | | `Remote Streamer` | Receive video, audio, network stats, and Streamer feedback from a vehicle. Configure network links, audio receive/send, video codec expectations, reorder behavior, and stream diagnostics here. | | `Streamer Configurator` | Open the Streamer GUI from the Player side. Useful for headless Streamer setup and service deployments. | | `Output Alignment` | Map Streamer-side video sources into the encoded output. Use it when the Streamer output is composed from several video sources or when alignment must be controlled before encoding. | | `External Scene` | Loads a `.vscene` file into the project. Use it when a shared scene should be imported, saved separately, or updated outside the main project file. | | `Video Composition` | Creates one clonable texture from several video sources. Use it when several sources should be combined before another entity displays or clones them. | | `Scene Mirror` | Mirrors the content of another scene. Use it to reuse shared scene content, such as a dashboard or common overlay, without duplicating the original entities. | Useful entity details: 2D Image Loads static scene graphics from `.png`, `.jpg`, or `.jpeg` files. Alpha is supported for formats that carry transparency. Convert unsupported image formats before importing them. Text Exposes text content, color, glow, glow size, glow color, font, font height, and resolution settings. Use it for in-scene labels and instrumentation that should stay native to Oden rather than inside a webview. Model Loads glTF models. Use `Clone Model` or instanced rendering when a project needs several copies of the same model. `Open` loads the model file. Environment lighting can improve reflections but increases GPU work. `Inspect Model` is for temporary inspection; changes made there are not saved back to the source asset. Collision meshes are mainly for plugin interaction and project-specific picking workflows. External Scene Keeps scene content in a separate `.vscene` file. Use it for version-controlled shared scenes, reusable camera rigs, or scenes that several projects import. Child entities remain editable in Oden. `Save Scene` writes the `.vscene` file, and `Auto Save` keeps the external scene updated when the parent project is saved. Streamer Configurator Connects a Player-side configurator window to a Streamer GUI. Use direct server address entry when discovery cannot find the Streamer. Automatic discovery works best on the same local network. Use `Bind Address` or `Bind IP` when the computer has several interfaces and the configurator should use a specific one. The configurator UI scale follows the Player-side setting, the top-right controls set maximum width and height, and the bottom-right handle resizes the streamed window. For camera/source configuration, see [Camera Inputs](camera-inputs.md). For Player layout details, see [Player Layout](player-layout.md). ## Project settings Project settings are saved inside the `.vproj` file. Use them for behavior that should travel with the project rather than the local computer. Important settings: Startup Scene Scene opened when the project starts. Background Default background mode or color. Use `Default`, `Default, Only For Orbit Camera`, or `Color` when available. Set `Background Color` when the project should render against a fixed color. Camera Eye Which eye the monitor viewport shows when stereo/HMD output is configured. Show Grid and Grid Height Viewport grid display and height. Force Feedback Enables force feedback for supported joysticks. Auto Video Packing Automatically packs visible video into the encoded Streamer output. Use per-megapixel bitrate in stream settings when output resolution changes dynamically. View Field of view, position, rotation, project-default view, and saved states. Use `Reset View To Project Default` to return to the saved view. Use `Set View As Project Default` after positioning the viewport for the production layout. `Save Current State` records a named view state, and `Clear All Saved States` removes the saved list. Save the project after changing project settings. For production projects, reopen the project and verify that the selected startup scene and saved view are still correct. ## Application settings Application settings are local to the computer and application config file. Use them for display and interaction behavior that should not necessarily travel with every project file. Window Mode `Windowed` uses a normal resizable window. `Windowed Fullscreen` fills the screen without native fullscreen. `Fullscreen` gives the lowest display latency on one monitor. `Spanning Fullscreen` is windowed fullscreen across multiple screens. Monitor Selects the display used by fullscreen and windowed-fullscreen modes when several monitors are attached. Hide GUI on Startup Starts the Player with commissioning controls hidden. The GUI can still be toggled with the configured shortcut, normally Ctrl+H. Inhibit Mouse Look Prevents mouse motion from moving the viewport camera. Enable this for operator stations where the mouse is part of an external UI. VSync Disable VSync for lowest latency unless a project-specific display setup needs it. MSAA Multisample anti-aliasing. Enable only when the visual quality benefit is worth the extra GPU cost. Rendering Mode Selects display projection behavior such as single projection, separate projection, spanning fullscreen, cylindrical, or dome-specific projection modes where available. Use normal single-display modes unless the deployment has a measured multi-projector or dome requirement. Auto Template Path to a `.vtemplate` file applied to loaded projects. Use it for repeatable deployment defaults, not for ad-hoc project edits. Camera Calibration Path to stored `.camera` calibration presets. The path may contain environment variables and must end with a slash, for example `C:/dev/Cameras/`. Shrink View When GUI Visible When enabled, Oden uses only the visible viewport while the GUI is shown. When disabled, Oden uses the full window as the viewport even behind the GUI, so entities do not move when the GUI is hidden. Keyboard shortcuts Many menu actions show their shortcut in the menu. Keep shortcut changes documented for operator stations. Each shortcut uses a key plus optional Ctrl, Shift, Alt, or Super modifiers. Modifiers can be combined. Set a shortcut to `[Inactive]` when the action must not be available from the keyboard. Additional local behavior settings can include scroll mode, inverted mouse, GUI color mode, full project files, no prompt on exit, and only-show-exit-dialog. Use these as deployment controls for the local workstation, not as project behavior that should follow the `.vproj` to another machine. ## Local files and directories Application config, licenses, dome data, and global plugins are local to the machine. Do not assume they travel with a `.vproj` project file. | Data | Typical location | | --- | --- | | Application config | Windows: `%LOCALAPPDATA%\oden\oden.conf`; Linux: `$HOME/.config/oden/oden.conf` | | License data | Stored under the per-application Oden data root for the activated user. Typical roots are Windows `C:\ProgramData\OdenVR\`, `C:\ProgramData\Oden Streamer\`, `C:\ProgramData\Oden Dome Player\`; Linux `$HOME/.config/oden/OdenVR/`, `$HOME/.config/oden/Oden_Streamer/`, `$HOME/.config/oden/Oden_Dome_Player/`. For root-run services, activate with `sudo` so the service account can read `key.conf` and `license2.lic`. | | Project plugins | Project file directory or configured `Project Plugins Path`. | | Global plugins | Directory beside the Player or Streamer executable. | | Dome and calibration assets | Project-specific path or configured calibration preset directory. | ## Launch modes Use command-line flags in service files, startup scripts, or troubleshooting sessions. | Flag | Use | | --- | --- | | `--headless` | Linux Streamer mode where the GUI is not rendered. Use it for services, vehicle computers, and embedded platforms. | | `--configurator` | Allows a Player `Streamer Configurator` entity to connect to and configure a Streamer even without an active Remote Streamer connection. | | `--windowless` | Runs the Player with the window hidden. Toggle with Ctrl+Shift+H. | | `--multiple-streamers` | Allows more than one Streamer instance on the same computer. Use only when ports, project files, licenses, and capture devices are intentionally separated. | | `--plugin-param ` | Passes plugin-specific parameters from the launcher instead of storing them in the project. | For service deployment, see [Deployment](../operate/deployment.md). --- # Network Configure Oden network behavior and diagnose connection quality. Last validated: 2026-05-05 Oden network links carry realtime video, audio, feedback, and com-channel traffic between Streamer and Player. For most projects, configure one Streamer `Initiator` link and one Player `Responder` link. For bitrate, FEC, and bandwidth regulation, see [Bitrate control and Auto Video Packing](stream-settings.md). ## Configure a direct Streamer-to-Player link Use this when the Streamer can reach the Player IP address and UDP receive port. 1. On the Player, select the `Remote Streamer` entity. 2. Open `Network`. 3. Select `Add Link` if the entity has no link. 4. Set `Mode` to `Responder`. 5. Set `Receive Port` to the UDP port the Streamer will send to, for example `47000`. 6. Leave `Bind IP` empty or set it to `0.0.0.0` unless the Player must listen on one specific address. 7. On Linux, set `Bind Device` only when traffic must use one network interface regardless of system routes. 8. On the Streamer, open `Network`. 9. Set the Streamer link `Mode` to `Initiator`. 10. Set `Destination Addr.` to the Player address or DNS name. 11. Set `Destination Port` to the Player `Receive Port`. 12. Start `Output` and verify video on the Player. The default Streamer link is an initiator, and the default destination is `127.0.0.1:47000`. Change it before testing across machines. Core link settings: Mode `Initiator` sends to a destination address and port. `Responder` listens on a receive port and replies through the same link state. Receive Port UDP port used by a responder. Destination Addr. / Destination Port Address and UDP port used by an initiator. Bind IP Local address to bind. Leave empty or use `0.0.0.0`/`::` unless a specific local address is required. Bind Device Linux interface name used when the link must leave through a specific network device. Name Human-readable label shown in stats and commissioning notes. Bonding Group Groups links that carry the same realtime stream. ## Add modem or interface links Use multiple links when a vehicle has more than one modem, network adapter, or route to the Player. 1. Add one link per path on both sides. 2. Keep each Streamer `Destination Addr.` and `Destination Port` matched to the corresponding Player responder. 3. Give each link a `Name` that identifies the modem or adapter. 4. On Linux, set `Bind Device` for links that must leave through a specific interface. 5. Put links that carry the same stream in the same `Bonding Group`. 6. In `LLTP Bonding`, leave `Dynamic Bonding` enabled only when Oden should choose link usage from feedback. 7. Set `FEC Redundant Links` to `0` or `1` unless a measured network test shows that more redundancy is needed. Use `Link Stats` to confirm that traffic is flowing on the expected links. If one link shows errors or no traffic, first check route, firewall, bind device, and destination port. Link stats include per-link bandwidth, packet loss, bytes in flight, round-trip time, and channel usage. Use the graph colors and link names to confirm that each physical modem or interface is active during the test, not merely configured. ## Use P2P or encryption Use `P2P` when the link may be able to switch to a direct peer-to-peer path after initial connectivity. The default `STUN Server` is `stun.l.google.com:19302`. Add `Excluded Subnets` in CIDR notation, for example `100.100.0.0/24`, when a subnet must not be used for P2P. Use `Encryption` when the link must authenticate peers and encrypt traffic. 1. Generate or select a `Key Pair Path` on each side. 2. Copy the other side’s `Public Key` into `Allowed Public Keys`. 3. If traffic is relayed through a WireGuard server, set `Internal src.` and `Internal dst.` to the corresponding tunnel addresses. 4. Keep initiator links to one allowed public key unless support has given a project-specific reason to do otherwise. ## Relay traffic through a WireGuard server Use this pattern when Streamer and Player cannot reach each other directly and must relay encrypted Oden traffic through a standalone WireGuard server. In this setup, both Streamer and Player links use `Initiator` mode because both sides send to the relay server rather than directly to each other. Example assumptions: - WireGuard server: `gateway.example.com` - Streamer has two modem interfaces: `192.168.8.10` and `192.168.10.10` - Internal tunnel addresses: `10.200.0.10` and `10.200.0.20` for Streamer links, `10.200.0.30` and `10.200.0.40` for Player links | Setting | Link 0 | Link 1 | | --- | --- | --- | | Mode | `Initiator` | `Initiator` | | Bind Addr. | `192.168.8.10` | `192.168.10.10` | | Destination Addr. | `gateway.example.com` | `gateway.example.com` | | Encryption > Allowed Public Keys | WireGuard server public key | WireGuard server public key | | Encryption > Advanced > Internal src. | `10.200.0.10` | `10.200.0.20` | | Encryption > Advanced > Internal dst. | `10.200.0.30` | `10.200.0.40` | | Setting | Link 0 | Link 1 | | --- | --- | --- | | Mode | `Initiator` | `Initiator` | | Bind Addr. | `0.0.0.0` | `0.0.0.0` | | Destination Addr. | `gateway.example.com` | `gateway.example.com` | | Encryption > Allowed Public Keys | WireGuard server public key | WireGuard server public key | | Encryption > Advanced > Internal src. | `10.200.0.30` | `10.200.0.40` | | Encryption > Advanced > Internal dst. | `10.200.0.10` | `10.200.0.20` | Generate a key pair for every Oden link and copy each public key to the WireGuard server. ```ini [Interface] Address = 10.200.0.1/24 PrivateKey = WIREGUARD_SERVER_PRIVATE_KEY ListenPort = 51820 [Peer] PublicKey = WIREGUARD_STREAMER_LINK_0_PUBLIC_KEY AllowedIPs = 10.200.0.10/32 [Peer] PublicKey = WIREGUARD_STREAMER_LINK_1_PUBLIC_KEY AllowedIPs = 10.200.0.20/32 [Peer] PublicKey = WIREGUARD_PLAYER_LINK_0_PUBLIC_KEY AllowedIPs = 10.200.0.30/32 [Peer] PublicKey = WIREGUARD_PLAYER_LINK_1_PUBLIC_KEY AllowedIPs = 10.200.0.40/32 ``` Make sure Linux routing sends each Streamer modem interface through the intended modem gateway. For example, traffic bound to `192.168.8.10` should leave through the modem on that interface. ## Validate network changes 1. Start Streamer `Output`. 2. On the Player, open the `Remote Streamer` entity. 3. In `Network`, open `Stats` and enable `Enable Link Stats`. 4. Confirm that `Rx` and `Tx` traffic update on the intended link. 5. In `Output`, open `Bandwidth Control` and check `Bandwidth`, `Round Trip Time`, `Packet Loss`, and `Wanted Bitrate`. 6. Save both projects when link settings are stable. If video connects but audio or com-channel traffic does not, check the same link first. All realtime traffic uses the configured network manager links. ## Project-file names Network links are stored under `net_settings.links`. The UI mode names `Initiator` and `Responder` serialize as `sender` and `receiver`. ```libconfig net_settings : { links : ( { name : "primary"; mode : "sender"; bind_ip : "::"; destination_ip : "192.0.2.20"; destination_port : 47000; bonding_group : 0; } ); }; ``` In Streamer projects, `net_settings` is under `stream_settings.typeData.realtime_nvenc_gstreamer`. In Player projects, it is under the `remote_streamer` entity. --- # Player Layout Configure operator-side scenes, 2D video placement, native layout entities, and webview-controlled video layout. Last validated: 2026-05-05 Use this page when the Player must display one or more vehicle streams in a predictable operator layout. The same concepts apply to OdenVR and Oden Dome Player, but dome projection adds calibration steps covered in [Stitching and Calibration](stitching-and-calibration.md). ## Choose a layout path | Path | Use when | | --- | --- | | Webview layout | The operator UI is HTML/JavaScript, controls vehicle selection, or needs dynamic multi-vehicle video placement. | | Native Oden scene | The layout is fixed, simple, or built from Oden entities without a web UI. | | Hybrid | The project uses a native scene for base visualization and a webview for controls, state, or dynamic panels. | For webview API details, see [Webview and JavaScript SDK](../integrate/webview-sdk.md). For multiple-vehicle operator layouts, see [Multiple Vehicles](../operate/multiple-vehicles.md). ## Add a received stream to a native scene 1. Connect the Player to the Streamer. 2. Confirm the Player project contains a `Remote Streamer` entity for the connected vehicle. 3. Add a `2D Video` entity where the video should appear. 4. In the `2D Video` entity, open `Input`. 5. Select the received stream or camera name exposed by the Remote Streamer. 6. Set placement, scale, and optional curvature. 7. Save the Player project. Important `2D Video` settings: Visible In Eye Restricts a video to left eye, right eye, or both eyes for stereo/HMD/dome-style output. Curvature Bends the video plane for immersive or dome-like layouts. `0` is flat, negative and positive values curve in opposite directions, and extra subdivisions are exposed when curvature is non-zero. More subdivisions look smoother but cost more GPU work. Stereo Mode Controls how stereo content is interpreted. Use Eye Selects which eye is used when the source contains stereo content and only one eye should be displayed. Border Adds a visible edge around the video panel. View Fixed Keeps the video attached to the view instead of the world. Use pixel or percentage-based sizing for HUD-style elements that should stay fixed in the viewport. Color, Chroma Key, Matte Key Adjust compositing and keyed video appearance. Focus Region Defines the part of the video that layout or packing logic should treat as important. Keep the aspect ratio locked unless the operator task intentionally stretches the source. Enable anti-aliasing only where edge quality matters. ## Use webview video layout The Oden webview SDK maps DOM elements to Oden video surfaces. Use stable camera names, and include the vehicle prefix when several connected vehicles expose the same camera name. ```html
``` ```javascript const odenClient = getOrCreateOdenLayoutClient(); odenClient.registerVideo("front", document.getElementById("front")); odenClient.registerVideo("rear", document.getElementById("rear")); ``` For a single connected vehicle, `Front` may be enough. For multi-vehicle layouts, use `vehicle_name:stream_name` so the layout server can select the correct Remote Streamer. Use manual placement only when DOM-driven placement is not enough. Keep manual updates synchronized with resize events so video surfaces do not drift from their HTML elements. ## Use native layout entities Native Oden layout entities are useful for fixed operator views that do not need a web application. Flexbox / Flexbox Group Creates a row or column layout for child entities. Use it for multi-camera dashboards, fixed panels, and nested layouts. Use one root Flexbox per scene, then add Flexbox Groups when nested rows or columns are needed. Root viewport padding controls the outer margin. Group settings control direction, fill behavior, spacing, and alignment. Highlight settings help inspect layout bounds while commissioning. Scene Mirror Mirrors part of another scene into the current scene. Use it to reuse a camera or visualization area without duplicating source entities. Follow HMD Keeps an entity positioned relative to the HMD. Use it for head-mounted overlays. Child entities inherit the headset transform. Use `Sync to HMD Camera` when an overlay should follow the HMD camera exactly. Front-facing see-through layouts depend on runtime timing and should be validated on the exact headset. Follow HMD is primarily used with OpenVR/SteamVR-style deployments. Text and 2D Image Add fixed labels, indicators, static overlays, or fallback graphics. Model Load a 3D model into the scene. Use inspect and collision settings when the model needs to be checked or interacted with. Remote Stitched Video Displays a stitched source received from a connected Streamer. Select it like any other received stream after the Remote Streamer has connected. ## Configure HMD layout Use the Player `HMD` settings when the operator view is rendered to a headset. Tested headset families include Valve Index, HP Reverb G1/G2, and HTC Vive Pro 1/2. Other OpenVR/OpenXR-compatible headsets may work, but validate them with the production runtime and GPU. Key HMD settings: HMD Selection Select `Any`, `Oculus`, `OpenVR`, `OpenXR`, or `None`. Use `None` to disable HMD output. Fixed Position Locks headset position at the origin. Fps Cam Track HMD Makes the monitor view track what the headset user sees. Draw Background Shows the Oden background in the headset. Draw While Inactive Keeps rendering even when the headset is not worn. Draw To Screen Disable screen rendering when only headset output is needed and GPU load must be reduced. Avoid changing OpenXR/Oculus field-of-view factors unless Voysys support has asked for it; non-default FoV can cause operator discomfort. Use `Follow HMD` for overlays that should stay positioned relative to the headset. When controller plugins depend on HMD inputs, test controller remapping on the exact runtime and controller generation because button and axis IDs can differ. ## Stream naming Name streams and video inputs for the physical camera or operator task, not for temporary hardware labels. Recommended examples: - `Front` - `Rear` - `Left` - `Right` - `Boom` - `Thermal` Avoid names that change between vehicles in the same fleet. The webview and OCP pages use those names to route layout and active-vehicle behavior. ## Validate the layout 1. Connect to a test Streamer or use `Test Source` inputs. 2. Resize the Player window or switch to the production display mode. 3. Confirm each video stays in the expected position. 4. In webview layouts, disconnect and reconnect vehicles to verify that the UI re-registers surfaces. 5. In multi-vehicle layouts, check that `vehicle_name:stream_name` entries do not collide. 6. Save the Player project and reopen it. For display mode and hidden-GUI deployment settings, see [Deployment](../operate/deployment.md). --- # Plugins Enable, configure, and troubleshoot Oden plugins. Last validated: 2026-05-05 Plugins extend Oden with custom entities, global background logic, capture sources, controls, and project-specific GUI. Load plugin files from trusted project or application paths, then add the registered plugin entity or configure the global instance. ## Load a project plugin Use a project plugin when the plugin belongs to one `.vproj` and should travel with that project. 1. Put the plugin dynamic library and its runtime dependencies in a project folder, for example `bin`. The plugin file normally ends in `.dll` on Windows and `.so` on Linux. 2. Open the project in Oden. 3. Open `Plugins`. 4. Open `Plugin Paths`. 5. Select `Add`. 6. Set `Plugin Path` to the plugin folder. Use a relative path when the project and plugin folder should move together. The path may contain `%HOME%` for the user’s home directory. Hover the field in the GUI to inspect the expanded path when diagnosing loading problems. 7. Save and reopen the project so Oden scans the path. 8. Open `Plugins` again and confirm that the library appears under `Project Plugins`. 9. Add the plugin entity from the normal entity `Add Child` menu when the plugin registers an entity. 10. Configure the entity options exposed by the plugin, then save the project. If the plugin is in the same folder as the project file, Oden scans that folder even when no explicit plugin path is set. ## Configure global plugin instances Use a global plugin when the plugin should run without being added to the scene graph. Global plugin instances appear under `Plugins` > `Global Plugin Instances`. 1. Install the plugin where the application scans program plugins, or set the application-level additional plugin path. 2. Restart Oden. 3. Open `Plugins`. 4. Open `Global Plugin Instances`. 5. Expand the plugin name. 6. Configure the plugin-provided controls. 7. Disable the instance only when the project must load without that global behavior. Global plugin availability depends on the application startup paths, so restart Oden after changing those paths. ## Pass plugin parameters on startup Use `--plugin-param` for values that should be supplied by launch scripts or deployment tooling instead of the project file. ```bash oden-streamer --plugin-param tcp_port 4000 --plugin-param mode production ``` Plugins read these key/value pairs through the plugin settings API. The supported keys are plugin-specific. ## Use plugin video capture Some plugins register a video capture backend. Use it from a video entity when the source is not a built-in camera, file, or network input. 1. Load the plugin and reopen the project. 2. Open the video entity. 3. Open `Input`. 4. Set `Type` to `Plugin video capture`. 5. Select or confirm the plugin-provided capture type. 6. Configure the plugin-defined options. 7. Start the input and check the texture preview. For the surrounding video input workflow, see [Camera Inputs](camera-inputs.md). ## Troubleshoot plugin loading 1. Confirm the plugin path is visible in `Plugins` > `Plugin Paths`. 2. Reopen the project after changing `Plugin Path`; reopen Oden after changing application plugin paths. 3. Confirm the plugin file matches the operating system and Oden build architecture. 4. Check that all dynamic-library dependencies are available. Use Dependencies GUI on Windows, or run `ldd -r -d ./plugin.so` on Linux. 5. Confirm the plugin registers a unique entity ID. 6. Check `Project Plugins` for the library and expand it to see registered plugin entities. 7. If `Hot Reloading` is enabled, restart Oden before production testing. > **NOTE** > `Hot Reloading` is intended for development. Do not rely on it for deployed systems. ## Project-file names Project plugin folders are stored in `plugin_dll_paths`. The older single `plugin_dll_path` field is deprecated and is patched into `plugin_dll_paths` when old projects load. ```libconfig plugin_dll_paths : [ "bin" ]; scene_manager : { scenes : ( { root_entity : { children : ( { type : "plugin_entity"; plugin_entity : { type_id : "0b424e19-5f78-4a43-9c75-bd38cb1258b0"; type_name : "Inference Plugin"; options : ( ); }; } ); }; } ); }; ``` Plugin-defined options are stored with the plugin entity or plugin capture settings. Prefer changing them through the plugin GUI unless the plugin author documents the project-file fields. --- # Control a Vehicle Add vehicle control, telemetry, gauges, ROS bridges, and custom control integrations to Oden. Last validated: 2026-05-05 Use this section when video is working and the operator needs to send commands to the vehicle or receive vehicle state. The standard path is Oden Control Pipeline (OCP). OCP moves operator intent to the vehicle, returns vehicle feedback to the operator, and measures whether the control loop is healthy. ## Start with OCP - [OCP Quickstart](ocp-quickstart.md) - connect a gamepad and a vehicle-side terminal program that prints control values. - [Gauges](gauges.md) - show telemetry such as speed or battery in portal/widget-based controls. - [Control a Vehicle using OCP](vehicle-side-control.md) - implement the vehicle-side TCP/JSON integration. - [Operator-side control](operator-side-control.md) - add custom operator-side webview, TCP, or plugin data. - [Latency Measurement](latency-measurement.md) - understand timestamp echo, faults, and OCP GUI fields. ## Other integration paths - [ROS](ros.md) - bridge OCP data into ROS 1 or ROS 2 when the vehicle stack uses ROS. - [Custom plugin control](custom-plugin-control.md) - use Oden plugins for integrations that need native Oden APIs. - [Plugin API](plugin-api.md) - build plugins for custom entities, capture, controls, and messaging. --- # OCP Quickstart Verify Oden Control Pipeline with a gamepad and a vehicle-side terminal client. Last validated: 2026-05-05 Use this quickstart after video is working. It proves that OdenVR can send operator input to Oden Streamer and that a vehicle-side process can receive the values. ## What you will run - OdenVR with Oden Control Pipeline enabled. - Oden Streamer or Oden Fleet Streamer with Oden Control Pipeline enabled. - A gamepad on the operator computer. - A vehicle-side TCP client connected to `127.0.0.1:4000` that prints received JSON control values. ## Steps 1. Connect OdenVR to the vehicle and verify live video. 2. Enable the Oden Control Pipeline plugin on both sides. 3. Connect a gamepad to the operator computer. 4. Start the vehicle-side TCP print client on the vehicle computer. 5. Move the gamepad sticks and press buttons. 6. Confirm that the terminal prints changing `controller` values. 7. Confirm that OCP faults are clear or explainable. The TCP protocol is 4-byte little-endian length followed by UTF-8 JSON. The vehicle-side client must echo `ack_time` and `ack_time_mac` in its response so latency measurement stays closed. For the full vehicle-side implementation details and a Rust example, see [Vehicle-Side Control](vehicle-side-control.md). ## Expected output A working terminal client should show repeated OCP control messages with: - `controller.buttons` - `controller.axes` - `telemetry.latency` - `telemetry.fault` - `ack_time` - `ack_time_mac` If no messages arrive, check that the vehicle-side client is connected to the Streamer host and port, OCP is enabled, and the Player is connected to the vehicle. --- # Gauges Display vehicle telemetry such as speed, battery, or mode in portal/widget-based operator controls. Last validated: 2026-05-05 Use gauges when the operator needs live vehicle state in the control page. Examples include speed, battery, hydraulic pressure, drive mode, autonomy state, or warnings from the vehicle controller. ## Preferred portal/widget flow In the portal-based operator experience, gauges should be configured as widgets on the operator page. The vehicle integration sends telemetry through OCP, and the operator page binds widget values to fields in that telemetry payload. Typical flow: 1. Decide which vehicle telemetry field should be visible. 2. Add the value to `vehicle_user_data.user_data` in the vehicle-side OCP response. 3. In the portal, add a gauge or indicator widget. 4. Bind the widget to the telemetry field. 5. Test with the real vehicle or a simulator. For example, the vehicle-side response can include: ```json { "ack_time": 123456, "ack_time_mac": 987654321, "vehicle_user_data": { "user_data": { "speed_mps": 1.4, "battery": 0.82, "drive_mode": "manual" } } } ``` ## Webview fallback If you are building a custom webview instead of using portal widgets, listen for `ocp_vehicle_user_data` and render the values in your page. See [Operator-Side Control](operator-side-control.md) and [Webview and JavaScript SDK](webview-sdk.md). ## Design notes Show operator-critical values with clear units and stale-data behavior. OCP repeats the latest vehicle data, so dashboards should use `ms_since_last_vehicle_data` when they need to warn about stale telemetry. --- # Vehicle-Side Control Connect a vehicle controller to the Oden Control Pipeline. Last validated: 2026-05-04 Use the vehicle-side Oden Control Pipeline (OCP) TCP API when software on or near the vehicle needs to receive operator commands from Oden and return vehicle state to the operator station. Your integration runs as a TCP client. OCP runs inside Oden Streamer as a global plugin and exposes the TCP server. The minimum useful integration is: 1. Start Oden Streamer with the OCP plugin available. 2. Connect your vehicle process to the OCP TCP server. 3. Read each framed JSON control message. 4. Apply the command only after your vehicle-side safety checks. 5. Send a framed JSON response that copies `ack_time` and `ack_time_mac` from the latest control message. 6. Add optional `vehicle_user_data` when the operator UI needs vehicle state. OCP is the Oden transport, telemetry, and fault layer. It is not the vehicle safety controller. The vehicle integration should still enforce actuator limits, drive-state interlocks, emergency stop behavior, command timeouts, and any project-specific safety logic. ## Configure the TCP server By default, the vehicle-side OCP server listens on localhost: ```none 127.0.0.1:4000 ``` Set `tcp_port` when the default port is already used or your deployment reserves another local port: ```bash oden-streamer --plugin-param tcp_port 4100 ``` The server binds to `127.0.0.1` unless `ocp_tcp_allow_remote` is present. Use remote binding only when the TCP client cannot run on the Streamer host: ```bash oden-streamer --plugin-param tcp_port 4000 --plugin-param ocp_tcp_allow_remote 1 ``` When remote binding is enabled, OCP binds the TCP server to `0.0.0.0`. Restrict that port with firewall rules or a private vehicle network. The OCP TCP protocol has no separate authentication layer. Useful plugin parameters: | Parameter | Default | Use | | --- | --- | --- | | `tcp_port` | `4000` | Vehicle-side TCP server port on Oden Streamer. | | `latency_limit` | `500` | Round-trip latency limit in milliseconds before OCP raises `HighLatency`. | | `ocp_tcp_allow_remote` | not set | When present, binds TCP servers to `0.0.0.0` instead of `127.0.0.1`. | | `ocp_player_tcp_port` | `4001` | Operator-side TCP server port. Included here because `ocp_tcp_allow_remote` affects both TCP servers. | For general plugin startup syntax, see [Plugins](../configure/plugins.md). For the broader OCP model, see [OCP overview](ocp-overview.md). ## Connect from the vehicle process The vehicle process is the TCP client. OCP accepts one active vehicle-side TCP connection at a time. If the connection drops, reconnect from your process; when OCP accepts the next connection it clears old queued control messages from the previous session. Keep the socket open and respond continuously. OCP writes control messages while it also waits for response frames from your process. If OCP waits about 2 seconds for response bytes while reading a frame, it closes the connection and logs a vehicle TCP client connection error. Practical connection rules: - Connect to `127.0.0.1:4000` unless you deliberately enabled remote binding. - Use TCP no-delay if your client library exposes it. - Treat disconnects as normal lifecycle events and reconnect after a short delay. - Do not let response generation block on slow vehicle subsystems; publish stale-but-marked user data rather than blocking the timestamp response path. - Keep custom JSON payloads small. OCP’s TCP readers reject inbound messages larger than 16 KiB. ## Message framing Both directions use the same frame format: ```none uint32_le payload_length payload_length bytes of UTF-8 JSON ``` `payload_length` is an unsigned 32-bit integer encoded little-endian. The JSON payload must fit in 16 KiB. If your vehicle response is larger, OCP drains and skips that frame. Malformed JSON, missing required response fields, and short reads close the active TCP connection. ## Read control messages OCP sends `OcpControlMessage` frames from Oden Streamer to the vehicle process. The message is sent roughly every 10 ms while the connection is active. If no fresh operator command has arrived, OCP reuses the latest command until the relevant timeout fault is raised. When a control-path fault is active, OCP sends default controller values and sets the telemetry fault state. Operator-to-vehicle control messages are produced at the OdenVR frame rate, capped at 100 Hz. The vehicle-side TCP server forwards control frames every 10 ms while a TCP client is connected. If no new operator message has arrived, OCP repeats the last received message at least every 20 ms until a fault is raised. After the fault, OCP continues sending default controller values. Feedback from the Streamer to OdenVR is sent once per frame; when no new vehicle user data has arrived, OCP repeats the last received vehicle user data. ```json { "controller": { "buttons": { "a": false, "b": false, "x": false, "y": false, "left_bumper": false, "right_bumper": false, "back": false, "start": false, "guide": false, "left_thumb": false, "right_thumb": false, "dpad_up": false, "dpad_right": false, "dpad_down": false, "dpad_left": false }, "axes": { "left_x": 0.0, "left_y": 0.0, "right_x": 0.0, "right_y": 0.0, "left_trigger": -1.0, "right_trigger": -1.0 } }, "telemetry": { "latency": 42, "fault": false, "fault_reason": "" }, "ack_time": 123456, "ack_time_mac": 987654321, "client_user_data": { "mode": "manual" } } ``` Control message fields: `controller` Optional gamepad state. When present, buttons are booleans and axes are raw gamepad values in the `-1.0` to `1.0` range. The default safe value is all buttons `false`, stick axes `0.0`, and triggers `-1.0`. When OCP gamepad forwarding is disabled from the operator side, `controller` is `null`. `telemetry.latency` Vehicle-side OCP round-trip latency measurement in milliseconds. The default limit before `HighLatency` is raised is `500` ms. `telemetry.fault` `true` when OCP sees an active operator-side or vehicle-side control fault. Use this as a health signal in addition to your own command timeout and safety checks. `telemetry.fault_reason` Comma-separated diagnostic text for active OCP receiver faults, such as `High Latency` or `Latency Loop Not Closed`. Do not build safety behavior that depends on exact display strings. `ack_time`, `ack_time_mac` Timestamp fields for the OCP latency loop. Copy both values unchanged into your next response. `client_user_data` Optional JSON payload from the operator side for this vehicle. This is the operator-side `user_data` payload, not the full operator-side wrapper. ## Send responses The vehicle must send `VehicleResponseMessage` frames back on the same TCP connection. The response must include the latest `ack_time` and `ack_time_mac` values copied from an OCP control message. Without this echo, OCP cannot close its video/control latency loop and the operator side will eventually report latency or feedback faults. Minimal response: ```json { "ack_time": 123456, "ack_time_mac": 987654321 } ``` Response with vehicle data: ```json { "ack_time": 123456, "ack_time_mac": 987654321, "vehicle_user_data": { "pos": { "lat": 57.7089, "lon": 11.9746 }, "user_data": { "speed_mps": 1.4, "drive_state": "enabled" } } } ``` `vehicle_user_data` is optional. When included, `pos` may be omitted or set to `null`, but `user_data` should be present. The operator side receives the latest vehicle data repeatedly; include freshness or state timestamps in `user_data` if the dashboard needs to distinguish new data from repeated data. > **IMPORTANT** > Do not transform, regenerate, clamp, or reinterpret `ack_time` or `ack_time_mac`. They are not application timestamps. They are opaque OCP latency-loop values and must be copied byte-for-byte through your JSON number representation. ## Minimal Rust client This example shows the TCP framing and timestamp echo. It uses `serde_json::Value` to keep the example focused on the protocol. Production integrations should deserialize into project-specific structs and validate every command before applying it. ```rust use serde_json::{json, Value}; use std::{ error::Error, io::{Read, Write}, net::TcpStream, thread, time::Duration, }; const MAX_MESSAGE_SIZE: u32 = 16 * 1024; fn read_frame(stream: &mut TcpStream) -> Result> { let mut len_buf = [0_u8; 4]; stream.read_exact(&mut len_buf)?; let len = u32::from_le_bytes(len_buf); if len > MAX_MESSAGE_SIZE { return Err(format!("OCP frame too large: {len} bytes").into()); } let mut payload = vec![0_u8; len as usize]; stream.read_exact(&mut payload)?; Ok(serde_json::from_slice(&payload)?) } fn write_frame(stream: &mut TcpStream, value: &Value) -> Result<(), Box> { let payload = serde_json::to_vec(value)?; if payload.len() > MAX_MESSAGE_SIZE as usize { return Err(format!("OCP response too large: {} bytes", payload.len()).into()); } stream.write_all(&(payload.len() as u32).to_le_bytes())?; stream.write_all(&payload)?; stream.flush()?; Ok(()) } fn handle_connection(mut stream: TcpStream) -> Result<(), Box> { stream.set_nodelay(true)?; loop { let control = read_frame(&mut stream)?; let ack_time = control .get("ack_time") .and_then(Value::as_u64) .ok_or("missing ack_time")?; let ack_time_mac = control .get("ack_time_mac") .and_then(Value::as_u64) .ok_or("missing ack_time_mac")?; let fault = control .pointer("/telemetry/fault") .and_then(Value::as_bool) .unwrap_or(true); if !fault { // Apply validated controller/client_user_data to your vehicle bridge here. } let response = json!({ "ack_time": ack_time, "ack_time_mac": ack_time_mac, "vehicle_user_data": { "pos": null, "user_data": { "vehicle_bridge": "running" } } }); write_frame(&mut stream, &response)?; } } fn main() { loop { match TcpStream::connect("127.0.0.1:4000") { Ok(stream) => { if let Err(err) = handle_connection(stream) { eprintln!("OCP connection closed: {err}"); } } Err(err) => eprintln!("OCP connect failed: {err}"), } thread::sleep(Duration::from_millis(100)); } } ``` ## Handle faults safely Use `telemetry.fault` and your own watchdogs to decide when to hold, coast, brake, or otherwise enter a vehicle-specific safe state. Do not rely only on the controller values, because OCP intentionally sends default controller values during fault states. Common vehicle-side fault conditions: | Fault | Meaning | Vehicle-side action | | --- | --- | --- | | `VehicleNoResponse` | No vehicle TCP client is connected. | Start or reconnect the vehicle process. Check the bind address and port. | | `NoControlMessage` | The Streamer has not received operator control messages for more than about 1000 ms. | Treat the command stream as stale. Check the Oden network link and active vehicle selection. | | `HighLatency` | Measured OCP round-trip latency is above `latency_limit`. | Use project-specific degraded or stop behavior. Check network, video latency, and whether your vehicle process blocks before responding. | | `Latency Loop Not Closed` / `InvalidMac` | The timestamp loop did not return a valid `ack_time` / `ack_time_mac` pair. | Confirm the vehicle response copies both fields unchanged and the operator-side integration echoes timestamps correctly. | | `OperatorStationHasError` | The operator side raised a fault such as lost input or inactive vehicle control. | Treat operator commands as unhealthy until the fault clears. | | `Camera Lost` | At least one monitored 2D video input is stale according to the Streamer drop detector. | Decide whether the vehicle may continue with degraded visibility. | | `Streamer Slow` | The Streamer frame loop exceeded the slow-frame threshold. | Check Streamer CPU/GPU load and capture pipeline health. | Faults are self-recovering in OCP. Your vehicle controller should still require whatever local conditions are necessary before returning to active motion. ## Troubleshoot the integration Connection refused Confirm the OCP plugin is loaded in Oden Streamer, the port matches `tcp_port`, and no other process is using the port. By default the server accepts only local connections on `127.0.0.1`. Remote client cannot connect Start Oden Streamer with `--plugin-param ocp_tcp_allow_remote 1`, confirm the server host firewall allows the TCP port, and connect to the Streamer host address rather than `127.0.0.1`. Connects, then disconnects after a short time Make sure your process sends framed responses continuously. OCP closes the connection on malformed JSON, missing required response fields, oversized response frames, short reads, or about 2 seconds without response bytes. `HighLatency` appears after connecting Return `ack_time` and `ack_time_mac` immediately after each control message. Move slow vehicle reads, database writes, or dashboard aggregation out of the response path. If latency is genuinely expected to exceed 500 ms, set a project-appropriate `latency_limit`. `Latency Loop Not Closed` appears Check that `ack_time` and `ack_time_mac` are copied unchanged by the vehicle process. If you have a custom operator-side web view, plugin, or player-side TCP client, it must also echo the timestamp fields as described in [Latency measurement](latency-measurement.md). Controller is `null` The operator side has disabled OCP gamepad forwarding with `ocp_disable_gamepad`. Use `client_user_data` or another project-specific input path, and keep the vehicle-side safety logic independent of the presence of gamepad fields. Controller values are all defaults Check `telemetry.fault`. OCP sends default controller values during control-path faults. Default means buttons `false`, stick axes `0.0`, and triggers `-1.0`. Operator UI does not show vehicle data Confirm responses include `vehicle_user_data.user_data`, stay under 16 KiB, and are sent on the same TCP connection. On the operator side, read the OCP vehicle data through a web view, plugin, or player-side TCP client. See [Operator-side control](operator-side-control.md). ## Next steps - [Operator-side control](operator-side-control.md) - send operator-side custom data or display `vehicle_user_data`. - [Latency measurement](latency-measurement.md) - understand the full timestamp path. - [OCP overview](ocp-overview.md) - review plugin parameters, data paths, and fault behavior. --- # ROS Bridge Oden Control Pipeline data to ROS 1 or ROS 2. Last validated: 2026-05-05 Use ROS when the vehicle control stack already exposes commands, state, or autonomy interfaces through ROS. Oden does not require ROS. The recommended pattern is to keep Oden Control Pipeline as the Oden-facing transport and run a small bridge process that translates between OCP TCP/JSON and ROS topics, services, or actions. ## Recommended architecture ```none OdenVR -> OCP over Oden links -> Oden Streamer -> vehicle-side OCP TCP client -> ROS bridge -> ROS 1 / ROS 2 vehicle stack ``` The ROS bridge should: - Connect to the Streamer OCP TCP server. - Read `OcpControlMessage` frames. - Validate faults and command freshness. - Publish safe, project-specific ROS commands. - Read ROS telemetry. - Return `VehicleResponseMessage` frames with `ack_time`, `ack_time_mac`, and vehicle user data. ## Repository Voysys should publish and link the maintained ROS bridge repository from this page. Until that public link exists, treat ROS integration as a support-guided path. The bridge should be kept small and auditable. Vehicle safety limits should still live in the vehicle controller or safety layer, not only in the bridge. See [Vehicle-Side Control](vehicle-side-control.md) for the OCP TCP protocol. --- # Custom Plugin Control Use Oden plugins for custom vehicle control and operator integrations. Last validated: 2026-05-05 Use a custom plugin when the integration needs direct Oden APIs, shared data, custom entities, custom capture, or tighter coupling to the Oden update loop than a TCP sidecar provides. For most vehicle controllers, start with OCP TCP first. Move to a plugin only when the integration needs native Oden behavior. ## Good plugin use cases - Custom operator input device handling. - Custom visualization entities. - Plugin-defined video capture. - Shared data between Oden plugins. - Operator-side data that should feed OCP without a webview or external TCP client. - Project-specific controls that need to run inside the Oden frame loop. ## APIs to look at Plugin SDK Main native extension surface. Use it for custom entities, global plugins, GUI controls, and update-loop integration. Com Channels Plugin-defined messages between Player and Streamer. Use when you need custom Oden-to-Oden messages outside the OCP contract. OCP shared data Operator-side plugins can read `vehicle_ocp` and publish `client_ocp`. Use this when plugin code is the operator-side control source. Webview named messages Use when a browser UI should exchange JSON with plugins. See [Plugin API](plugin-api.md) and [Plugin Messaging](plugin-messaging.md). --- # Operator-Side Control Connect an operator-side application to the Oden Control Pipeline. Last validated: 2026-05-04 Operator-side OCP integration is optional. Add it when the operator station needs a custom dashboard, custom input path, active-vehicle selection, automation, or an external process that exchanges data with the vehicle through OCP. For the complete control-path model, start with [Oden Control Pipeline overview](ocp-overview.md). For webview layout and general JavaScript SDK behavior, see [Webview and JavaScript SDK](webview-sdk.md). ## Choose an operator-side path | Path | Use it for | What handles timestamps | | --- | --- | --- | | Webview | Browser-based operator UI inside OdenVR / Player. | The injected `OdenLayoutClient` stores `ack_time` and `ack_time_mac` from vehicle feedback and injects them when JavaScript sends `ocp_client_user_data`. | | Player-side TCP | A local external application, service, or test tool. | Your TCP client must copy `ack_time` and `ack_time_mac` from feedback into `ack_time_returned` and `ack_time_mac_returned`. | | Custom Oden plugin | A plugin that needs direct access to Oden shared data or another native input device. | Your plugin must publish the returned timestamp fields in `client_ocp`. | Only one client data source may send OCP client data during a Player session. The first source that sends data locks the session to `Webview`, `TCP`, or `Plugin`. If another source sends data later, OCP logs a source-conflict error, stops client data processing, and requires a Player restart. > **IMPORTANT** > A web page that creates `OdenLayoutClient` can auto-echo OCP timestamps even when your application code has not sent custom OCP data yet. If you intend to use Player-side TCP or a custom plugin as the operator data source, do not also run a webview that participates in OCP. ## Receive vehicle feedback All operator-side paths receive the same logical feedback object. It is keyed by vehicle name, so use those keys when setting `active_vehicle` or sending per-vehicle user data. ```json { "vehicle_feedback": { "vehicle-1": { "ping_latency_ms": 8, "message_latency_roundtrip": 42, "ms_since_last_vehicle_data": 12, "missing_cameras": null, "sender_fault": [], "receiver_fault": [], "vehicle_data": { "pos": { "lat": 57.7, "lon": 11.9 }, "user_data": { "battery": 0.82 } }, "last_remote_input": null, "ack_time": 123456, "ack_time_mac": 654321 } }, "last_input": null } ``` Use these fields first: `vehicle_feedback` Map from vehicle name to feedback for that vehicle. `vehicle_data.user_data` Custom JSON returned by the vehicle-side integration. OCP repeats the latest received vehicle data; use `ms_since_last_vehicle_data` to detect stale data. `sender_fault` / `receiver_fault` Operator-side and vehicle-side OCP faults as strings. `last_remote_input` Controller input last reported back from the vehicle side. `ack_time` / `ack_time_mac` Timestamp values for the OCP latency loop. Webview code normally does not handle them directly. TCP clients and custom plugins must echo them back. `last_input` Last local gamepad/controller input sent by the operator station. It is `null` when no input is available or OCP gamepad forwarding is disabled. `last_remote_input` Last input reported back from the vehicle side. Use it to show what command the vehicle most recently received, not just what the operator most recently pressed. `missing_cameras` List of monitored camera names whose drop detector reported missing frames. It is `null` when monitored cameras are healthy. Cameras without drop detection are not listed. ## Send operator data Send `ClientOcpShared` data back to OCP when you need to select a vehicle, attach operator-side user data, or disable OCP’s built-in gamepad forwarding. ```json { "active_vehicle": "vehicle-1", "client_user_data": { "vehicle-1": { "user_data": { "mode": "manual", "requested_tool": "bucket" }, "ocp_disable_gamepad": false, "ack_time_returned": 123456, "ack_time_mac_returned": 654321 } } } ``` `active_vehicle` Selects which vehicle receives OCP gamepad input. With one connected vehicle, it may be omitted. With multiple vehicles, set it to one of the keys from `vehicle_feedback`; otherwise OCP marks vehicle control inactive. `client_user_data` Map from vehicle name to data for that vehicle. The vehicle-side TCP message exposes this as `client_user_data`. `user_data` Your custom JSON payload. If you use it as a custom control command path, the vehicle-side integration must explicitly read and validate it. `ocp_disable_gamepad` Set to `true` when OCP should not forward its gamepad controller object. This also suppresses the operator-side `InputLost` fault. `ack_time_returned` / `ack_time_mac_returned` Required for Player-side TCP and custom plugin sources. Copy the latest values from that vehicle’s feedback. Webview sends these fields automatically. ## Webview task Use the webview path when the operator UI runs inside OdenVR / Player. The page receives `ocp_vehicle_user_data` and sends `ocp_client_user_data` through the injected JavaScript SDK. 1. Enable the `Oden Control Pipeline` global plugin. 2. Enable the `WebView` global plugin. 3. Point the WebView `Address` setting to your web app. 4. Create one shared `OdenLayoutClient` instance in the page. 5. Register a callback for `ocp_vehicle_user_data`. 6. Send `ocp_client_user_data` only when this webview is the intended OCP client data source. ```javascript const odenClient = getOrCreateOdenLayoutClient(); function onOcpFeedback(payload) { const entries = Object.entries(payload.vehicle_feedback ?? {}); if (entries.length === 0) return; const [vehicleName, feedback] = entries[0]; const vehicleData = feedback.vehicle_data?.user_data ?? {}; console.log("Vehicle data", vehicleName, vehicleData); odenClient?.sendNamedUserMessage("ocp_client_user_data", { active_vehicle: vehicleName, client_user_data: { [vehicleName]: { user_data: { selected_mode: "work", }, ocp_disable_gamepad: false, }, }, }); } odenClient?.registerUserMessageCallback("ocp_vehicle_user_data", onOcpFeedback); // Later, when the component or page is destroyed: // odenClient?.unregisterUserMessageCallback("ocp_vehicle_user_data", onOcpFeedback); ``` The WebView client tracks the latest `ack_time` and `ack_time_mac` per vehicle. When your code calls `sendNamedUserMessage("ocp_client_user_data", …​)`, the client injects `ack_time_returned` and `ack_time_mac_returned` into each matching vehicle entry. If no custom JavaScript sends `ocp_client_user_data`, the client can still auto-echo timestamps with an empty user-data payload. That keeps latency measurement alive for webview-only operator stations, but it also means the webview becomes the OCP client data source. ## Player-side TCP task Use Player-side TCP when an external application should run beside OdenVR / Player. OCP starts the Player-side TCP server during OCP initialization. Defaults: - Listen address: `127.0.0.1` - Port: `4001` - Port parameter: `ocp_player_tcp_port` - Remote bind parameter: `ocp_tcp_allow_remote` - Active clients: one at a time - Frame format: 4-byte unsigned little-endian payload length, then UTF-8 JSON - Maximum payload: 16 KB To change the port: ```shell oden-vr --plugin-param ocp_player_tcp_port 4101 ``` To allow non-local TCP clients, set `ocp_tcp_allow_remote`. This binds OCP TCP servers to `0.0.0.0` instead of `127.0.0.1`. Use this only on a protected network and open the firewall deliberately. ```shell oden-vr --plugin-param ocp_tcp_allow_remote 1 ``` A TCP client loop should: 1. Connect to `127.0.0.1:4001` unless the port was changed. 2. Read a 4-byte little-endian length. 3. Read that many JSON bytes and parse `VehicleOcpShared`. 4. Store the latest `ack_time` and `ack_time_mac` for each vehicle. 5. Send `ClientOcpShared` with a 4-byte length prefix. 6. Include the latest `ack_time_returned` and `ack_time_mac_returned`. 7. Reconnect if the socket closes. ```javascript // Pseudocode: frame every TCP JSON payload as: writeUInt32LE(Buffer.byteLength(json)); write(json); ``` This minimal Rust example shows the Player-side TCP framing and timestamp echo: ```rust use serde_json::{json, Value}; use std::{ error::Error, io::{Read, Write}, net::TcpStream, }; fn read_json(stream: &mut TcpStream) -> Result> { let mut len_buf = [0_u8; 4]; stream.read_exact(&mut len_buf)?; let len = u32::from_le_bytes(len_buf); if len > 16 * 1024 { return Err("OCP frame too large".into()); } let mut payload = vec![0_u8; len as usize]; stream.read_exact(&mut payload)?; Ok(serde_json::from_slice(&payload)?) } fn write_json(stream: &mut TcpStream, value: &Value) -> Result<(), Box> { let payload = serde_json::to_vec(value)?; stream.write_all(&(payload.len() as u32).to_le_bytes())?; stream.write_all(&payload)?; Ok(()) } fn main() -> Result<(), Box> { let mut stream = TcpStream::connect("127.0.0.1:4001")?; stream.set_nodelay(true)?; loop { let feedback = read_json(&mut stream)?; let (vehicle_name, vehicle) = feedback["vehicle_feedback"] .as_object() .and_then(|vehicles| vehicles.iter().next()) .ok_or("no vehicle feedback")?; let ack_time = vehicle["ack_time"].as_u64().unwrap_or(0); let ack_time_mac = vehicle["ack_time_mac"].as_u64().unwrap_or(0) as u32; let mut client_user_data = serde_json::Map::new(); client_user_data.insert( vehicle_name.clone(), json!({ "user_data": { "operator_app": "running" }, "ocp_disable_gamepad": false, "ack_time_returned": ack_time, "ack_time_mac_returned": ack_time_mac }), ); let response = json!({ "active_vehicle": vehicle_name, "client_user_data": client_user_data }); write_json(&mut stream, &response)?; } } ``` The example at `plugins/ocp_operator_example` contains a fuller Rust implementation. ## Custom plugin task Use a custom Oden plugin when the operator integration needs native Oden APIs or shared memory instead of TCP. OCP publishes feedback as named shared data: - `vehicle_ocp_size`: 32-bit little-endian byte count. - `vehicle_ocp`: CBOR-encoded `VehicleOcpShared`. The plugin sends client data back as: - `client_ocp_size`: 32-bit little-endian byte count. - `client_ocp`: CBOR-encoded `ClientOcpShared`. The same source-locking rule applies. If a plugin publishes `client_ocp`, do not also send `ocp_client_user_data` from a webview or Player-side TCP client in the same Player session. ## Vehicle selection OCP discovers vehicles on the Player side before it can route operator data. With Fleet active OCP uses Fleet’s vehicle-name-to-UUID mapping and supports multiple vehicles. Without Fleet OCP falls back to the scene and supports exactly one `Remote Streamer`. For multi-vehicle operation, send `active_vehicle` from the operator-side path. Use the exact vehicle name from `vehicle_feedback`. Only the active vehicle receives OCP gamepad input. ## Troubleshooting No `ocp_vehicle_user_data` in the webview Check that the OCP global plugin is enabled, the WebView page creates `OdenLayoutClient`, and the Player has discovered a vehicle. Without Fleet, the scene must contain exactly one `Remote Streamer`. Player-side TCP cannot connect Confirm OdenVR / Player is running with OCP enabled and listening on `127.0.0.1:4001` or the configured `ocp_player_tcp_port`. Only use a remote host if `ocp_tcp_allow_remote` is set. Only one TCP client is served at a time. OCP reports a client data source conflict Restart the Player and send OCP client data from only one source. Watch for a webview `OdenLayoutClient` auto-echoing timestamps while a TCP app or plugin is also sending data. Multiple vehicles are connected but none receives input Send `active_vehicle` and make sure it matches a `vehicle_feedback` key. Without Fleet, OCP does not support more than one `Remote Streamer`. `InputLost` appears while using custom controls Set `ocp_disable_gamepad: true` in the per-vehicle client data. Then make sure the vehicle-side integration reads your custom `user_data`; OCP will no longer send a gamepad `controller` object for that vehicle. Latency measurement stops or `Latency Loop Not Closed` / `InvalidMac` appears For TCP or plugin integrations, echo the latest `ack_time` and `ack_time_mac` unchanged as `ack_time_returned` and `ack_time_mac_returned`. For webviews, include a `client_user_data` entry for the same vehicle key so the SDK can inject the values. Also verify the vehicle-side integration returns the Streamer-side `ack_time` and `ack_time_mac`. Vehicle data is stale Check `ms_since_last_vehicle_data`. The operator side repeats the last vehicle data until the vehicle-side TCP integration sends new `vehicle_user_data`. TCP messages are ignored Keep payloads under 16 KB and send valid UTF-8 JSON after the 4-byte little-endian length prefix. Oversized messages are skipped and malformed JSON is logged as a parse warning. ## Related pages - [Oden Control Pipeline overview](ocp-overview.md) - [Webview and JavaScript SDK](webview-sdk.md) - [Vehicle-side control](vehicle-side-control.md) - [Latency measurement](latency-measurement.md) --- # Oden Control Pipeline overview Understand what Oden Control Pipeline does and how the vehicle-side and operator-side paths fit together. Last validated: 2026-05-04 Oden Control Pipeline (OCP) moves operator intent to a vehicle and brings vehicle state back to the operator station. It is the control-data companion to Oden’s video path: OdenVR reads or receives operator input, OCP routes it to the connected Oden Streamer, and the vehicle-side integration turns those commands into vehicle-specific control. OCP is useful when you want a teleoperation control path that already understands Oden vehicles, operator stations, feedback, faults, and latency measurement. It gives you a standard place to connect the vehicle controller, a standard place to connect operator-side UI or automation, and a shared fault model for deciding when the control signal should be considered unhealthy. OCP does not replace your vehicle safety controller. Treat OCP as the transport and observability layer for control messages; the vehicle integration should still enforce vehicle-specific limits, interlocks, emergency stop behavior, and actuator safety. ## What OCP does OCP runs as a global plugin in both Oden applications: OdenVR / Player The operator side discovers the connected vehicle, reads gamepad input by default, accepts optional operator-side user data, sends control messages, receives feedback, and publishes data to web views, plugins, or the player-side TCP API. Oden Streamer The vehicle side receives control messages from the operator, exposes them to the vehicle integration over TCP, collects vehicle responses, reports receiver faults, and embeds latency timestamps into the outgoing video stream. The default integration is intentionally small: - Connect vehicle-side code to the OCP TCP server on the Streamer. - Read framed JSON control messages containing optional controller input, telemetry, timestamp fields, and optional operator user data. - Send framed JSON responses containing the timestamp fields and optional vehicle user data. - Optionally connect operator-side software through a web view, a custom plugin, or the player-side TCP server. ## When to use OCP Use OCP when: - You are building a teleoperated vehicle or robot with Oden Streamer on the vehicle and OdenVR at the operator station. - The operator’s gamepad should be forwarded to the vehicle with health status and latency telemetry. - The vehicle needs to send custom state, position, or dashboard data back to the operator. - A web UI, Oden plugin, or external process needs to participate in the control path. - You need Oden-aware faults for lost input, lost feedback, missing cameras, unavailable vehicle integration, high latency, or slow Streamer frames. Use another path, or put a narrower bridge in front of OCP, when: - Your vehicle controller needs a different real-time bus or hard real-time guarantees. - The operator input is not part of Oden and you only need ordinary application messaging. - Your safety case requires an independent certified control channel. ## Data paths OCP has two main paths. Most deployments need the vehicle-side path; operator-side integration is added only when you need custom UI, custom input handling, automation, or external software at the operator station. ### Vehicle-side path The vehicle-side path connects Oden Streamer to the vehicle controller. ```none OdenVR input -> OCP operator sender -> Oden com channel -> OCP Streamer receiver -> vehicle-side TCP server -> vehicle integration / ECU bridge -> vehicle controller ``` By default, the Streamer-side TCP server listens on `127.0.0.1:4000`. Set `ocp_tcp_allow_remote` only when the TCP client must connect from another host. Each TCP message is length-prefixed with a 4-byte little-endian size followed by UTF-8 JSON; messages larger than 16 KB are dropped. The Streamer sends an `OcpControlMessage` to the TCP client. It includes: - `controller`: gamepad/controller state, or `null` when gamepad forwarding is disabled or unavailable. - `telemetry`: current latency, fault boolean, and fault reason string. - `ack_time` and `ack_time_mac`: timestamp values that must be returned unmodified. - `client_user_data`: optional operator-side user data. The vehicle integration responds with `VehicleResponseMessage`. It must copy `ack_time` and `ack_time_mac` back to OCP and may include `vehicle_user_data`. Vehicle user data is carried back to the operator side and can contain position plus any JSON payload your dashboard or application understands. When OCP sees an active fault on the control path, it sends default controller values to the vehicle-side TCP client. Your vehicle integration should map that default command and the telemetry fault state to the vehicle’s safe behavior. ### Operator-side path The operator-side path is optional. Use it when the operator station needs to display vehicle data, send custom data to the vehicle, choose the active vehicle, or replace OCP’s default gamepad handling. ```none Vehicle feedback -> OCP operator sender -> web view / plugin shared data / player-side TCP -> operator UI or external application -> optional client user data -> OCP operator sender -> vehicle-side path ``` OCP supports three operator-side integration points: Web view Receives `ocp_vehicle_user_data` and sends `ocp_client_user_data` with the Oden JavaScript SDK. Timestamp handling is automatic for web views. Custom Oden plugin Reads `vehicle_ocp` shared data and publishes `client_ocp` shared data. Player-side TCP Exposes a local TCP server on `127.0.0.1:4001` by default. It uses the same 4-byte length prefix and JSON payload style as the vehicle-side TCP server. Only one operator-side client data source may be active in a session. The first source to send client data becomes the locked source. If another source sends data after that, OCP stops all client data communication and requires a restart. This keeps timestamp echo and control-user-data ownership unambiguous. ## Vehicle discovery and active control On the operator side, OCP needs to know which remote Streamer represents each vehicle. With the Fleet plugin active, OCP uses the fleet vehicle-name-to-UUID mapping and supports multiple vehicles. Without Fleet, OCP falls back to the scene and only supports exactly one `Remote Streamer`. For multiple vehicles, operator-side data should set `active_vehicle`. Only the active vehicle receives gamepad input. If no active vehicle is selected while multiple vehicles are connected, OCP marks vehicle control inactive for the non-selected paths. ## Fault model OCP faults are health signals for the control pipeline. They are self-recovering: when the underlying condition clears, the fault clears. Operator-side faults include: - `InputLost`: no expected gamepad input is available. - `NoFeedbackMessage`: the operator has not received feedback from the Streamer for more than 1000 ms. - `VehicleControlInactive`: this vehicle is not currently selected for control. Vehicle-side faults include: - `VehicleNoResponse`: no TCP client is connected to the vehicle-side OCP server. - `NoControlMessage`: control messages from the operator are missing for more than 1000 ms. - `CameraLost`: a monitored camera has not produced a valid frame within the drop-detector timeout. The default is 200 ms, and cameras with drop detection disabled are ignored. - `StreamerSlow`: the Streamer frame loop exceeded the slow-frame threshold, currently 500 ms. - `HighLatency`: measured round-trip latency is above `latency_limit`. - `OperatorStationHasError`: the operator side has reported a sender fault. - `InvalidMac`: latency timestamp validation failed. - `ControlThreadChannelSlow`: OCP’s internal control queue is not being serviced quickly enough. The important design point is that faults flow with the control message. The operator can see vehicle-side faults, the vehicle side can see operator-side faults, and the vehicle integration receives a telemetry fault flag and reason string. ## Settings to know first The Oden Control Pipeline plugin exposes the same practical settings on Streamer and Player. Most deployments can keep the defaults. | Setting | Default | Use | | --- | --- | --- | | `tcp_port` | `4000` | Vehicle-side TCP server port on the Streamer. | | `ocp_player_tcp_port` | `4001` | Operator-side TCP server port on OdenVR / Player when an external operator-side TCP process is used. | | `ocp_tcp_allow_remote` | unset | Binds OCP TCP servers to `0.0.0.0` instead of `127.0.0.1`. Use only when another machine must connect directly to the TCP server and the network is trusted. | | `latency_limit` | `500` | Streamer-side threshold in milliseconds for the `HighLatency` fault. Increase it only when the measured end-to-end control path is still acceptable for the vehicle. | ## Latency concepts OCP tracks two related values: Ping latency A lightweight Oden com-channel ping from operator to vehicle and back. This is useful for network health. Message round-trip latency The safety-relevant OCP timestamp loop. The vehicle side creates an `ack_time` and `ack_time_mac`, the vehicle integration returns them to OCP, OCP embeds them into outgoing video metadata, the operator side extracts and echoes them back in the next control message, and the vehicle side validates the returned value before measuring elapsed time. The default `latency_limit` is 500 ms. When the measured message round trip exceeds that limit, OCP raises `HighLatency`. If the timestamp or MAC is not passed through unmodified, latency measurement fails and OCP raises `InvalidMac` / "Latency Loop Not Closed" behavior. Because the timestamp loop follows the real control and video path, it includes more than network transit time. It can include vehicle integration processing, video transport, operator-side handling, and the return control message. ## Where to go next - [Vehicle-side control](vehicle-side-control.md) - implement the TCP client that talks to OCP on the Streamer. - [Operator-side control](operator-side-control.md) - add web-view, plugin, or external application data exchange at the operator station. - [Latency measurement](latency-measurement.md) - understand timestamp echo, `ocp_disable_gamepad`, and source locking. --- # Webview and JavaScript SDK Build custom Oden operator interfaces with the webview plugin and JavaScript SDK. Last validated: 2026-05-04 Oden’s WebView plugin lets you render a browser-based operator interface inside OdenVR / Player. The page can place Oden video streams into DOM-defined regions, exchange JSON messages with Oden plugins, and participate in Fleet and OCP operator workflows. Use the webview path when the operator UI is naturally a web app: dashboards, multi-camera layouts, fleet selectors, maps, mission controls, or application-specific controls. The web page does not render Oden video pixels itself. Instead, it tells Oden where video should appear, and Oden draws the video over the browser surface. ## How it fits together ```none Web app in Oden WebView -> injected OdenLayoutClient -> local WebSocket layout server -> WebView plugin -> Oden video layout, Fleet, OCP, or custom plugins ``` The WebView plugin injects a global JavaScript class named `OdenLayoutClient` into each page. The client opens a WebSocket to a localhost port chosen by Oden and uses the `oden_layout` WebSocket subprotocol. Applications should create one shared instance and reuse it for the lifetime of the page. The injected script also exposes `window.oden_version`. ## Enable the webview 1. Enable the `WebView` global plugin in OdenVR / Player. 2. Open the WebView plugin panel. 3. Set `Address` to your web app, for example `[http://localhost:3000](http://localhost:3000)`. 4. Enable `Accept Input` when the page should receive mouse and keyboard input. 5. Use `Fill View` when the web UI should cover the whole viewport. The most important WebView settings are: `Address` The URL loaded by the embedded browser. `Width` / `Height` The browser render size when `Fill View` is disabled. `Accept Input` Forwards mouse and keyboard input to the page. `Inhibit Mouse Look` Prevents Oden’s 3D mouse-look behavior while interacting with the page. `Fill View` Uses the current viewport size as the browser size. `Ignore Url Updates` Keeps the currently rendered page instead of reloading when the configured URL value changes. Use this when an operator web app manages its own route state and should not be reset by project-side URL updates. `Mute log` Stops browser console logs from being forwarded into the Oden log. `Clear Session Cookies` Clears browser session cookies at startup. ## Create the client Guard the client creation so the app can still render during server-side rendering, tests, or ordinary browser development. ```typescript declare global { interface Window { OdenLayoutClient?: new () => any; odenLayoutClient?: any; oden_version?: string; } } export function getOrCreateOdenLayoutClient() { if (typeof window === "undefined" || !window.OdenLayoutClient) { return null; } if (!window.odenLayoutClient) { window.odenLayoutClient = new window.OdenLayoutClient(); } return window.odenLayoutClient; } ``` The client queues a small number of outgoing layout and user messages until its WebSocket opens. Still, your app should treat the client as a singleton. Creating multiple instances creates multiple WebSocket connections and duplicate callbacks. ## JavaScript API `registerVideo(name, element)` Registers a DOM element as the placement rectangle for an Oden video stream. The client tracks `getBoundingClientRect()` and sends updates when the element moves, resizes, or when video attributes change. `unregisterVideo(name)` Removes a video registration. Call this when a component unmounts or a route changes. `sendPositionUpdate()` Sends the current placement for all registered video elements. This is normally called automatically. `registerCallback(callback)` Registers a callback for available-video updates. The callback receives an object keyed by video name, for example `{ "Front": { width: 1920, height: 1080 } }`. `unregisterCallback(callback)` Removes an available-video callback. `registerUserMessageCallback(name, callback)` Registers a callback for named user messages from Oden. The callback receives the message `payload`. `unregisterUserMessageCallback(name, callback)` Removes a named user-message callback. `sendNamedUserMessage(name, payload)` Sends a named JSON message to Oden. Use this for plugin messages, Fleet messages, and OCP messages. `sendMessage(layout)` / `sendBoxData(layout)` Sends a raw video layout message. Use this only when you need manual video placement. `close()` Closes the WebSocket, disconnects observers, and stops the position update loop. ## Video layout The recommended path is to create transparent DOM elements where video should appear, then register those elements with `registerVideo()`. Oden draws the corresponding stream into each rectangle. ```javascript import { useEffect, useRef } from "react"; import { getOrCreateOdenLayoutClient } from "./oden"; export function OdenVideo({ name, scaleX = "1.0", scaleY = "1.0", rotation = "0.0", cropLeft = "0.0", cropRight = "0.0", cropTop = "0.0", cropBottom = "0.0", z = "-1", }) { const ref = useRef(null); useEffect(() => { const client = getOrCreateOdenLayoutClient(); if (!client || !ref.current) return; client.registerVideo(name, ref.current); return () => { client.unregisterVideo(name); }; }, [name]); return (
); } ``` A stream name is usually the camera or video entity name, such as `Front`. When Fleet or another multi-streamer setup is active, names can include a vehicle prefix, such as `vehicle-12:Front`. Listen for available videos instead of hard-coding names whenever possible: ```javascript const client = getOrCreateOdenLayoutClient(); function onVideos(videos) { // { "Front": { width: 1920, height: 1080 }, ... } console.log("Available Oden videos", videos); } client?.registerCallback(onVideos); // Later: client?.unregisterCallback(onVideos); ``` ### Layout attributes The automatic layout client reads these attributes from the registered DOM element: `scale-x`, `scale-y` Scale multipliers for the video placement. Use `scale-x="-1.0"` to mirror a rear camera. `rotation` Rotation in degrees. `crop-left`, `crop-right`, `crop-top`, `crop-bottom` Normalized crop values from `0.0` to `1.0`. `z` View-space z order used by Oden’s immediate drawing path. `data-camera-id` Optional camera name override. Use this if the DOM registration key must be unique but the video stream name should be shared. ### Manual placement Manual placement sends the raw layout shape expected by the WebView layout server. Do not wrap video placement in `sendNamedUserMessage()`. ```javascript const client = getOrCreateOdenLayoutClient(); client?.sendMessage({ videos: [ { name: "Front", position: { x: 100, y: 80 }, size: { width: 1280, height: 720 }, scale: { x: 1.0, y: 1.0 }, rotation: 0.0, crop: { left: 0.0, right: 0.0, top: 0.0, bottom: 0.0 }, z: 1, }, ], }); ``` Coordinates and sizes are browser CSS pixels in the web page coordinate system. Oden applies the current webview scale internally. ## Named user messages Named user messages are JSON messages with this shape: ```json { "name": "vehicle_state", "payload": { "speed": 4.2, "battery": 0.81 } } ``` Use named messages for application data. Use raw layout messages for video placement. ### JavaScript to Oden ```javascript const client = getOrCreateOdenLayoutClient(); client?.sendNamedUserMessage("drive_commands", { throttle: 0.15, brake: 0.0, steering: -0.2, }); ``` ### Oden to JavaScript ```javascript const client = getOrCreateOdenLayoutClient(); function onVehicleState(payload) { console.log("Vehicle state", payload); } client?.registerUserMessageCallback("vehicle_state", onVehicleState); // Later: client?.unregisterUserMessageCallback("vehicle_state", onVehicleState); ``` ### Plugin side Rust plugins send messages to webviews through the named MPMC channel `user_message_oden_to_webview`. Current inbound webview messages are received with `webview_shared::create_receiver()` and a set of wanted message names. ```rust use std::collections::HashSet; use oden_plugin_rs::{ named_mpmc_channel::{NamedMpmcChannelExt, Sender}, webview_user_message::WebviewUserMessage, InitParams, OdenPlugin, UpdateParams, }; use serde_json::json; struct State { to_webview: Sender, from_webview: webview_shared::Receiver, } impl OdenPlugin for State { fn init(api: &InitParams) -> Self { let wanted_messages = HashSet::from(["drive_commands".to_string()]); Self { to_webview: api.named_mpmc_channel_tx("user_message_oden_to_webview", 128), from_webview: webview_shared::create_receiver(api, wanted_messages), } } fn update(&mut self, _api: &UpdateParams) { self.to_webview .try_send(WebviewUserMessage { name: "vehicle_state".to_string(), payload: Some(json!({ "speed": 4.2, "battery": 0.81 })), }) .ok(); while let Ok(message) = self.from_webview.try_recv() { if message.name == "drive_commands" { // Deserialize message.payload into your command type. } } } } ``` `webview_shared::create_receiver()` filters by message name. If a message name is not in `wanted_messages`, that plugin instance will not receive it. ## Fleet messages When the Fleet plugin is active, webviews can discover and connect vehicles with named user messages. These are the message names used by the current Fleet player plugin. | Direction | Name | Payload | | --- | --- | --- | | Webview to Oden | `fleet_list_vehicles` | `{}` | | Oden to webview | `fleet_online_vehicles` | Array of `{ id, name, availability }`, where `availability` is `Available`, `Monitored`, or `Controlled`. | | Webview to Oden | `fleet_connect` | `{ "vehicle_name": "vehicle-12" }` | | Webview to Oden | `fleet_disconnect` | `{ "vehicle_name": "vehicle-12" }` | | Webview to Oden | `configure_player` | Optional player configuration such as `packer_enabled`, `packer_auto_crop`, `background_color`, or `hide_connection_ui`. | Example: ```javascript const client = getOrCreateOdenLayoutClient(); function onVehicles(vehicles) { // [{ id, name, availability }, ...] console.log(vehicles); } client?.registerUserMessageCallback("fleet_online_vehicles", onVehicles); client?.sendNamedUserMessage("fleet_list_vehicles", {}); client?.sendNamedUserMessage("fleet_connect", { vehicle_name: "vehicle-12", }); ``` ## OCP operator messages OCP publishes vehicle feedback to the webview and accepts optional operator-side user data back from the page. See [Oden Control Pipeline overview](ocp-overview.md) for the full control-path model. | Direction | Name | Payload | | --- | --- | --- | | Oden to webview | `ocp_vehicle_user_data` | `VehicleOcpShared`: `{ vehicle_feedback, last_input }`. | | Webview to Oden | `ocp_client_user_data` | `ClientOcpShared`: `{ active_vehicle, client_user_data }`. | `vehicle_feedback` is keyed by vehicle name. Each value includes OCP latency fields, sender and receiver faults, optional vehicle data, the last remote input, and timestamp fields used by the OCP latency loop. When JavaScript sends `ocp_client_user_data`, the injected client automatically echoes the latest `ack_time` and `ack_time_mac` for each vehicle entry it has seen. Your web app normally only supplies `active_vehicle`, `user_data`, and optionally `ocp_disable_gamepad`. ```javascript const client = getOrCreateOdenLayoutClient(); function onOcpData(payload) { const entries = Object.entries(payload.vehicle_feedback ?? {}); if (entries.length === 0) return; const [vehicleName] = entries[0]; client?.sendNamedUserMessage("ocp_client_user_data", { active_vehicle: vehicleName, client_user_data: { [vehicleName]: { user_data: { selected_tool: "bucket", requested_mode: "work", }, ocp_disable_gamepad: false, }, }, }); } client?.registerUserMessageCallback("ocp_vehicle_user_data", onOcpData); ``` Only one operator-side client data source should send OCP client data in a session. Do not send `ocp_client_user_data` from both a webview and another operator-side TCP or plugin client at the same time. ## Message names reference | Name | Direction from web page | Use | | --- | --- | --- | | `fleet_list_vehicles` | Send | Request the current Fleet vehicle list. | | `fleet_online_vehicles` | Receive | Receive Fleet vehicle availability. | | `fleet_connect` | Send | Request control connection by vehicle name. | | `fleet_disconnect` | Send | Disconnect a Fleet vehicle by vehicle name. | | `configure_player` | Send | Apply selected player-side configuration. | | `ocp_vehicle_user_data` | Receive | Receive OCP vehicle feedback and input state. | | `ocp_client_user_data` | Send | Send operator-side user data and active vehicle selection to OCP. | | `connect` | Send | Low-level connection request with `{ "roverId": "…​" }`. Fleet integrations should prefer `fleet_connect`. | | `disconnect` | Send | Low-level disconnect request with `{ "roverId": "…​" }`. Fleet integrations should prefer `fleet_disconnect`. | Custom plugins can define any additional message names. Use stable, namespaced names such as `vehicle_state`, `drive_commands`, or `my_plugin:set_mode`. ## Troubleshooting No `OdenLayoutClient` The page is not running inside Oden’s WebView, or the injected script did not load. Keep the singleton helper nullable so local browser development still works. No video appears Check `Layout Server > Available videos` in the WebView plugin panel, or use `registerCallback()` to log available names. Make sure the registered element has non-zero size and the name matches the stream name Oden reports. Video is behind the web UI Adjust the element’s `z` attribute. For overlays and picture-in-picture views, use an explicit positive `z`. Plugin does not receive webview messages Make sure the plugin registered the message name in `webview_shared::create_receiver(api, wanted_messages)`. OCP client data stops working Only one OCP client data source can own operator-side user data in a session. Restart Oden after a source conflict, then send from only one of webview, plugin shared data, or player-side TCP. ## More examples - [Player layout](../configure/player-layout.md) - [Fleet management](../operate/fleet-management.md) - [Multiple vehicles](../operate/multiple-vehicles.md) - [Operator-side control](operator-side-control.md) --- # Plugin API Build native Oden extensions for entities, capture, controls, messaging, and integrations. Last validated: 2026-05-05 Use plugins when an integration needs to run inside Oden instead of beside it. Plugins can add custom entities, global background logic, capture sources, controls, and messaging. ## Start here - [Load and configure plugins](../configure/plugins.md) - project plugin paths, global plugins, startup parameters, and troubleshooting. - [Plugin Distribution](plugin-distribution.md) - package plugins with projects and deployments. - [C/C++/Rust](plugin-languages.md) - choose an SDK language path. - [Plugin Messaging](plugin-messaging.md) - use Com Channels and webview messages. ## When to use a plugin Use a plugin when you need: - Native Oden update-loop behavior. - Custom entities or GUI controls. - Direct plugin-to-plugin shared data. - Custom video capture. - A control or telemetry integration that cannot be cleanly handled by OCP TCP or webview messages. Do not put safety-critical vehicle limits only in a plugin. Vehicle-side safety controllers should enforce their own limits and command timeouts. --- # Plugin Distribution Package and deploy Oden plugins with projects, applications, and production systems. Last validated: 2026-05-05 Plugins are dynamic libraries loaded by Oden. They normally end in `.dll` on Windows and `.so` on Linux. ## Project plugins Use project plugins when the plugin belongs to one `.vproj`. 1. Put the plugin and runtime dependencies in a folder beside the project, for example `bin`. 2. Set the project plugin path. 3. Save and reopen the project. 4. Add the plugin entity or configure the plugin-provided settings. Relative plugin paths are useful when the project and plugin folder move together. ## Global plugins Use global plugins when the plugin should run without being added to the scene graph. Global plugins must be installed where the Player or Streamer scans application-level plugins. Restart Oden after changing global plugin paths or replacing global plugin binaries. ## Deployment checks Before shipping a plugin deployment: - Match operating system, CPU architecture, and Oden build. - Include all runtime dependencies. - Check Windows dependencies with Dependencies GUI. - Check Linux dependencies with `ldd -r -d ./plugin.so`. - Keep plugin versions aligned with the Oden version deployed to the vehicle and operator. - Disable hot reload in production. See [Plugins](../configure/plugins.md) for detailed loading and troubleshooting. --- # C/C++/Rust Choose a language path for Oden plugin development. Last validated: 2026-05-05 Oden plugins can be built from native code. The current recommended documentation path should be Rust-first, with C/C++ available for integrations that need it. ## Rust Prefer Rust for new plugins when possible. Rust gives better type safety for Oden data structures and is a good fit for vehicle/control integrations that already use Rust. Voysys should publish the Rust plugin API docs from the Oden repository and link them here. ## C and C++ Use C or C++ when: - Existing customer code is already in C/C++. - The integration depends on a vendor SDK that is C/C++ only. - The plugin must share ABI-level structures with another native component. Keep C/C++ plugin boundaries small and test dependency loading on the exact deployment image. ## What to publish The public Plugin API section should eventually include: - Rust crate API documentation. - Minimal plugin template. - Global plugin example. - Custom entity example. - Plugin video capture example. - OCP/shared-data example. - Packaging and versioning guidance. --- # Plugin Messaging Use Oden Com Channels for custom plugin messages between Player and Streamer. Last validated: 2026-05-05 Use this page when a custom Oden plugin needs to exchange user-defined messages between the Player and Streamer. For the standard vehicle-control path, start with [Oden Control Pipeline overview](ocp-overview.md). Use Com Channels when you need plugin-level messages that are outside the Oden Control Pipeline contract. ## Com Channels Com Channels is Oden’s built-in communication channel for plugin-defined messages. Messages can be sent between Player and Streamer over the configured Oden links. The transport is UDP, so the same practical constraints apply: packets can be delayed, reordered, duplicated, or lost. Messages can be processed in two ways: Synchronous Delivered in the application frame loop. Use this when message handling must line up with Oden update timing. Asynchronous Delivered through listener queues serviced by separate threads. Use this when plugin work should not wait for the main frame loop. Com Channels are used through the Voysys Plugin SDK. Contact Voysys for SDK access when building native plugins. ## Inspect Links and Queues Use the `Com Channels` sidebar tab while testing a plugin integration. Link Shows transmit and receive statistics, send rate, last received message, and other per-link counters. Use it to prove that messages are moving over the same links as the Oden session. Message Queues Shows message types currently being sent or received. The sender side can show message names; the receiver side shows message identifiers. Use it to spot duplicate message types, missing senders, or a queue that is no longer being drained. ## Advanced Settings Most projects should keep defaults. Tune these only after a measured problem is visible in the queue or link stats. Max Packet Size Maximum UDP packet payload used for Com Channel messages. Queue Size Maximum queued messages per listener. The synchronous listener queue is cleared each frame; each asynchronous listener has its own queue and thread. Limit Send Rate Limits how often an asynchronous send queue is flushed. Async Send Rate Flush cadence used when send-rate limiting is enabled. Max Invalid Packets In A Row Number of timestamp-invalid packets that must arrive before Oden accepts the new timestamp sequence. This helps after one Player disconnects and another Player on a different computer connects to the same Streamer. If a plugin only uses synchronous messages and the frame rate is low, a smaller send-rate limit can make messages feel more responsive. Validate this with the real plugin and network path before deploying. ## Design Notes Keep Com Channel messages small and versioned. Include enough message identity for the receiver to ignore unknown or incompatible messages. Do not put safety-critical vehicle limits only in a Com Channel plugin; the vehicle-side safety controller must still enforce its own limits. For operator UI data in a webview, use [Webview and JavaScript SDK](webview-sdk.md). For vehicle control and telemetry over TCP/JSON, use [Vehicle-Side Control](vehicle-side-control.md) and [Operator-Side Control](operator-side-control.md). --- # Supervise Many Vehicles Keep Oden vehicles, operators, sessions, and diagnostics understandable as a deployment grows. Last validated: 2026-05-05 Use this section when the first vehicle stream works and the next problem is operational: more vehicles, more operators, more links, and more evidence when something behaves badly. Many-vehicle supervision is usually delivered as a managed enterprise setup. The public self-serve flow is intentionally optimized for getting one vehicle and one operator running quickly. If you are building dispatch, monitoring, authorization, or custom operator handoff for a fleet, talk to Voysys early so the portal model, licenses, and Oden project structure fit the deployment. ## Supervision tasks - [Multiple vehicles](multiple-vehicles.md) explains how Oden represents several connected vehicles and how a web operator UI selects the active control target. - [Fleet management](fleet-management.md) covers the Bifrost/Fleet Client flow that connects vehicles and operators by name. - [Performance monitoring](performance-monitoring.md) points to the portal and in-application places to check online state, active sessions, and runtime health. - [Diagnostics and recording](diagnostics-and-recording.md) covers the evidence to collect during acceptance testing and support cases. - [Troubleshooting](troubleshooting.md) gives first-response checks for connection, video, audio, control, and service issues. ## Network configuration Network setup deserves its own pass once the basic stream is stable. Oden can use multiple links so a vehicle can combine cellular, satellite, Wi-Fi, and local network paths when they are available. Start with [Network Configuration](network-configuration.md), then use [Network](../configure/network.md) for the lower-level link fields in Oden. --- # Multiple Vehicles Connect one operator interface to multiple vehicles. Last validated: 2026-05-04 Use a multiple-vehicle setup when one operator station should keep several vehicles connected at the same time, for example to monitor a fleet and switch which vehicle receives control input. Each vehicle is connected through Fleet Client by name. Video layout and OCP control selection are handled from the operator-side web view. Multiple-vehicle operation is a gated enterprise feature in the managed portal. This page describes the technical model so the shape is clear, but production fleet supervision usually needs Voysys involvement for portal provisioning, operator permissions, dispatch behavior, and custom UI decisions. For the single-vehicle connection flow, see [Connect Player and Streamer](../start/connect-player-and-streamer.md). For the lower-level webview API reference, see [Webview and JavaScript SDK](../integrate/webview-sdk.md). ## Before you start Make sure the basic fleet flow works for one vehicle before adding more. - Each vehicle runs Oden Fleet Streamer or an Oden Streamer setup with Fleet Client configured. - The Player has the **Fleet Client** plugin enabled. - The Player has the **Webview** plugin enabled when the operator interface controls connections or video layout. - Enable **Oden Control Pipeline** when the operator station must receive vehicle feedback or send control/user data. - Use fleet connections that create Remote Streamer entities in the current Player project. Do not use project-based vehicle connections that download and open a different Player project when a vehicle connects. - Give every vehicle a stable, unique fleet name. The webview connection messages use the vehicle `name`, not the vehicle `id`. ## List online vehicles Request the fleet list before showing connect buttons in the operator UI. The response contains the fleet `id`, the `name` to use in connection messages, and the current `availability`. ```javascript const odenClient = getOrCreateOdenLayoutClient(); function updateVehicleList(vehicles) { for (const vehicle of vehicles) { console.log(vehicle.name, vehicle.availability); } } odenClient.registerUserMessageCallback("fleet_online_vehicles", updateVehicleList); odenClient.sendNamedUserMessage("fleet_list_vehicles", {}); ``` Fleet availability values are: | Availability | Meaning | | --- | --- | | `Available` | The vehicle is online and has no active fleet control or monitor session. | | `Monitored` | The vehicle has an active monitor session, but no active control session. | | `Controlled` | The vehicle already has an active control session. A second control connection is rejected by fleet management. | ## Connect several vehicles Send one `fleet_connect` message for each vehicle that should be connected. Use the `name` value from `fleet_online_vehicles`. ```javascript const selectedVehicles = ["vehicle_a", "vehicle_b", "vehicle_c"]; for (const vehicleName of selectedVehicles) { odenClient.sendNamedUserMessage("fleet_connect", { vehicle_name: vehicleName, }); } ``` When the connections are accepted, Fleet Client creates or updates one Remote Streamer per connected vehicle and publishes the vehicle-name-to-Remote-Streamer mapping used by Webview and OCP. ## Lay out video for each vehicle When several connected vehicles expose streams with the same camera names, address a stream as: ```text vehicle_name:stream_name ``` For example, if two vehicles both expose a `Front` stream, register `vehicle_a:Front` and `vehicle_b:Front` separately. The webview layout server maps the vehicle-name prefix to the correct Remote Streamer. ```html
``` ```javascript odenClient.registerVideo( "vehicle-a-front", document.getElementById("vehicle-a-front") ); odenClient.registerVideo( "vehicle-b-front", document.getElementById("vehicle-b-front") ); ``` You can also listen for video information and build the layout from the names Oden reports. ```javascript odenClient.registerCallback((videos) => { // Example keys after multi-vehicle layout is active: // "vehicle_a:Front", "vehicle_b:Front" console.log("Videos available for layout:", videos); }); ``` See [Player Layout](../configure/player-layout.md) and [Webview and JavaScript SDK](../integrate/webview-sdk.md) for the full layout API. ## Select the active vehicle OCP can send gamepad input to only one vehicle at a time. Set `active_vehicle` in `ocp_client_user_data` to choose which connected vehicle receives gamepad input. Changing `active_vehicle` switches control without disconnecting from the other vehicles. ```javascript function selectActiveVehicle(vehicleName) { odenClient.sendNamedUserMessage("ocp_client_user_data", { active_vehicle: vehicleName, client_user_data: { [vehicleName]: { user_data: {}, ocp_disable_gamepad: false, }, }, }); } selectActiveVehicle("vehicle_a"); ``` For a multi-vehicle session, always set `active_vehicle`. If it is omitted while more than one vehicle is connected, OCP marks every connected vehicle as inactive for control and raises `VehicleControlInactive`. Vehicles that are connected but not active also report `VehicleControlInactive`, which is expected. If your web UI or another operator-side system sends its own control data instead of using OCP gamepad input, set `ocp_disable_gamepad: true` for that vehicle’s `client_user_data`. Only one operator-side client data source should send OCP client data during a session. Do not mix webview, plugin, and player-side TCP control data in the same session. ## Show feedback for every vehicle OCP publishes feedback for all connected vehicles in `ocp_vehicle_user_data`. The `vehicle_feedback` object is keyed by vehicle name. ```javascript odenClient.registerUserMessageCallback("ocp_vehicle_user_data", (data) => { for (const [vehicleName, feedback] of Object.entries(data.vehicle_feedback)) { console.log(vehicleName, { ping: feedback.ping_latency_ms, roundtrip: feedback.message_latency_roundtrip, senderFaults: feedback.sender_fault, receiverFaults: feedback.receiver_fault, vehicleData: feedback.vehicle_data, }); } }); ``` Common fields to show in a multi-vehicle operator UI: | Field | Use | | --- | --- | | `ping_latency_ms` | Network ping latency between operator and vehicle. | | `message_latency_roundtrip` | OCP message round-trip latency through the control/video feedback path. | | `ms_since_last_vehicle_data` | How old the last `vehicle_data` payload is. | | `sender_fault` | Operator-side faults such as `InputLost`, `NoFeedbackMessage`, or `VehicleControlInactive`. | | `receiver_fault` | Vehicle-side faults such as `VehicleNoResponse`, `NoControlMessage`, `CameraLost`, `StreamerSlow`, `HighLatency`, `OperatorStationHasError`, `InvalidMac`, or `ControlThreadChannelSlow`. | | `vehicle_data` | Vehicle-side position and user data supplied by the vehicle integration. | ## Disconnect a vehicle Disconnect vehicles individually when the operator no longer needs their video or feedback. ```javascript odenClient.sendNamedUserMessage("fleet_disconnect", { vehicle_name: "vehicle_b", }); ``` If the disconnected vehicle was the active vehicle, send a new `ocp_client_user_data` message with another `active_vehicle`. ## Troubleshooting Vehicle does not appear in `fleet_online_vehicles` Confirm that the vehicle is online in Bifrost, the Fleet Client plugin is enabled, and both the vehicle and Player are activated and able to reach the fleet service. Connect request does not attach the expected vehicle Check that the UI sends `vehicle_name` with the fleet `name` field. Do not send the fleet `id`. If the vehicle is `Controlled`, another operator already has a control session. Only one vehicle shows video, or a camera name appears to collide Use the `vehicle_name:stream_name` form for video layout entries. Without the vehicle prefix, the layout server falls back to the first Remote Streamer that matches the stream name. No vehicle receives gamepad input In a multi-vehicle session, send `ocp_client_user_data` with `active_vehicle` set to one connected vehicle name. Check `sender_fault` for `VehicleControlInactive` and `InputLost`. The active vehicle changes but control data stops Check that only one operator-side OCP client data source is active. If webview, plugin, and player-side TCP sources send client data in the same session, OCP stops client data communication and requires a restart. Latency or feedback values look stale Check `ms_since_last_vehicle_data`, `NoFeedbackMessage`, `VehicleNoResponse`, and `HighLatency`. For custom vehicle integrations, make sure `ack_time` and `ack_time_mac` are returned unmodified in the vehicle response path. --- # Fleet Management Connect Oden Streamer and OdenVR through Bifrost fleet management. Last validated: 2026-05-04 Bifrost is Voysys' cloud fleet management system for Oden. It tracks which vehicles are online, lets an operator select a vehicle by name, starts and stops fleet sessions, and provides relay infrastructure for the initial secure network path. After a session is active, Oden tries to use a direct peer-to-peer path when the network allows it. Bifrost does not replace the Streamer or Player. Oden Fleet Streamer runs on the vehicle, OdenVR or Oden Dome Player runs on the operator station, and the **Fleet Client** plugin on both sides coordinates the session through Bifrost. In this page, **Player** means OdenVR or Oden Dome Player. ## Prerequisites Before you connect through Bifrost, make sure the system has: - Oden Fleet Streamer installed on the vehicle computer. It includes the Fleet Client and Oden Control Pipeline plugins used by the fleet flow. - OdenVR or Oden Dome Player installed on the operator computer. - Activated licenses on both sides. For a headless Fleet Streamer service, activate with the command used by the service and restart it afterward. - Network access from both computers to Bifrost. The Fleet Client authenticates with Bifrost and keeps the server connection alive with heartbeats. - A Streamer project with a working video source. For a first check, use a test source before switching to real cameras. - The **Fleet Client** plugin enabled on the Player. Enable **Oden Control Pipeline** when the operator will control the vehicle. Enable **Webview** when the operator interface is a web UI. If Oden Fleet Streamer was installed as a systemd service, manage it with: ```shell sudo systemctl start oden-streamer.service sudo systemctl status oden-streamer.service sudo systemctl restart oden-streamer.service ``` The service uses `/opt/oden-streamer/oden-vehicle-config.vproj` as its startup project. ## Connect a Fleet Streamer and Player 1. Start Oden Fleet Streamer on the vehicle. When the Fleet Client authenticates as a vehicle, Bifrost can list the vehicle as online. On newer Bifrost protocol versions, the Streamer requests its assigned Streamer project from the server after authentication. If no server project is available, the Streamer falls back to its local/default project. 2. Start the Player on the operator station. Open the plugin list and enable **Fleet Client**. If this is a control setup, also enable **Oden Control Pipeline**. For a web-based operator interface, enable **Webview**. 3. Open the Player connection UI. The Fleet Client authenticates as an operator and requests the current vehicle list from Bifrost. Each vehicle is shown by name with an availability status. 4. Select the vehicle and connect. For a control session, the Player sends a control request for the vehicle name. Bifrost creates the session, selects relay information, and the two Fleet Clients exchange the link keys needed to configure the Player and Streamer network links. When the session is accepted, the Player either loads the project assigned to the vehicle or creates a Remote Streamer entity for the session. The Streamer configures its matching links, starts streaming, and enables audio sending for the session. 5. Verify video and link health. Open the Remote Streamer entity on the Player to check traffic, packet loss, round-trip time, and video state. If the link starts through a relay, Oden may switch to peer-to-peer automatically when a direct path becomes available. 6. Disconnect when finished. Use the disconnect button in the Player connection UI. The Fleet Client sends a disconnect request for the active session and removes the fleet-created links. For a general first-stream workflow, see [Oden Quickstart](../start/quickstart.md). For a comparison with direct network links, see [Connect Player and Streamer](../start/connect-player-and-streamer.md). ## Webview Fleet Messages A webview can manage the same fleet flow by sending named user messages through the Oden Webview SDK. Create a single `OdenLayoutClient` instance, register callbacks for incoming messages, and use the vehicle `name` when connecting. Do not use the vehicle `id` as the connect target. ```javascript const odenClient = getOrCreateOdenLayoutClient(); const onFleetVehicles = (vehicles) => { // vehicles is an array: // [ // { id: string, name: string, availability: "Available" | "Monitored" | "Controlled" } // ] console.log("Online vehicles", vehicles); }; odenClient.registerUserMessageCallback("fleet_online_vehicles", onFleetVehicles); odenClient.sendNamedUserMessage("fleet_list_vehicles", {}); ``` ```javascript odenClient.sendNamedUserMessage("fleet_connect", { vehicle_name: "vehicle_name" }); odenClient.sendNamedUserMessage("fleet_disconnect", { vehicle_name: "vehicle_name" }); ``` `fleet_list_vehicles` Requests the online vehicle list from Bifrost. The reply is sent back as `fleet_online_vehicles`. `fleet_online_vehicles` Contains an array of vehicles with `id`, `name`, and `availability`. The list is sent after a webview requests it with `fleet_list_vehicles`. `fleet_connect` Requests a control connection to the vehicle named by `vehicle_name`. The Fleet Client retries wanted control connections while the vehicle is missing from the local connection list. `fleet_disconnect` Disconnects the control session for the vehicle named by `vehicle_name`. For the full SDK context, see [Webview and JavaScript SDK](../integrate/webview-sdk.md). For video layout from a webview, see [Player Layout](../configure/player-layout.md). ## Common Statuses | Status | Meaning | | --- | --- | | Available | The vehicle is online in Bifrost and has no active control or monitor session. | | Monitored | At least one monitor session exists for the vehicle. Control may still be available unless another operator has a control session. | | Controlled | A control session exists for the vehicle. The Player connection UI disables starting another control session to a controlled vehicle. | | Authentication not yet attempted | The Fleet Client has been created but has not completed its first authentication attempt. | | Connected to `
` | The Fleet Client is authenticated with a Bifrost fleet server. | | Invalid credentials | Bifrost rejected the Fleet Client credentials. Check the license or external identity token used by the application. | | Validation error: `` | Bifrost rejected the authentication request with a validation error. Use the message and application log to identify the provisioning or token problem. | ## Troubleshooting ### Vehicle Does Not Appear Online - Check that Oden Fleet Streamer is running on the vehicle. On Linux service installations, run `sudo systemctl status oden-streamer.service`. - Check that the Streamer is activated and that the Fleet Client plugin can authenticate. The Fleet Client GUI shows `Authentication State`. - Confirm that the vehicle computer can reach Bifrost. If it cannot, the vehicle cannot register as online. - Restart the Fleet Streamer service after activating or changing the license. - Make sure only one Oden Streamer instance is running on the vehicle unless the setup explicitly uses `--multiple-streamers`. ### Player Cannot See or Connect to a Vehicle - Enable the **Fleet Client** plugin in the Player. - Check the Player license or external identity token. `Invalid credentials` means Bifrost rejected authentication. - Verify that the vehicle name in a webview `fleet_connect` message matches the `name` field from `fleet_online_vehicles`. - If the vehicle is `Controlled`, another control session already exists. Disconnect that session before starting a new control session. - If the connection UI is hidden by project configuration, use the webview messages or the Fleet Client plugin GUI to inspect state. ### Connection Succeeds but Video Does Not Update - Verify the Streamer video input locally. Use a test source to separate camera problems from fleet/network problems. - Open the Remote Streamer entity on the Player and check packet loss, round-trip time, and whether packets are arriving. - Confirm that the Streamer project loaded after authentication. If no server-side Streamer project is available, the Streamer should load its local/default project. - Check that firewall and routing rules do not block the direct peer-to-peer path. The session can still start through a relay, but network policy can affect quality and whether P2P transition succeeds. ### Webview Requests Do Nothing - Enable the **Webview** plugin and load the page inside the Oden webview. The Oden Webview SDK message pipeline is available to pages running in Oden. - Register `fleet_online_vehicles` before sending `fleet_list_vehicles` so the response is not missed. - Send JSON payloads with the exact message names: `fleet_list_vehicles`, `fleet_connect`, and `fleet_disconnect`. - Use `vehicle_name`, not `id`, in connect and disconnect payloads. ## Related Pages - [Install Oden](../start/install-oden.md) - [Activate licenses](../start/activate-licenses.md) - [Connect Player and Streamer](../start/connect-player-and-streamer.md) - [Fleet management from a webview](../integrate/webview-sdk.md) - [Network and Remote Streamer links](../configure/network.md) --- # Performance Monitoring Check Oden fleet status, active vehicles, operator assets, and runtime health during a deployment. Last validated: 2026-05-05 Use performance monitoring to answer two questions before opening logs: - Is the expected vehicle or operator online in the portal? - If it is online, is Oden receiving video, audio, control feedback, and link statistics at runtime? ## Portal checks Open the Voysys portal and go to the fleet dashboard for the account. The self-serve portal routes personal accounts through `/home`, vehicles through `/home/vehicles`, and operators through `/home/operators`. Team accounts use the same pages under `/home/`. The dashboard currently separates: Vehicles Vehicle-side licenses and assets, including the vehicle type and whether a matching active instance was seen. Operators Operator-side licenses and assets, including whether an OdenVR/Oden Player instance is active. Projects Portal projects that can be assigned to vehicle licenses. Unclassified licenses Existing portal licenses that need to be classified as vehicle or operator before they fit the new fleet model. For an online check, look at the vehicle or operator status first. If the portal shows the asset as inactive, fix the portal, license, or service problem before spending time on video settings. ## Runtime checks When the portal shows the vehicle and operator as active, check the Oden applications. On the vehicle side: - Confirm `oden-streamer.service` is running when Fleet Streamer is installed as a service. - Confirm the Streamer project loaded the expected cameras and output. - Confirm the Fleet Client plugin is authenticated. On the operator side: - Confirm OdenVR or Oden Player is signed in or activated with the intended operator license. - Open the `Remote Streamer` entity and check traffic, round-trip time, packet loss, and whether video packets arrive. - Open the OCP plugin when control is enabled and check sender/receiver faults. For the detailed in-app evidence checklist, see [Diagnostics and Recording](diagnostics-and-recording.md). ## What to watch | Signal | Why it matters | | --- | --- | | Vehicle active in portal | Shows that the portal sees a vehicle-side application instance for the license. | | Operator active in portal | Shows that the portal sees the OdenVR/Oden Player license in use. | | Fleet availability | Shows whether the vehicle can be connected, monitored, or is already controlled by another session. | | Remote Streamer bandwidth | Shows whether video data is arriving and whether bitrate control has room to work. | | Round-trip time and packet loss | Shows whether the current link path is good enough for teleoperation. | | OCP faults | Separates vehicle-side control integration problems from operator input and connection problems. | | Frame-time statistics | Shows whether the computer is overloaded even when the network is healthy. | ## Support notes Capture the portal state and runtime state at the same time. A useful support snapshot includes the vehicle name, operator name, Oden versions, portal active/inactive status, Remote Streamer stats, OCP faults, and any service logs from the vehicle. --- # Diagnostics and Recording Use Oden statistics, frame-time monitoring, link diagnostics, raw recording, and extracted frames during operations and support. Last validated: 2026-05-05 Use this page when an Oden setup works but needs evidence: frame timing, link behavior, camera proof, reproducible recordings, or support material. ## Statistics Open the `Statistics` sidebar tab to inspect application and entity performance. The main measurements are update time, draw time, GUI time, total frame time, and main-thread CPU load. When plugins are present, plugin timing can appear for the relevant entities. Statistics usually show average, maximum, and standard deviation values, and graph history where the build exposes it. Use statistics during acceptance testing: - Check average and maximum frame time while the real cameras are running. - Watch for spikes when connecting a Player, changing scenes, opening a webview, or enabling plugins. - Compare Streamer and Player frame timing when video is unstable but the network stats look clean. ## Frame-time Monitoring Frame-time monitoring prints a console message when a frame exceeds the configured threshold. Use it when short stalls are visible to operators or when support needs timestamps for intermittent issues. Settings: Active Enables monitoring. Threshold Frame-time threshold that triggers a message. For Streamer service deployments, read the messages from the service journal: ```shell sudo journalctl -u oden-streamer.service -f ``` ## Link Diagnostics For runtime network checks, select the Player-side `Remote Streamer` entity and inspect link statistics. The first section groups incoming and outgoing bandwidth by traffic type. The packet timing graph shows frames as columns, packet timing within each frame, and the first packet from the next frame as a red marker. During a test, record: - Output resolution, codec, target bitrate, and frame rate from the Streamer. - Player-side bandwidth, round-trip time, and packet loss. - Channel usage and bytes in flight for each active link. - Whether traffic is direct, relayed, encrypted, or using P2P. - Any spikes in bytes in flight, wanted bitrate, reorder delay, or packet loss. If the Streamer output is running but the Player shows no image, combine link stats with [connection troubleshooting](troubleshooting.md#connection-or-no-remote-stream). ## Raw Recording Raw recording captures Oden video sources and optional custom plugin data. Use it to reproduce a scenario without access to the real vehicle or camera rig. Recording options: Destination folder Folder for the recorded video and playback project. Create Folder Creates a dedicated folder for the recording files. Frameskip Skips frames to reduce recording frame rate and disk usage. Use Ringbuffer Limits disk usage by overwriting the oldest frames after the maximum is reached. Use Time Based Ringbuffer Limits recording by time instead of disk space. To record a full scenario: 1. Open the `Raw Recording` sidebar tab. 2. Choose the destination folder and ringbuffer behavior. 3. Start recording. 4. Reproduce the scenario. 5. Stop recording before closing Oden. To record one source, select the relevant entity and use its single-entity raw-recording controls. > **WARNING** > Stop recording before exiting Oden. If Oden crashes or is stopped with Ctrl+C while recording is active, the recording can contain corrupted video streams. ## Playback and Frame Extraction To play a raw recording, open the folder containing the generated playback `.vproj` file. The `Raw Recording Playback` settings then appear in the project. Playback settings: Loop Repeats the recording. Loop Start/Stop Time Restricts the loop to a time range. Min, Max, Time Shows recording start, stop, and timestamp information. Use frame extraction when support, calibration, or documentation needs still images: Destination Folder Folder for extracted images. Interval Time between captured frames. Wait Time Delay before extraction begins. Extraction Frames Number of frames to extract. Entity Source entity to extract from. After selecting the entity and extraction settings, press the frame extraction start button and wait until the requested frames have been written before closing the playback project. Voysys raw `.vraw` recordings can be converted with the public `vraw_convert` tool at [https://github.com/voysys/vraw\_convert](https://github.com/voysys/vraw_convert). ## Support Bundle Checklist When reporting an issue, collect: - Product and version for every Oden application. - Operating system, GPU, driver version, and JetPack version where relevant. - Streamer project file and Player project file if they are safe to share. - Screenshot or copied values from Streamer `Output`. - Player `Remote Streamer` stats while the issue is happening. - Service journal if Fleet Streamer runs as `oden-streamer.service`. - Raw recording or extracted frames for camera, stitching, or rendering issues. For first-response checks, see [Troubleshooting](troubleshooting.md). --- # Deployment Prepare Oden for production or unattended use. Last validated: 2026-05-26 Use this checklist when moving an Oden setup from commissioning to unattended or production use. It focuses on the parts that must survive restarts: the Streamer service, the Streamer project file, Player display behavior, licenses, network reachability, and startup verification. ## Streamer service On Linux vehicle computers, Oden Fleet Streamer can install a `systemd` service named `oden-streamer.service`. The service is not installed by default. During package installation, choose to install, enable, and start the service when the Streamer should run automatically on boot. For scripted Linux deployments, pre-seed the installer answers before installing the Fleet Streamer package: ```shell echo "oden-streamer oden-streamer/accept-eula boolean true" | sudo debconf-set-selections echo "oden-streamer oden-streamer/install-services boolean true" | sudo debconf-set-selections export DEBIAN_FRONTEND=noninteractive sudo apt-get install ./oden-fleet-streamer_*.deb ``` The service runs as `root`, uses `/opt/oden-streamer` as its working directory, and starts: ```shell /usr/bin/oden-streamer --headless /opt/oden-streamer/oden-vehicle-config.vproj ``` Use `systemctl` for normal service operations: ```shell sudo systemctl status oden-streamer.service sudo systemctl start oden-streamer.service sudo systemctl stop oden-streamer.service sudo systemctl restart oden-streamer.service sudo systemctl enable oden-streamer.service sudo systemctl disable oden-streamer.service ``` > **NOTE** > `--headless` is a Linux Streamer mode where the GUI is not rendered. It is intended for unattended vehicle computers and embedded platforms. If you need remote access to the Streamer GUI while output is stopped, start the Streamer with `--configurator` as well, or make that part of the deployment’s service definition. See [Projects and Scenes](../configure/projects-and-scenes.md) for the Player-side Streamer Configurator workflow. Do not start a second Streamer on the same computer while the service is running. Stop `oden-streamer.service` before opening the same project in the local GUI. ## Streamer project file The Fleet Streamer service loads `/opt/oden-streamer/oden-vehicle-config.vproj`. If that file does not exist when the service starts, the service copies `/opt/oden-streamer/oden-vehicle-config-default.vproj` to that path before launching Streamer. Keep the production vehicle project at: ```text /opt/oden-streamer/oden-vehicle-config.vproj ``` To edit the project on the vehicle computer: 1. Stop the service. 2. Open the project with elevated permissions. 3. Save the project. 4. Close Streamer. 5. Start the service again. ```shell sudo systemctl stop oden-streamer.service sudo oden-streamer /opt/oden-streamer/oden-vehicle-config.vproj sudo systemctl start oden-streamer.service ``` The project may be owned by `root` because the service runs as `root`. If you open it as a normal user, saving may fail. Prefer changing the project through the Streamer GUI or Streamer Configurator. Editing the `.vproj` file directly is possible because it is a libconfig file, but it is easy to break a production project with an invalid edit. Before deploying the project, confirm at least: - The correct `Startup Scene` is selected in Project Settings. - All camera inputs start reliably after a cold boot. - The Streamer `Output` settings match the target resolution, codec, bitrate, FEC, and bandwidth-control policy. - Any project plugins are deployed beside the project or in the configured `Project Plugins Path`. ## Player display setup For operator stations, configure the Player so the operator sees the intended view without commissioning controls. Set these in **Application Settings** on the Player: Hide GUI on Startup Enable when the Player should start with the GUI hidden. Inhibit Mouse Look Enable when mouse movement must not move the 3D camera. Window Mode Choose the production display mode. Use `Fullscreen` for lowest latency on one display, `Windowed Fullscreen` when the window should stay visible while another screen is clicked, or `Spanning Fullscreen` for a multi-display span. Only Show Exit Dialog Enable if operators should see only the exit dialog while the GUI is hidden. The same settings can be deployed through the application config file: Windows `%LOCALAPPDATA%\oden\oden.conf` Linux `$HOME/.config/oden/oden.conf` ```text hide_gui : true; inhibit_mouse_look : true; window_mode : "fullscreen"; ``` Use `"windowed_fullscreen"` or `"spanning_fullscreen"` instead of `"fullscreen"` when that better matches the display layout. The GUI can still be toggled with the configured `Toggle Hide GUI` keyboard shortcut. The default shortcut is Ctrl+H. The `--windowless` command-line flag hides the Player window itself. Use it only for deployments where the Player must run without a visible application window. The windowless mode can be toggled with Ctrl+Shift+H. ## HMD and VR display setup When the Player is used with a head-mounted display, configure HMD behavior before hiding the GUI for production. Tested HMD families include Valve Index, HP Reverb G1/G2, and HTC Vive Pro 1/2. Other OpenVR/OpenXR-compatible headsets may work, but should be validated with the production GPU, driver, and runtime. Key settings: HMD Selection Selects the runtime backend: `Any`, `Oculus`, `OpenVR`, `OpenXR`, or `None`. Use `None` to disable HMD output and `Any` only when the deployment does not need a fixed backend. Fixed Position Locks HMD position to the origin and disables XYZ movement in the HMD world. Fps Cam Track HMD Makes the monitor view match what the HMD user sees. Draw Background Shows the Oden background in the HMD. Draw While Inactive Keeps rendering to the HMD even when the headset is not currently worn. Draw To Screen Disable screen rendering when only the HMD output is needed and GPU load must be reduced. Avoid changing HMD field-of-view factors unless Voysys support has asked for it. Non-default FoV can cause operator discomfort and invalidates display validation. For controller-based plugins, test controller remapping on the exact HMD model. Button and axis IDs can differ between runtimes and controller generations. ## Licenses Activate each installed Oden application on the computer where it will run before production use. Activation requires internet access and binds the license to that computer. After activation, Oden can run offline until the local activation period needs to be refreshed. For headless Streamer service installations, activate with the same Linux command that the service uses, then restart the service: ```shell sudo oden-streamer --activate sudo systemctl restart oden-streamer.service ``` For Player deployments, activate the installed Player application: ```shell oden-vr --activate ``` On Windows, run the installed executable from PowerShell: ```powershell & "C:\Program Files\OdenVR\OdenVR.exe" --activate & "C:\Program Files\Oden Streamer\OdenStreamer.exe" --activate ``` Before moving a license to another computer, revoke it while the old computer still has internet access: ```shell oden-vr --revoke oden-streamer --revoke ``` Check **Help**  **License Info** during acceptance testing and record the activation status for each production computer. For license file locations and offline behavior, see [Activate Licenses](../start/activate-licenses.md) and [Projects and Scenes](../configure/projects-and-scenes.md). ## Network readiness Verify the production network from the direction Oden will actually connect. By default, the Streamer initiates the connection and the Player responds, so the Player receive port must be reachable from the Streamer. Check these items before unattended operation: - The Player `Remote Streamer` entity has the correct link mode, receive port, and bind settings. - The Streamer network settings point at the Player responder address and port, or at the configured relay path. - Firewalls allow the Oden traffic on the configured ports. - If a Linux link uses `Bind Device`, the named network interface exists after boot and is the intended route. - If WireGuard encryption or relay routing is used, `Internal Src` and `Internal Dst` match the tunnel addresses. - `Target Bitrate`, `Target usage`, FEC, and reorder settings leave headroom for the real link. - Link stats show stable bandwidth, round-trip time, and packet loss under realistic load. Use the Player `Remote Streamer` stats during tests. `Packet Loss` should stay near zero on a clean link, `Round Trip Time` should match the expected path, and `Bandwidth` should stay within the available network budget. See [Network](../configure/network.md), [Connect Player and Streamer](../start/connect-player-and-streamer.md), and [Bitrate Control and Auto Video Packing](../configure/stream-settings.md) for the detailed settings. ## Docker Streamer deployments Use Docker only when the deployment needs container isolation or a containerized vehicle runtime. Native package installation and `oden-streamer.service` are simpler for most vehicles. Prerequisites: - NVIDIA GPU - Docker - NVIDIA Container Toolkit On Ubuntu, install and configure NVIDIA Container Toolkit: ```shell curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \ sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update sudo apt-get install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker ``` For desktop Ubuntu containers, use an Ubuntu base image matching the Oden `.deb` package target. For Jetson, use an L4T base image matching the host JetPack version. Check Jetson L4T with `cat /etc/nv_tegra_release`. On desktop NVIDIA systems, the container image does not need to include the host NVIDIA driver libraries. NVIDIA Container Toolkit injects the matching driver libraries at runtime when the container is started with GPU access. That is why a plain Ubuntu base image can be enough for desktop Oden Streamer containers, as long as the Ubuntu package target matches the image. ```dockerfile FROM ubuntu:24.04 ARG ODEN_INSTALLER_PATH=./oden-streamer.deb ENV DEBIAN_FRONTEND=noninteractive COPY "$ODEN_INSTALLER_PATH" /oden-streamer.deb RUN apt-get update -qq && \ apt-get install -qq -y --no-install-recommends /oden-streamer.deb && \ rm -rf /var/lib/apt/lists/* /oden-streamer.deb USER root CMD [ "oden-streamer", "--headless", "--configurator", "/root/project/streamer.vproj" ] ``` For Jetson containers, use the matching L4T base image: ```dockerfile FROM nvcr.io/nvidia/l4t-base:36.4.0 ARG ODEN_INSTALLER_PATH=./oden-streamer.deb ENV DEBIAN_FRONTEND=noninteractive COPY "$ODEN_INSTALLER_PATH" /oden-streamer.deb RUN apt-get update -qq && \ apt-get install -qq -y --no-install-recommends /oden-streamer.deb && \ rm -rf /var/lib/apt/lists/* /oden-streamer.deb USER root CMD [ "oden-streamer", "--headless", "--configurator", "/root/project/streamer.vproj" ] ``` JetPack 5.1 uses `nvcr.io/nvidia/l4t-base:35.3.1`. JetPack 6.1 uses `nvcr.io/nvidia/l4t-base:36.4.0`. Build with the Oden Streamer `.deb` next to the Dockerfile: ```shell docker build --build-arg ODEN_INSTALLER_PATH=./oden-streamer.deb -t oden-streamer:latest . ``` Run with GPU access, host networking, license data, and the project directory mounted: ```shell docker run --runtime nvidia -e NVIDIA_VISIBLE_DEVICES=all \ --network host --rm -it \ -v /run/udev:/run/udev:ro \ -v ./key.conf:/root/.config/oden/Oden_Streamer/key.conf \ -v ./project:/root/project \ oden-streamer:latest ``` `--network host` is commonly used because Oden uses realtime UDP links. Mount camera devices and plugin folders explicitly when the project needs them. `--runtime nvidia` and `NVIDIA_VISIBLE_DEVICES=all` give the Streamer GPU access; on newer Docker installations, `--gpus all` can be used instead. The `/run/udev` mount lets Oden read hardware identity data used by licensing. Mount `key.conf` at `/root/.config/oden/Oden_Streamer/key.conf` when the Streamer runs as root in the container, and mount the project directory at the same path used by the Dockerfile `CMD`. In the example above, the project file must be available as `/root/project/streamer.vproj`. ```yaml services: oden-streamer: image: oden-streamer:latest network_mode: host volumes: - /run/udev:/run/udev:ro - ./key.conf:/root/.config/oden/Oden_Streamer/key.conf - ./project:/root/project environment: - NVIDIA_VISIBLE_DEVICES=all runtime: nvidia ``` ```shell docker compose up ``` For Jetson zero-copy GStreamer IPC, make sure the `nvunixfd` plugin is available inside the container by installing it in the image or mounting it from the host. On JetPack 5, the Streamer installer bundles the plugin in `/usr/lib/aarch64-linux-gnu/gstreamer-1.0/`. On JetPack 6 and newer, install DeepStream or build it from `[https://github.com/voysys/nvunixfd](https://github.com/voysys/nvunixfd)` with `make`, then copy the `.so` to `/usr/lib/aarch64-linux-gnu/gstreamer-1.0/`. For container deployments, repeat that install inside the image or mount the plugin into the same path. ## Docker Fleet Streamer deployments Use this layout to run Oden Fleet Streamer as a long-running fleet daemon inside a Docker container, activated against the Voysys portal. This is distinct from the project-file driven Streamer container described above; here, the installer script pulls the Fleet Streamer package from `releases.voysys.dev` at build time and activation state is kept on a host volume. The same NVIDIA Container Toolkit prerequisites apply. Place a `Dockerfile` and a `docker-compose.yml` in a directory on the host. Pick the `Dockerfile` matching your host: desktop Ubuntu (x86\_64) or Jetson (arm64). ```dockerfile FROM ubuntu:24.04 RUN echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/99no-recommends && \ apt-get update && \ apt-get install -y --no-install-recommends curl ca-certificates RUN curl -fsSL https://releases.voysys.dev/install.sh \ | sh -s -- fleet-streamer --install-service false \ && rm -rf /var/lib/apt/lists/* ENTRYPOINT ["/usr/bin/oden-streamer"] CMD ["--headless"] ``` For Jetson hosts, swap the base image for the L4T tag matching your JetPack release; see the [NGC catalog](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/l4t-base). ```dockerfile FROM nvcr.io/nvidia/l4t-base:r35.2.1 RUN echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/99no-recommends && \ apt-get update && \ apt-get install -y --no-install-recommends curl ca-certificates RUN curl -fsSL https://releases.voysys.dev/install.sh \ | sh -s -- fleet-streamer --install-service false \ && rm -rf /var/lib/apt/lists/* ENTRYPOINT ["/usr/bin/oden-streamer"] CMD ["--headless"] ``` The `--headless` default keeps the daemon from trying to open a GUI window. The `--activate` step below overrides it because Docker replaces the default `CMD` with the arguments after the service name. ```yaml services: fleet-streamer: build: . image: oden-fleet-streamer:latest container_name: oden-fleet-streamer restart: unless-stopped # Bind-mounts CUDA, TensorRT and NVMM userspace libs from the host runtime: nvidia environment: - NVIDIA_VISIBLE_DEVICES=all - NVIDIA_DRIVER_CAPABILITIES=all # To achieve host-level network performance network_mode: host volumes: # Needed for license activation - /run/udev:/run/udev:ro # Persistence for activation state across container recreates - oden-fleet-streamer-data:/root # Add more volume mounts if needed, e.g. camera devices volumes: oden-fleet-streamer-data: ``` Build the image: ```shell docker compose build ``` Activate against the Voysys portal. Replace `` with the key from the portal: ```shell docker compose run --rm fleet-streamer \ --activate ``` The activation token is stored in the `oden-fleet-streamer-data` Docker volume and persists across container rebuilds. Start the daemon: ```shell docker compose up -d ``` Follow the logs: ```shell docker compose logs -f fleet-streamer ``` To pick up a new Oden Fleet Streamer release, rebuild the image and bring the service back up. Activation persists; you do not need to re-activate after an update. ```shell docker compose build --no-cache docker compose up -d ``` ## Startup checks Run these checks after every production image, package upgrade, project update, or network change. ```shell sudo systemctl status oden-streamer.service test -f /opt/oden-streamer/oden-vehicle-config.vproj ``` ```shell sudo journalctl -u oden-streamer.service -b --no-pager ``` Confirm that: - The service is `active (running)` after boot. - The expected project file was loaded. - No license error is shown. - All cameras or test sources start. - Output starts with the expected codec, resolution, frame rate, and bitrate. - The Player connects without manual steps. - The Player GUI is hidden or visible according to the deployment profile. - Remote Streamer stats show expected bandwidth, round-trip time, and packet loss. - Control, audio, plugins, and external integrations are active if the deployment uses them. Finally, power-cycle the vehicle computer and the operator station. Do not sign off the deployment until the complete stream, control path, and display layout recover without manual commissioning steps. --- # Troubleshooting Diagnose common Oden setup and runtime problems. Last validated: 2026-05-04 Use this page as the first-response checklist for a Streamer, Player, or Fleet Streamer system that does not install, activate, connect, show video, keep latency low, load plugins, or run as a service. Each section links to the detailed setup or reference page for the subsystem. ## Quick triage 1. Record the product, version, operating system, GPU, project file, connection path, and exact error text. 2. Check that all Oden installers in the setup are from the same release version. 3. Confirm that the Streamer and Player both have valid licenses. 4. If the Streamer normally runs as a service, check the service before starting a second Streamer instance. ```shell sudo systemctl status oden-streamer.service ``` 5. Replace the real camera with a `Test Source` input. If the test source works, continue with [No video or no input preview](#no-video-or-no-input-preview). If it does not work, continue with [Connection or no remote stream](#connection-or-no-remote-stream) or [Service problems](#service-problems). 6. On the Streamer, verify that the input `Texture` preview updates before troubleshooting the Player. 7. On the Streamer, verify that the `Output` tab is running and reports the expected resolution, codec, bitrate, and frame rate. 8. On the Player, select the `Remote Streamer` entity and check `Bandwidth`, `Round Trip Time`, and `Packet Loss`. ## Installation problems Use [Install Oden](../start/install-oden.md) for the full install flow. Checklist: - Download the installer from `[https://releases.voysys.dev](https://releases.voysys.dev)` and verify the matching `.sha256` file when available. - Use the installer for the correct product: Oden Fleet Streamer, Oden Streamer, OdenVR, or Oden Dome Player. - Use matching release versions on the Streamer and Player. - On Ubuntu, install downloaded packages with a leading `./`, for example `sudo apt-get install ./oden-vr__amd64.deb`. - On Jetson, select the package whose filename matches both the Ubuntu version and JetPack version. Check Jetson L4T with `cat /etc/nv_tegra_release`. - Install current GPU drivers before diagnosing video or encoder failures. - If Oden fails to open a window on Linux, try the Streamer in headless mode only after confirming that the system is intended to run without a GUI. ```shell oden-streamer --headless /path/to/project.vproj ``` - For noninteractive Fleet Streamer installs, pre-seed both the EULA and service choices before installing the `.deb`. ## License problems Use [Activate Licenses](../start/activate-licenses.md) for the full activation and revoke flow. Checklist: - Activate the product that will actually run on that computer. A Streamer license does not activate the Player unless the license includes that application. - Make sure the computer can reach `[https://license.voysys.se](https://license.voysys.se)` during activation, refresh, and revoke. - Paste the key exactly as provided, including hyphens. - Restart the application after the first successful activation. - For a headless Fleet Streamer service, activate with `sudo` so the root-run service can read the license data. ```shell sudo oden-streamer --activate sudo systemctl restart oden-streamer.service ``` - If terminal activation says a key already exists, use `--force` only when intentionally replacing the saved key on the same computer. - If the key is already activated elsewhere, revoke it on the old computer before activating the new one. - If the license expired or was not refreshed in time, reconnect the computer to the internet and activate again. - Check **Help**  **License Info** for the current validity, product capabilities, and activation dates. Common meanings: `Unable to connect to license server` Check internet access, DNS, firewall, proxy settings, and access to `[https://license.voysys.se](https://license.voysys.se)`. `License key has already been activated on another computer` Revoke the license on the other computer first. `License not valid for this application` Use the license for the installed product, or contact Voysys to confirm the licensed applications. `The Streamer Has No Valid License` The Streamer can start, but it will show a license error until activation succeeds. ## No video or no input preview Use [Camera Inputs](../configure/camera-inputs.md) and [First Vehicle Stream](../start/first-vehicle-stream.md) for detailed input settings. Start by locating where video stops: 1. If the input `Texture` preview does not update, troubleshoot the camera or input. 2. If the input preview updates but the `Output` tab is stopped, troubleshoot Streamer output. 3. If Streamer output is running but the Player has no image, troubleshoot connection and Remote Streamer settings. Input checklist: - Press `Start` on input types that have a start button. - Use `Test Source` to prove the project, encoder, and network path before diagnosing the real camera. - Match the input codec to the camera or sender. - For RTSP, check the URL, username, password, and selected codec. - For RTP, check that the sender uses the same UDP port and codec configured in Oden. - For GStreamer Pipeline, confirm that the pipeline reaches `odenvideosink`. Oden can append `! odenvideosink processing-deadline=0` if it is omitted. - For SRT or unstable GStreamer sources, increase `Pipeline Latency` in the input’s advanced settings. - For V4L2, confirm that the device node, pixel format, resolution, and frame rate are supported. Try `Blocking Mode` or `Retry Until Success` when the camera is slow to start. - For Direct Show, rescan devices after plugging in capture hardware. - For industrial cameras, rescan devices or interfaces and check camera access mode, IP address, exposure, gain, and packet-loss settings. Output and Player checklist: - In Streamer `Output`, press `Start` and confirm that the output stats update. - Use `HEVC (H.265)` unless the receiving system requires another codec. - On the Player, make sure the project contains a `Remote Streamer` entity. - Stop the Remote Streamer input before changing stopped-only settings such as `Codec`. - Match the Remote Streamer `Codec` to the Streamer `Output` codec. - If the Player shows `No Signal`, the Remote Streamer drop detector has not seen image changes before its timeout. Check whether the Streamer is still sending changing frames, whether the input is frozen, and whether packet loss is preventing complete frames. ## Connection or no remote stream Use [Connect Player and Streamer](../start/connect-player-and-streamer.md) and [Network](../configure/network.md). Fleet-managed connection checklist: - Use Oden Fleet Streamer on the vehicle side. - Make sure `oden-streamer.service` is running if Fleet Streamer was installed as a service. - Make sure the Player-side **Fleet Client** plugin is enabled. - Confirm both machines can reach the fleet service and that both applications are activated. - If the vehicle appears online but no video arrives, select the `Remote Streamer` entity and check `Bandwidth`, `Round Trip Time`, and `Packet Loss`. Direct connection checklist: - In the Player `Remote Streamer` entity, configure a receiver link and note the `Receive Port`. - In the Streamer `Network` tab, configure a sender link to the Player computer’s reachable IP address and the same port. - Do not use `127.0.0.1` unless Streamer and Player are on the same computer. - Open the configured UDP receive port in the Player firewall. - If using `Bind IP`, enter an address that exists on the local machine or leave it empty. - On Linux, use `Bind Device` only when traffic must go through a specific interface. A wrong bind device can bypass normal routes. - For initiator/responder links, the responder receive port must be reachable by the initiator. - When using WireGuard relay or encryption, confirm that keys and internal source/destination addresses match the relay configuration. ## High latency or unstable video Use [Bitrate control and Auto Video Packing](../configure/stream-settings.md) and [low-latency display settings](../configure/stream-settings.md#low-latency-display-settings). Checklist: - Start with a conservative output resolution, frame rate, and bitrate. Increase quality only after the Player stats are stable. - Enable `Sync to Video` and select the primary camera when low latency to that camera matters. - Use `HEVC (H.265)` for the normal low-latency path. - Keep the Player in fullscreen mode for lowest display latency. - Disable VSync unless the deployment specifically requires it. - Run the Streamer with `--headless` on Linux deployments where the GUI is not needed. - If `Packet Loss` is high, lower `Target Bitrate` first. - Enable `Use FEC` only when the link has packet loss and enough spare bandwidth for redundant packets. If FEC increases congestion, lower bitrate or reduce FEC. - If `Round Trip Time` or `Bytes In Flight` climbs during streaming, the network is likely saturated. Lower bitrate, resolution, frame rate, or target usage. - If packet reordering is high, test `Allow Reorder Delay` and `Max Reorder Delay` on the Remote Streamer. Disable reorder delay only for applications where minimum latency is more important than resilience to reordering. - Use P2P when available to avoid relay latency. ## Plugin problems Use [Plugins](../configure/plugins.md). Checklist: - Program plugins belong in the project plugin path or next to the project file. - Global plugins must be in the same directory as the Player or Streamer executable. - After changing `Project Plugins Path`, save and reopen the project. - If the plugin path uses environment variables, hover the path field and confirm the expanded path. - Make sure each plugin entity uses a unique entity ID. - Keep hot reloading disabled in production. - On Windows, open the plugin `.dll` in Dependencies and resolve missing dependencies. - On Linux, run `ldd -r -d ./.so` in the plugin directory and resolve any missing libraries. - Check the application log or service journal for plugin load failures, version mismatch warnings, or duplicate-load warnings. ## Service problems Use [Noninteractive Fleet Streamer service install](../start/install-oden.md#noninteractive-fleet-streamer-service-install) and [Launch modes](../configure/projects-and-scenes.md#launch-modes). Fleet Streamer service facts: - The service is installed only when selected during the Fleet Streamer `.deb` install or when pre-seeded through debconf. - The service name is `oden-streamer.service`. - The service runs as `root`. - The service starts `/usr/bin/oden-streamer --headless /opt/oden-streamer/oden-vehicle-config.vproj`. - If `/opt/oden-streamer/oden-vehicle-config.vproj` does not exist, the service copies the default project before starting. Checklist: - Check service state and recent logs. ```shell sudo systemctl status oden-streamer.service sudo journalctl -u oden-streamer.service -n 200 --no-pager ``` - Restart the service after changing the project, license, network, or plugin files. ```shell sudo systemctl restart oden-streamer.service ``` - Stop the service before opening the same project manually in the GUI. ```shell sudo systemctl stop oden-streamer.service sudo oden-streamer /opt/oden-streamer/oden-vehicle-config.vproj ``` - If manual Streamer startup reports another Streamer instance, stop the service or intentionally start with `--multiple-streamers`. - If saving fails when editing `/opt/oden-streamer/oden-vehicle-config.vproj`, check file ownership and remember that the service runs as root. - Activate service deployments with `sudo oden-streamer --activate `, then restart the service. - If the service restarts repeatedly, inspect the journal for license errors, plugin load failures, missing camera devices, or project parse errors. ## Detailed pages - [Install Oden](../start/install-oden.md) - [Activate Licenses](../start/activate-licenses.md) - [Connect Player and Streamer](../start/connect-player-and-streamer.md) - [Camera Inputs](../configure/camera-inputs.md) - [Bitrate Control and Auto Video Packing](../configure/stream-settings.md) - [Network](../configure/network.md) - [Plugins](../configure/plugins.md) - [Projects and Scenes](../configure/projects-and-scenes.md) - [Deployment](deployment.md) --- # Network Configuration Plan and validate vehicle-side and operator-side network links for Oden deployments. Last validated: 2026-05-05 Oden is designed for real teleoperation networks, not only clean lab networks. A vehicle may have cellular modems, satellite, Wi-Fi, Ethernet, or a site VPN available at different times. Good Oden deployments use those paths deliberately so a weak link does not become the whole system. The goal is simple: keep video, audio, and control connected through the best available paths, and prove during testing that the paths are actually active. For the exact Oden link fields, see [Network](../configure/network.md). ## Why multiple links matter Cellular networks fail in local, boring ways: one carrier is congested, one modem roams, one antenna is shadowed, or one area has coverage from a different provider. Satellite and Wi-Fi solve different parts of the map. Oden can combine several links so the vehicle keeps a usable path when any one access network is weak. Use multiple links when: - The vehicle can connect through more than one modem, carrier, satellite terminal, Wi-Fi network, or routed interface. - Operators need coverage across a large site or route instead of one fixed test area. - A deployment must degrade gracefully rather than drop the session when one link changes. Do not stop at adding links in the project. During commissioning, verify that each physical link carries traffic when the matching network is available. ## Vehicle side link configuration On the vehicle, each link should describe one real egress path. 1. Add one Oden link per modem, adapter, tunnel, relay, or intended route. 2. Give each link a name that maps to hardware or network ownership, for example `cellular-a`, `cellular-b`, `satellite`, or `depot-wifi`. 3. On Linux, use `Bind Device` or a specific bind address when traffic must leave through one interface. 4. Use a separate destination port per link unless the network design intentionally shares a port. 5. Keep links for the same stream in the same bonding group when they should contribute to the same video/control path. 6. Save the Streamer project after validating the link state. For service installs, restart the vehicle service after changing the project: ```shell sudo systemctl restart oden-streamer.service sudo systemctl status oden-streamer.service ``` ## Operator side link configuration On the operator side, the Player or OdenVR project must have matching receiver links. 1. Create one `Remote Streamer` link for each vehicle-side link path. 2. Match the receive ports and relay/P2P/encryption settings to the vehicle-side configuration. 3. Leave the operator bind address broad unless the workstation has multiple interfaces and routing must be explicit. 4. When using the portal fleet flow, let Fleet Client create or update the session links unless support has given you a project-specific reason to override them. 5. Verify `Remote Streamer` link stats while a real session is running. For operator layout and visible-camera behavior, see [Project Configuration](../configure/project-configuration.md) and [Bitrate Control and Auto Video Packing](../configure/stream-settings.md). ## Troubleshooting multiple links The most common multiple-link problem is believing that there are multiple active links because they exist in the project. Treat that as unproven until you see traffic on each intended path. Run these checks during commissioning: - Disable or unplug one access network at a time and confirm the session stays connected through the remaining links. - Watch `Remote Streamer` link stats and confirm bytes, packet timing, and loss change on the expected link. - Check OS routing from the vehicle computer so each modem/interface has a usable default or policy route. - Confirm the configured `Bind Device`, bind address, destination address, and destination port match the physical path. - Check firewall and NAT rules on every path, especially when one link works and another stays idle. - Test fallback in the same geography where the vehicle will actually operate. If one link never carries traffic, simplify the test: run a single-link project through that path, prove routing and firewall behavior, then re-add the link to the bonded setup. For support evidence, capture portal active state, Oden version, Streamer service logs, Remote Streamer link stats, and the network hardware list. See [Diagnostics and Recording](diagnostics-and-recording.md) for the broader checklist. --- # Technical Reference Field-by-field reference for Oden entities, settings, and subsystems. Last validated: 2026-05-19 Use this section when you already know the task and need the exact behavior of a specific entity, setting, or subsystem. The [Get Started](../start/index.md), [Stream Video and Audio](../configure/index.md), [Control a Vehicle](../integrate/index.md), and [Supervise Many Vehicles](../operate/index.md) sections explain workflows; this section documents the individual pieces. ## Entities - [Entity](entity.md) base concept and shared properties. - [2D Image](entity-2d-image.md), [2D Video](entity-2d-video.md), [Text](entity-text.md), [Model](entity-model.md). - [Stitched Video](entity-stitched-video.md), [Remote Stitched Video](entity-remote-stitched-video.md), [Remote Streamer](entity-remote-streamer.md), [Streamer Configurator](entity-streamer-configurator.md). - [Flexbox](entity-flexbox.md), [Video Composition](entity-video-composition.md), [Virtual Camera](entity-virtual-camera.md), [Output Alignment](entity-output-alignment.md). - [External Scene](entity-external-scene.md), [Scene Mirror](entity-scene-mirror.md), [Follow HMD](entity-follow-hmd.md), [Encoder Test](entity-encoder-test.md). ## Settings and subsystems - [Application Settings](application-settings.md), [Project Settings](project-settings.md), [Configuration Files](configuration-files.md), [Command Line Arguments](command-line-arguments.md). - [Video Inputs](video-inputs.md), [Hardware Decoder](hw-decoder.md), [Stitching](stitching.md), [Streamer Output](streamer-output.md). - [Audio Streaming](audio-streaming.md), [AI Inference](ai-inference.md), [Chroma Keyer](chroma-keyer.md), [Auto Packer](auto-packer.md). - [Colors](colors.md), [Coordinate System](coordinate-system.md), [Movement](movement.md), [Scenes](scenes.md). - [Com Channels](com-channels.md), [Network](network.md), [Statistics](statistics.md), [Raw Recording](raw-recording.md), [Plugins](plugins.md). - [HMD](hmd.md), [License Management](license-management.md). --- # Entity Entity is a base entity that has no functionality other than the ability to change position, scale, and rotation. There are a few useful uses for this entity, such as: - Store other entities underneath it for better structure of the project. - Get its transform from a plugin to apply it on GUI elements that are drawn from the plugin. - Use it to transform multiple entities while keeping their relation intact amongst each other. --- # 2D Image 2D Images in .png, .jpg, and .jpeg format can be loaded. Transparency is fully supported. This is the recommended way to insert graphics in a scene. If there is a need to insert 2D Images in a different format, then a format conversion is required. There are many third party applications that can be used for this, e.g. Paint which is included with Windows. --- # 2D Video A 2D Video is a video input that is displayed on a floating flat video surface in 3D space. The 2D Video entity has multiple different inputs that it can take as its video source, these are described in [Video Inputs](video-inputs.md). The 2D Video’s biggest use is together with the [Output Alignment](entity-output-alignment.md) entity where it could be used to layout multiple 2D videos in the output texture. Another powerful way of using 2D Videos is to capture a computer’s display and show that. This is useful for presentations, games, and tutorials. 2D Videos are added to the scene graph like all other entities. The input is opened the same way inputs are opened in a Stitched Video entity. ![2d video](_images/2d-video.png) Figure 1. The settings UI for 2D Videos. ## Settings There are multiple different settings for 2D videos, some will be described here while others have their own chapters. ### Visible In Eye Sets which eye or eyes in an HMD that the 2D Video should be visible for. In tab _Project Setting_, you can set which eye the 3D viewport should show. ### Curvature The 2D video is flat by default, but curvature can be added to it. The curvature goes from -1 to 1 where 0 is flat. Subdivisions When the curvature is not 0, another setting appears which is subdivisions. Subdivisions set how many planes will be used to create the curvature. Smoother curvature requires more subdivisions but will require more computing power. ### Stereo Mode Stereo mode can be enabled to allow stereoscopic video inputs that are split horizontally or vertically. Use Eye **Use Eye** gives the user the choice to set which eye should be visible in the 3D viewport. This setting is only shown if **Stereo Mode** is not set to **Mono**. ### Anti-Aliasing Anti-aliasing is a filter that can be added to make the edges of the 2D video smoother. ### Border A border can be added to the 2D video by enabling the setting **Border**. ![2d video border](_images/2d-video-border.png) Figure 2. The setting UI for 2D Videos border. ### View Fixed View fixed is a tool for placing a 2D Video in the view space of the screen. This means that the video is in that pixel position even if the viewport camera moves. This is useful if you want a video that is always shown to the user regardless of their orientation in 3D. The position of the 2D video can either be set by pixel position or by percentage. The aspect ratio is locked by default but could be disabled by unchecking the setting **Lock Aspect**. ![2d video view fixed](_images/2d-video-view-fixed.png) Figure 3. The setting UI for 2D videos view fixed. ### Color Color is described in [Color Handling](colors.md). ### Chroma Key Chroma Key is described in [Chroma Key](chroma-keyer.md). ### Matte Key Matte Key is described in [Matte Key](matte-key.md). ### Input Input is described in [Video Inputs](video-inputs.md). ## Focus region 2D videos have another function which is the focus region. Focus region is a technique where the 2D Video only consists of a small part of another video stream. This is useful if you only want to send a certain part of an image, but its greatest use is together with [Output Alignment](entity-output-alignment.md). Two 2D videos are children to an [Output Alignment](entity-output-alignment.md) entity where one of them has input source and the second 2D Video will have its input as a clone stream from the first 2D Video. When enabling the focus region, all information about where the slice of the original image is taken from is streamed to the Player. If we send the original image in lower resolution while sending the focus region in its full resolution the Player can combine these two images, with a resulting image that is blurry in some regions and crystal clear in some, as in the figure below. ![2d video focus region example](_images/2d-video-focus-region-example.png) Figure 4. Focus region example where most of the image is blurry while the bottom left is in high resolution. Focus region is easy to use and is only two settings as seen in the figure below. One of the settings is **Focus Center** which is where the center of the focus region area will be located in the original image. These values are clamped so the focus region can never go outside of the image. The **Focus Center** values can be controlled from a plugin. The second setting is **Focus Size** which is how large the focus region should be, this cannot be changed during runtime without inspecting the layout in the [Output Alignment](entity-output-alignment.md). ![2d video focus region](_images/2d-video-focus-region.png) Figure 5. The UI enabling the focus region option. --- # Encoder Test Encoder Test creates a sphere with a colorful pattern (Perlin noise). This can be used e.g. to test network streaming when no cameras are available. The encoder test often has a higher entropy (i.e. is harder to encode) than a regular input. ![encoder test](_images/encoder-test.png) ## Settings Noise The amount of noise added to the encoder test, in percent. Range 0–100%. Noise Frequency The frequency at which the noise amount is modulated, in Hz. Range 0–1000 Hz. Speed The time multiplier for the perlin noise animation, in percent. Range 0–100%, default 15%. --- # External Scene External Scene can be used if you want parts of a scene to be separated in another file than your project. This could be because you share this data between multiple project and want to version control it separately. You can change the child entities to the External Scene entity and then use the "Save Scene" button to save the changes to the external scene file. ## Usage To load the desired .vscene file, use the file picker. If you wish to directly create an external .vscene, you must provide a path along with the file name. ## Settings External Scene File The path to the .vscene file to import. Save Scene Will save the state to the .vscene file. If the given filename does not end with `.vscene`, the extension is appended automatically. Auto Save Will auto save the file on changes. --- # Flexbox / Flexbox Group Layouting of 2D Video and Flexbox Group entities in screen-space coordinates using the CSS Flexible Box Module. Please see [https://developer.mozilla.org/en-US/docs/Web/CSS/CSS\_Flexible\_Box\_Layout/Basic\_Concepts\_of\_Flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) for more information. > **NOTE** > There is only allowed to be one Flexbox in each scene, but there could be multiple Flexbox Groups. ## Use Case When displaying videos in a flat context it can be a pain to layout the different cameras in a nice and easily configurable way. Flexbox entity is used as root layouting node and subsequent children are Flexbox Group entities and 2D Video entities which can be laid out in the desired way using the settings below. If you are familiar with web development you can think of the flexbox child entities as div elements in HTML, where the flexbox settings are the CSS styling applied to them. ![flexbox example layout](_images/flexbox-example-layout.png) ## Flexbox ### Usage Flexbox entity is used as root layouting node where some highlighting settings are available for easier development of the flexbox layout. The padding for the viewport can be configured to limit the area where the layout should be constrained to. All flexbox children are shown as tree-nodes and can be configured directly or by clicking into an Flexbox Group. ### Settings Padding Viewport padding top, right, bottom, and left. Highlight Layout Highlights the flexbox child boundaries when hovered over in the viewport. Highlight Bounds Turns the highlighting of the layout to be always on. Highlight Color Set the color of the highlight box. Text Color Set the color of the text overlay. Border Color Set the color of the highlight border. Border Thickness Set the thickness of the highlight border. ## Flexbox Group ### Usage Use the Flexbox Group entity to group two or more cameras or Flexbox Groups which should be laid out in relation to one another. No need to use a Flexbox Group entity above a single 2D Video. Flexbox Groups are laid out in relation to one another with bounds which can be highlighted by the Highlight Layout Setting. Within the Flexbox Group the 2D Videos are laid out with the boundary as the constraint. ### Settings Width Set the width of the flexbox child. Height Set the height of the flexbox child. Min Width Set the minimum width of the flexbox child. Min Height Set the minimum height of the flexbox child. Max Width Set the maximum width of the flexbox child. Max Height Set the maximum height of the flexbox child. Gap Width Set the gap between flexbox children within a flexbox group width wise. Gap Height Set the gap between flexbox children within a flexbox group height wise. Relative Size Set the proportion the flexbox child should take within the flexbox container (the underlying CSS property is `flex-grow`). Flex Shrink Set the proportion the flexbox child should shrink relative to the other flexbox children within the flexbox container. Inset Control the top, right, bottom, and left margins Justification Defines how flexbox children are distributed using space between and around the flexbox children along the main-axis of a flexbox group. Align Items Align a flexbox child to the Left, Right or Center. Direction Control if the flexbox children should be laid out in column or row within a group. Positioning Control if positioning should be done relative to the flexbox group or absolute in relation to the viewport. Highlight Name Set if the entity name should be drawn over the highlight box. --- # Follow HMD Follow HMD is an entity that polls the transform from an attached head mounted display (HMD) and applies it to the entity. Entities that are children of the Follow HMD entity will be affected by this transform. This can be used e.g. to display information to the user regardless of the head position. ## Settings Sync to HMD Camera Syncs the Follow HMD transform to the front-facing HMD camera. If the front-facing cameras are used together with the Follow HMD entity to create a see through video, the transform will not be in sync with the received images. With this setting enabled, the transformation will be time synced with the front-facing cameras instead of the HMD. (Only available to SteamVR / Valve Index HMDs.) --- # Model 3D models can be added to a scene. The supported formats are glTF (`.gltf`) and binary glTF (`.glb`). ## Settings ![model settings](_images/model-settings.png) Clone Model If there should be multiple instances of the same model it is better for performance to have one model added to the project and then use this setting to clone from that model. When using "Clone Model", the software can make use of instanced rendering to increase performance. Open Opens a dialog window for selecting which model to load. Env. Lighting Use environmental lighting for the model, which can make it look better and e.g. offers reflection effects. Environmental lighting uses GPU resources and can significantly increase the rendering time of models using it. ### Inspect Model This will show all nodes of the model and allow for tweaking. > **NOTE** > No changes here will be saved to the model or the project! ### Collision Meshes Collision meshes are a feature that can be used when integrating physics engines via plugins. For more information about this advanced topic, please contact your support representative. --- # Output Alignment (Streamer) Output Alignment is an entity that helps the user to align one or multiple video sources in the output video texture that Oden Streamer sends to OdenVR. The Output Alignment entity gives the ability to set the exact pixel position and size for each video source in a quick way. Along with helping the user align the video sources it also packs the alignment data and transmits it to OdenVR. OdenVR can then automatically split the incoming video texture into separate video streams. To use the Output Alignment entity you need to add your [2D Video](entity-2d-video.md) entities as child objects to the Output Alignment, as seen in the figure below. ![output alignment](_images/output-alignment.png) Figure 1. The [2D Video](entity-2d-video.md) that is being aligned must be a child object to the Output Alignment entity The Output Alignment entity has several settings which can change how the output alignment works, as well as settings for aligning the video sources, explained in detail in chapter [Settings](#settings). ![output alignment settings](_images/output-alignment-settings.png) Figure 2. The settings of an Output Alignment entity. Oden Streamer will stream everything visible as one texture. The Output Alignment entity helps layout video streams in that texture. It will also stream the alignment data along with the video so the Remote Streamer entity can automatically crop the texture into separate video stream. When cloning from a Remote Streamer, three different types can come from an Output Alignment: - LLTP - The complete video stream with all sub videos - Stream - This is the cropped video stream that correlates to one of the input video sources - Focus Region Composite - This is a focus region video stream which is a combination of two or multiple video streams to create a region of interest video. ![output alignment player](_images/output-alignment-player.png) Figure 3. The output of an Output Alignment stream. ## Settings There are a few settings that can be changed in the Output Alignment entity; some affect the entity as a whole and some affect each individual video source. Enabled This locks the camera to show the output alignment layout. It can be disabled to allow the user to move freely in 3D space. The alignment data will be wrong if disabled when streaming. Snap to Output When setting up a focus region that has one original source and multiple focus sources that is combined into one output, there are some restrictions on where video sources can be placed. This boils down to how the encoder works and if not placed correctly it could add artifacts to the video stream. If this setting is enabled, the software will move entities so that it fulfills the requirement so no artifacts occur. This setting is strongly recommended to have enabled if using focus regions with multiple quality regions. Auto-Layout When pressed the software will try to layout the 2D surfaces automatically in the given space. ### Video Source Settings Each video source has individual settings for how it should be placed in the output texture. The [2D Video](entity-2d-video.md) needs to have an active input source for the settings to show up in the Output Alignment entity. ![output alignment settings video](_images/output-alignment-settings-video.png) Figure 4. The available settings for each video stream. Id Id is the identification number that will be shown at the OdenVR end when retrieving the video sources, as seen in figure [The output of an Output Alignment stream.](#output-alignment-player). Position This sets the position of the video source where (0, 0) corresponds to the top left pixel in the output resolution. Video sources can be placed outside of the output texture. Scale This setting sets the scale of the entity relatively to the size of the source. This can be done either by percentage or pixel scale which is set by the [Scale Mode](#scale-mode) setting. Scale Mode Scale mode sets how the video source size is controlled. The alternatives are **Percent** or **Pixels**, the aspect ratio is always kept. Rotation Rotation is used to rotate the video entity by full 90, 180, or 270 degrees to better fit all video streams into the output resolution. If the video source has a focus region attached to it that focus region will also be rotated. Mirror The mirror checkbox can be used to flip the video. If the video source has a focus region attached to it that video will also be mirrored. ## Limitations Output Alignment only works with [2D Video](entity-2d-video.md) entities. No other entities will be effected by the Output Alignment. When using focus region together with auto mode switch there could be some encoder bleeding on the edges when the resolution scale is not 1. This is because of how the encoder works, to combat this we recommend checking so all the resolution scales work with the focus region before deploying. If not, check out different positions or slightly different resolution scales. --- # Remote Stitched Video A Remote Stitched Video renders a Stitched Video that is present on the Streamer. If you have multiple vehicles with calibrated cameras you can setup one Player project that shows the Stitched Video from the connected Streamer. Remote Streamer Select the Remote Streamer that is receiving video from the Streamer that has the Stitched Video you want. Remote Entity Select the entity on the Streamer that you want to render. In the list, available entities are shown as "Name (Number of streams that are sent to the Player / number of total video streams)" --- # Remote Streamer The Remote Streamer entity is the main way to receive video, audio and data communication from Oden Streamer. ![remote streamer overview](_images/remote-streamer-overview.png) Figure 1. Overview of the Remote Streamer GUI. Target Usage Controls how much of the available link bandwidth the streamer should aim to use. 50% is a good baseline value for this setting. It is important to leave headroom in the link for rapidly fluctuating signal conditions. > **NOTE** > The Streamer has a target bitrate setting that controls the maximum allowed bitrate. Even if there is available bandwidth in the network, this maximum bitrate will not be exceeded. Show Graph When set the network stats graphs will be drawn in the world. The position of the graphs is controlled by the position of the Remote Streamer entity. ![remote streamer stats](_images/remote-streamer-stats.png) Figure 2. Remote Streamer network stats. Channel Usage Measurement of how much of the available network capacity is used at this moment. Packet Loss Shows if any packets are lost or too late to be counted as part of the frame. Bytes In Flight Measurement of how much data is in flight in the network. Bandwidth The current bandwidth that the streaming video consumes. Round Trip Time The current round trip latency to the streamer. ## Streamer Stats ![remote streamer stats gui](_images/remote-streamer-stats-gui.png) Figure 3. Streamer stats. This is the same stats as shown by the show graph checkbox. Additionally, stats for each link is shown separately and at the bottom of this section is a color coded graph of what link each packet in the current frame arrived from. ## Network In this section all the network links that the player should use is configured. If the streamer has multiple links then you don’t need to add more than one link here. But if the player for example has two LTE modems then you need to configure them here. See [Network](network.md). ## Audio See [Audio Streaming](audio-streaming.md). ## Video ![remote streamer video](_images/remote-streamer-video.png) Figure 4. Overview of the Remote Streamer video settings. Filter Under the filter tab you can configure an image filter. A sharpening filter is recommended for better visual clarity. Drop Detector The drop detector detects if the image changes during the specified timeout value. If it does not change the image is replaced with a `No Signal` text. This is to ensure that the operator is aware that the image is no longer current. The time since that last valid image is available through the plugin API. HW Decoder See [Hardware Decoder](hw-decoder.md). If you press Stop on the input you get access to more settings. ![remote streamer video stopped](_images/remote-streamer-video-stopped.png) Figure 5. Additional Remote Streamer video settings, available when the input is stopped. Allow Reorder Delay Controls how many frames to keep when receiving packets from newer frames. Max Reorder Delay If your network has a large amount of packet reorders then increasing the max reorder delay may reduce the amount of observed packet loss. Configuring [FEC](streamer-output.md) on the Streamer may be a better option. If your application is extremely latency sensitive you can disable allow reorder delay. Max Invalid Packets Controls how many packets in a row from a different stream has to be observed for the receiver to resync its current packet counter. This in effect controls how long it takes for the stream to be displayed if the Streamer were to restart. You can try increasing this value if you have lots of packet reordering in your network. Codec Must match the codec used by the Streamer to encode the video. It is strongly recommended to use the default `HEVC (H.265)` codec. --- # Scene Mirror Scene Mirror is an entity that mirrors what is shown in another scene. This entity could be used in the case where multiple entities are the same for multiple scenes. For example, when creating a dashboard for a vehicle that should be in the same place regardless of which scene it is. This helps because the user only needs to change one entity for it to affect all other scenes. ## Settings Scene To Mirror This setting selects which scene that will be mirrored. > **NOTE** > A scene cannot mirror itself, and a Scene Mirror will not display a scene that itself contains a Scene Mirror (chained mirroring is not supported). --- # Stitched Video Stitched Video is an entity that can calibrate a camera rig containing one or more cameras. The cameras can then be stitched together during runtime using different techniques. Common uses cases for the Stitched Video are to remove the fish-eye effect for one camera or to make a larger stitched video by combining multiple cameras. Another way to think about the use case for Stitched Video is that where a 2D Video presents video like one would see video on a TV or phone screen the Stitched Video allows to look out from the camera like if the viewer were at the center of the camera rig. In this way of thinking about it, the purpose of a Stitched Video is to visualize the world as correctly as possible based on the cameras that are part of it. A Stitched Video requires calibration to work properly. ![stitched video overview](_images/stitched-video-overview.png) ## Stitching The Stitching tab contains settings for controlling the stitching of the video. ![stitched video stitching](_images/stitched-video-stitching.png) Blend Distance Given two cameras with some overlap between them, Blend Distance sets how much of the overlap is visible. Value goes from 0.0-1.0 where 0.0 is a sharp line (no visible overlap) and 1.0 shows the full overlap. Blend Curve The overlap zone is the area where video is shown from both cameras. Blend Curve describes the blending function across the overlap zone. Type The stitching can be viewed on different surfaces. The currently supported types are: - Sphere - GPU Auto - Model - External Show Stitch Zone When enabled, it will show where the stitch between different video feeds is located, can be helpful to have enabled when changing stitch settings. ### Type specific settings Some specific settings are only visible when a type is selected. Radius(Sphere specific) Sets the size of the sphere which the video is displayed on. It is recommended to set the size to the distance of the object most likely to be looked at. Lock Auto-Stitch(GPU Auto specific) When enabled, freezes the current depth map and stops the algorithm from updating the stitch geometry. Useful for locking in a result you are happy with, or for testing under static conditions. Reset(GPU Auto specific) Clears the current depth state and the temporal smoothing buffers so the algorithm restarts analysis from scratch. Add (Model specific) Adds one or more of the selected primitives, the following are supported: - Box - Sphere - Quad - Model From File All model types have settings regarding transform, scale, and rotation. There are other settings that are specific for this type called **Entity transform** which can connect this primitive to other entities transform. Quad has a button called **Set As Calibrated Floor**, if a horizon calibration has been made it will automatically set the quad to the height of the calculated floor. ### Manual Geometry Adjustment Manual Geometry Adjustment lets you override or supplement the automatic stitch geometry by defining regions of the panorama where the distance and blending of the projection surface are set by hand. The combined adjustments are baked into a small depth/weight texture that the renderer samples when projecting the cameras. Regions can be layered, and the preview at the bottom shows the resulting depth map. #### Sector Regions A sector region is an angular slice of the panorama with a fixed projection distance. Use sectors when a portion of the view should sit at a different depth than the rest. Add Adds a new sector region with default values (angle 0°, size 25°, blend 0.5, distance 3.5 m). Angle The center azimuth, in degrees, where the sector is placed. 0° is forward; values wrap at 360°. Size Total angular width of the sector, in degrees. Default 25°. Blending Edge feathering of the sector. 0.0 is a hard edge; 1.0 fades smoothly across the entire width. Default 0.5. Distance The projection distance for this sector, in meters. Logarithmic slider, range 0.4–800 m, default 3.5 m. #### Ground Plane A ground plane is a tilted plane placed below the rig. Use it to project the floor at a consistent distance regardless of camera angle. Active Enables the ground plane. Angle Pitch angle of the plane from vertical, in degrees. Range 10–70°, default 45°. Height Distance of the plane below the camera, in meters. Range 0.5–100 m, default 1.5 m. Blending Edge feathering of the plane. Range 0.0–1.0, default 0.5. #### Circular Placed Regions A circular region is a sphere placed at a specific 3D position. Use it to override projection at a localised point in the panorama (e.g. a nearby pole or vehicle part). Add Starts an interactive placement: click once in the 3D view to set the region center, then click again to set the radius. #### Preview Depthmap Mod Displays the depth/weight texture computed from all the active manual adjustments. The red channel encodes distance and the green channel encodes the blending weight. Useful for verifying that overlapping regions combine as expected. ### Advanced The Advanced subtree exposes settings that depend on the selected stitch type. For GPU Auto, this includes depth map resolution and other algorithm tuning; for other types, the section may be empty. ## Color Color is described in [Color Handling](colors.md). ## Chroma Key Chroma Key is described in [Chroma Key](chroma-keyer.md). ## Matte Key Matte Key is described in [Matte Key](matte-key.md). ## Horizon Horizon can change the rotation of the stitched video to better align the video with the real world if the cameras are tilted. The horizon can be calibrated with the use of an aruco marker. For the calibration, the marker on the backside of the calibration board can be used or it can be printed. > **NOTE** > When printing a marker, make sure it is printed on a flat stable surface! At least three markers need be captured for the calibration, but we recommend using more captures to get a better calibration. When three markers have been captured the button "Calibrate" will be available, when pressed, it will rotate the stitched video. The video might not be centered where the user wants it, the manual horizon values can then be used to make fine-tunings. ![horizon gui](_images/horizon-gui.png) Angle The angle of each axis that the stitched video will be rotated around. Bake Angle This button will take the horizon angles and bake them into the camera rig settings. This is recommended after horizon calibration has been made. Reset Resets the applied horizon. Drag To Adjust When enabled, make it possible to change the horizon by clicking and dragging the view. Capture marker When pressed, captures a visible marker. Calibrate Runs the calibration algorithm and changes the horizon. At least three markers must have been captured. Marker Position Each marker that has been captured will be shown here along with the position. The marker can be deleted with the **Delete** button. ### Horizon Calibration Settings Show marker When enabled it will show the captured marker in the 3D world. > **NOTE** > The rotation may not always be accurate, however the rotation is not used in the algorithm so it can be discarded. ![stitched video marker](_images/stitched-video-marker.png) Marker Size The size of the physical calibration board. Dict Size The size of the dictionary with markers that will be created. Marker Bits The number of bits in each dimension for the marker. Marker ID The ID of the marker in the dictionary. Reset To Default Values Resets to the default values. Save as .png Saves the marker to a .png file. ## Calibration Calibration is used to calibrate the camera positions, this can be done with one camera or multiple. ![stitched video images](_images/stitched-video-images.png) Figure 1. The image shows how a failed calibration look like. It can be seen that 'Image Set 4' has a large error, the image would need to be retaken. Capture Image Set Capture the current frame to use for the calibration. Do Calibration Does a camera rig calibration with the currently captured images. It is available after at least one image is captured. Delete Last Capture Delete the last calibration image taken, only appears after a minimum of 1 image has been taken. Capture Image Sets This tab contains all the images taken of the calibration board and the pixel error for each image. The Images can also be inspected and deleted. ### Advanced Advanced settings for the calibration, recommended is to let them be the default value. ![stitched video advanced](_images/stitched-video-advanced.png) Look For Markers If enabled, the software will look for calibration boards and single markers. Show Board Shows the captured location of the calibration board. Show Cameras Shows the positions of the cameras in the 3D space in relation to each other. Locked Camera Lock one of the cameras so the rest moves in relation to that camera. Locked Forward Lock rotations of the camera selected in the above setting. #### Calibration Board Settings for how the calibration should look like, the supplied calibration board from Voysys use the default values. ![stitched video calibration board](_images/stitched-video-calibration-board.png) Square Length The width of each square on the calibration board. > **NOTE** > If a calibration board has been printed it is important to measure the square size very accurately. Cols The number of columns of aruco markers. Rows The number of rows of aruco markers. > **NOTE** > The displayed calibration board might be flipped so the columns and rows may be inverted. Fill Ratio Set how much of the white area the aruco marker should cover. Dictionary Set which pre-made dictionary to use. Reset To Default Values Sets all values to the default. Save as .png Save the calibration board image to a .png file for printing. #### Single marker Settings for the single marker detection, this marker is used for both calibrations and check calibrations. ![stitched video marker](_images/stitched-video-marker.png) Marker Size The size of the physical calibration board. Dict Size The size of the dictionary with markers that will be created. Marker Bits The number of bits in each dimension for the marker. Marker ID The ID of the marker in the dictionary. Reset To Default Values Resets to the default values. Save as .png Saves the marker to a .png file. #### Calibration Check Calibration check can be used to analyse how good the calibration is, this is done by using the single marker on the backside of the calibration board. If no calibration board is available, it is possible to print one. A .png file can be downloaded from the **Single Marker** tab. Most of the settings are only visible after a calibration check has been made. ![stitched video calibration check](_images/stitched-video-calibration-check.png) Check Calibration Using Marker Pressing this button while having an aruco marker visible by two or more cameras will give a value on how good the calibration is. Force Non-Linear Force the solver to use Non-Linear equations to solve the problem. Show Marker Show a marker where the software has detected them in the video. Marker Images Show an image of the marker on the place the marker was detected. Show rays Show the rays which were used to detect the marker. #### Result Marker ID Show which ID in the dictionary the detected marker has. Result Computed Using Non-Linear Optimization Indicates that the marker position was solved by minimising reprojection error across cameras rather than by simple ray intersection. Shown only when the non-linear solver was used. Distance to Marker Center The distance to the marker center. Marker Position The calculated position of the marker. Residual error The error of the captured marker, larger error means that the calibration is not good. Seen in Camera Shows which cameras that detected the marker during the check. #### Geometry Control Aligns model geometry (primitives added under the Model stitch type) to a marker detected by Calibration Check. For each quad in the model geometry that has an **Id**, a button is available to align that quad to the detected marker’s position and rotation. If no quads with IDs exist, the section shows a hint to add one first. #### Optimization Options Use AprilTag2 Uses the AprilTag 2 algorithm to detect the markers which can give a better result, however, will take more computation time. #### Rig Parameters Very advanced settings about how the camera rig is set up and should not be tampered with if you do know exactly what you are doing. ![stitched video rig](_images/stitched-video-rig.png) Reset Resets the rig parameters. Rig Rotation Rotates the whole rig which includes all cameras. ##### Camera N One subtree per camera in the rig. Most values are intrinsic/extrinsic calibration parameters and should not be hand-edited unless you know exactly what you are doing. Position The camera’s position relative to the rig center, in meters (X, Y, Z). K The camera’s intrinsic calibration coefficients (5-element distortion model). These describe focal length and lens distortion. Offset The image plane offset from the optical center, in normalised coordinates. Corrects for sensor misalignment. Rotation The camera’s orientation as Euler angles in degrees. Max Theta The maximum half-angle from the optical axis that the camera is allowed to project, in degrees. Limits the field of view to avoid sampling invalid peripheral pixels. Horizontal FoV Read-only. The horizontal field of view in degrees, computed from the K matrix and sensor width. Vertical FoV Read-only. The vertical field of view in degrees, computed from the K matrix and sensor height. Diagonal FoV Read-only. The diagonal field of view in degrees. ##### Calibration Manipulation Tools to re-orient the entire rig relative to one chosen camera. The settings are only visible inside a Camera N subtree. Center Position On Camera N Translates the rig so that the selected camera sits at the origin. All other cameras shift by the same vector, preserving relative positions. Center Camera N Rotation on New Forward Rotates the whole rig so that the selected camera’s optical axis aligns with the **New Forward** direction below. New Forward The target forward direction (quaternion) used by **Center Camera N Rotation on New Forward**. ## Stored Calibrations The software ships with some premade calibration for common cameras, by selecting one in the dropdown menu it sets all camera rig parameters. More calibrations can be added to the dropdown menu by specifying a path to a folder containing '.camera' files. More information is described in [Application Settings](application-settings.md) under "Camera Calibration". ### Captured Image Sets ![stitched video captured images](_images/stitched-video-captured-images.png) Inspect Images Open up a new GUI for inspecting the captured images. Delete All Captures Deletes all the captured images. Frame N Each tab shows information about the captured frame. ### Review Calibration Step through the intermediate states recorded during the most recent calibration run. Only visible after a calibration has been made and when the history contains more than one step. ![stitched video review calibration](_images/stitched-video-review-calibration.png) Step Selects which step in the calibration history to view. Step 0 is the initial guess; later steps show successive refinements. Description A text label describing the current step (e.g. **Initial guess**, **Refining cameras**, **Converged**). ### Timed Capture Timed capture can be used to take multiple captured over a period of time. ![stitched video timed capture](_images/stitched-video-timed-capture.png) Count The number of captures that should be captured. Interval The time between each capture. Start Timed Capture Start the timed capture. ## Inputs Input is described in [Video Inputs](video-inputs.md). --- # Streamer Configurator Allows remote access to the Streamer application’s GUI. There are two conditions when it will work: - Output is running (allows Streamer Configurator to be used on computer that receives the stream) - When the output is not started, if the `--configurator` flag is given to the Streamer executable ## How To Connect Add the Streamer Configurator entity to a project containing the Remote Streamer entity. A button will appear where you can connect to the Streamer application. ## Manual Addressing Manual addressing can be used to specify a specific Streamer to connect to directly using its IP address. ## `--configurator` Flag If the Streamer application is started with the `--configurator` flag it can be connected to directly using its **Server Address**. When the `--configurator` flag is used, Streamer applications show up automatically when the Streamer and Player are connected to the same network. A specific bind device can be set through the **Bind Address** setting. ### `--headless --configurator` The Streamer GUI can be accessed through the Streamer Configurator even if the application is running `--headless`. ```shell STREAMER_NAME --headless --configurator /home/username/project/streamer.vproj ``` ### No stop without `--configurator` If changes to be output needs to be done remotely, make sure to use the `--configurator` flag when starting the Streamer application. Otherwise Streamer Configurator will not be able to connect to the Streamer when output is stopped. ## UI Scale UI Scale is not available through the streamer configurator gui. The Player application’s UI Scale setting is used. ## Settings Max Resolution The maximum width and height of the Streamer GUI window, set via the drag control in the top right corner of the entity. Bandwidth Optional target bandwidth (in Mbit/s) for the configurator stream. Can be disabled to let the system pick automatically. ### Manual Address These settings are inside the **Manual Address** tree node and are used for direct address configuration. Server Address Address for the `--configurator` server you want to connect to. Default `127.0.0.1:31000`. Bind Address Bind device address to route data through a specific device. Default `0.0.0.0:0`. The bottom-right corner triangle of the entity can be used to resize the window dynamically. --- # Text Entity Add customizable text objects to the viewport with selectable font and color. ## Use Case Highlighting something on the viewport, differentiating different window selections. ## Settings Text Text to be displayed. Supports multiple lines. Default: "Some nice text!". Color Color of the text. Font Selection of text font. Variant Selects a variant of the chosen font, when the font provides multiple variants. ### Advanced Font Height Change the height of the rendered text, in metres. Default 0.04 m. --- # Video Composition The Video Composition entity is used for joining multiple video inputs into one large texture. The entity does not display the texture by itself but acts as a video source that can be cloned from with [clone stream](video-inputs.md#clone-stream) input. ## Settings ![video composite settings](_images/video-composite-settings.png) Figure 1. The setting UI for Video Composition. Texture Show the joined texture. Save Texture Save the current texture to a .png file. Resolution The size of the output texture. Background The background color of the texture in RGBA color space. Add Source Add a video source to the Video Composition entity. ## Source Settings ![video composite source](_images/video-composite-source.png) Figure 2. The settings UI for for each video source. Source Clone the selected video source to the texture, works in the same way as [clone stream](video-inputs.md#clone-stream). Origin The pixel position where the video source should be placed. The position is the upper left pixel position of the video source. Size The size at which this source is drawn within the output texture. > **NOTE** > A mismatched aspect ratio between **Size** and the source resolution will stretch the image — take care to preserve the source’s aspect ratio. --- # Virtual Camera The Virtual Camera entity is an entity which acts as a camera in the current scene. The Virtual Camera entity can be moved around to direct the view in any direction. The Virtual Camera does not display video by itself, for that you need a 2D video with the Clone Stream input. ## Use case Common usage for this entity is to extract a 2D Video from a Stitched Video or a part of another video source. The output can then be displayed as a 2D surface. In order to improve performance the Only Render setting should be used to only display the relevant objects. ## Settings Keep Aspect Ratio If enabled, keeps the aspect ratio when changing the resolution. Resolution Resolution for the output of the Virtual Camera. Field of View Field of view for the Virtual Camera, in degrees. Default 90°, range 3–150°. Background Set the background color in RGBA color space. Only Render Selects one or more specific entities (by UUID) to render in the camera output. When set, only the selected entities are rendered. This can be used to lower the rendering cost on the CPU and GPU if not all entities need to be rendered by Virtual Camera. Texture Shows current camera output. Save Texture Save the current texture to a .png file. Make View Same As Virtual Camera Moves the view to the same position as the Virtual Camera. This does not change the aspect ratio and fov of the view which need to be manually changed to mimic the Virtual Camera. Set To Current View Set the Virtual Camera to be exactly as the current view. It changes the position, rotation, fov, and resolution to match the current view. The texture of the Virtual Camera will be the same as the user sees in the viewport. --- # AI Inference Oden includes an inference engine based on NVIDIA TensorRT for running neural networks. Requires an NVIDIA GPU (Geforce, Quadro, or Jetson). Networks in ONNX and TRT formats are supported. The system will automatically convert the ONNX model to a device-optimized TensorRT engine at runtime. This process can take several minutes. Once loaded, it is possible to retrieve the inference output using the plugin API. ## Windows Installation Usage of the Inference functionality on Windows requires installation of NVIDIA TensorRT 10 or later, downloadable here: [https://developer.nvidia.com/tensorrt](https://developer.nvidia.com/tensorrt) (login required). Remember to add the lib directory to PATH, as mentioned in the TensorRT docs. ### ONNX Model Import Support In order to import ONNX models into Oden the model needs to be compiled from ONNX to TRT format. This functionality requires CUDA to be installed: - [https://developer.nvidia.com/cuda-downloads](https://developer.nvidia.com/cuda-downloads) ![inference settings](_images/inference-settings.png) Figure 1. The settings UI for Inference ## Settings Add Neural Network Loads a new neural network (ONNX or TRT) IO Tensors Shows information about input/output tensors. Allows the user to select a video stream as input. Info Shows the network UUID and runtime duration. Manually Trigger Enable manual triggering of the network via the plugin API instead of running continuously every frame. --- # Application Settings Application settings are settings outside the scope of a project and will apply changes to the application itself. Window Mode Select the desired window mode: Fullscreen, Windowed, Windowed Fullscreen, or Spanning Fullscreen. For lowest latency choice Fullscreen. Monitor Select which connected monitor Oden should be in windowed fullscreen on. > **NOTE** > Only displayed when **Window Mode** is **Windowed Fullscreen**. Rendering mode Selection of different projection matrices used to project the images onto different displays. Single Projection Single display projection. Separate Projections Multiple display projection where the input image is being projected onto multiple displays. **Contact Voysys for more information on how setup can be done optimally.** Cylindrical May be beneficial if a very narrow display is used and a broad image needs to be projected. **Should normally not be used unless in special circumstances.** Dome Projects the image onto a dome display. Available when a dome renderer is configured. ![projection](_images/projection.png) VSync Screen tearing is a visual artifact in video display where a display device shows information from multiple frames in a single screen draw. Vertical synchronization (VSync) is an option which prevent the video card from doing anything visible to the display memory until after the monitor finishes its current refresh cycle. MSAA Multisample anti-aliasing (MSAA) is a type of spatial anti-aliasing, a technique used in computer graphics to remove artifacts in raster images. Works by simply rendering a scene at a higher resolution, and then downsampling to a lower-resolution output. Scroll Mode Select mouse or trackpad scrolling. Mouse Inverted Invert the input of the mouse when moving objects around in the 3D-engine. Inhibit Mouse Look If true, will inhibit the ability to move around in the view in 3D space with the mouse. GUI Color Mode Select the color template for the GUI: **Oden Accent** or **Monochrome**. Full Project Files If disabled, default values will not be printed to the project file. No Prompt On Exit Show no prompt when closing a project or exiting the program. Only Show Exit Dialog If enabled, when having the GUI hidden and closing the application with for instance "alt + F4" will result in that only the exit dialog will be shown and not the whole GUI. Auto Template Path to a .vtemplate file that will be applied to any project loaded. Camera Calibration Path to a folder containing .camera files. All files in the folder which ends with '.camera' will be loaded into Oden. The calibrations will be available in the dropdown menu under Calibration→Stored Calibrations→Calibration Presets, the name of the file will be the name in the dropdown menu. The path can contain environment variables, for example, %HOME%\\dev\\Cameras\\ is acceptable and will expand the HOME variable. > **NOTE** > The path must end with a slash, i.e. C:\\dev\\Cameras\\ Shrink View When GUI Visible When this setting is enabled, Oden will use the viewport that is visible to the user, and then when hiding the GUI object will move because the viewport gets larger. If this setting is disabled, Oden will use the whole window as a viewport even the area behind the GUI. This will make so the objects do not move around when hiding the GUI. Keyboard Shortcuts In Oden, there are a couple of keyboard shortcuts that can be remapped. Shortcuts combine a button and zero or more modifiers and the available modifiers are ctrl, shift, alt, and super. Modifiers can be stacked by selecting multiple. To disable a shortcut you can select a button called \[Inactive\] which will deactivate the shortcut. ![application settings keyboard shortcuts](_images/application-settings-keyboard-shortcuts.png) --- # Auto Video Packer The Auto Video Packer automatically optimizes the output video stream resolution by analyzing which videos are visible at the OdenVR and how much screen space each video occupies. It then dynamically scales and arranges the video streams into the output resolution, ensuring that each video gets an appropriate amount of resolution based on its importance on screen. This feature is particularly useful when streaming multiple video sources, as it avoids sending full resolution for videos that only occupy a small portion of the operator’s screen. It is recommended to use the auto packer instead of using different scenes for different camera layouts. ## How It Works OdenVR analyzes which videos are visible on screen and how much space each one occupies, then sends this data to Oden Streamer. Oden Streamer uses this information to scale and arrange the videos into the output resolution, allocating more resolution to videos that occupy more screen space. When _Apply Auto Crop_ is enabled, the packer also crops away parts of a video that are not visible on the OdenVR screen, further reducing the output resolution needed. When disabled, the full video is still sent but the screen occupation is estimated from the visible area. The screen analyzer also works through [Virtual Cameras](entity-virtual-camera.md) if they are shown in the viewport. > **NOTE** > Videos not shown are capped to 32 pixels in its longest dimension. ## Limitations - Auto video packer can only handle a maximum of 16 videos. - Layouting of the same video multiple times in the viewport will cause the sent video to be in higher resolution. ## OdenVR The following settings are available in the [Project Settings](project-settings.md) on the OdenVR side: Automatic Video Packing Enables or disables the Auto Video Packer. When enabled, the output resolution and video layout will be managed automatically. Apply Auto Crop When enabled, the packer will take viewport crop into account when calculating video sizes. Use Fixed Streamer Resolution When enabled, a fixed output resolution is used instead of dynamically adjusting the resolution based on the packed content. Fixed Streamer Resolution The fixed output resolution to use when _Use Fixed Streamer Resolution_ is enabled. ## Oden Streamer The Auto Video Packer GUI on Oden Streamer is available in the [Output](streamer-output.md) settings. It displays the following information: Current Output Resolution The current dynamically calculated output resolution (or fixed resolution if configured). Max Streamer Resolution The maximum resolution that the packer can use. This is determined by the output resolution set in the [Output](streamer-output.md) settings. Player Screen Resolution The resolution of the OdenVR screen as reported over the network. > **TIP** > When auto video packing is enabled it is recommended to use _Per Megapixel Bitrate_ instead of a fixed _Target Bitrate_, as the output resolution will change dynamically. See [Output (Streamer)](streamer-output.md). ### Per Video Information Each video source is listed as a tree node showing its name and current scaled resolution. Expanding it shows the following: Resolution The original resolution of the video source. Screen Occupation How much of the OdenVR screen this video occupies, as a percentage. Cropped The crop percentages applied to each side of the video (Left, Top, Right, Bottom). Cropped Resolution The resolution of the video after crop has been applied. Downscale Controls the priority of the video in the packing algorithm (0.0 - 1.0, default: 1.0). Acts as a multiplier on the video’s screen occupation, reducing how much output resolution is allocated to it. Useful for deprioritizing less important video feeds. The effect is only visible when the packer is constrained, i.e. when the combined videos do not fit within the max streamer resolution. Scale The scale factor that the packer has calculated for this video. Scaled Resolution The final resolution of the video after scaling, as it will appear in the output. --- # Audio Streaming The system has built-in one- and two-way audio streaming support available in the Streamer Output and in the Remote Streamer entity. - In Streamer it is accessible under **Output**  **Audio Streaming** - In Remote Streamer it is accessible under **Remote Streamer**  **Audio** > **NOTE** > Linux specifics > > See [Linux audio setup](../configure/audio.md#linux-audio-setup) for instructions. ![remote streamer audio](_images/remote-streamer-audio.png) Figure 1. Overview of the audio settings. Audio Processing Enable Enables the audio processing module. Echo Cancellation Sets the echo cancellation level: None, Low, Moderate (default), or High. Noise Suppression Sets the noise suppression level: None, Low (default), Moderate, High, or Very High. Compression Gain Sets the compression gain in decibels, range 0–90 dB. > **NOTE** > The audio processing module requires the Send `Period` to be 480 frames. Send Use Default Use the default audio recording device. Device The device to use for streaming audio. Period The number of audio samples to capture before sending. Valid values are 120, 240, 256, 480 (default), 512, 960, and 1024. Mode VBR (variable bitrate) or CBR (constant bitrate). Target Bitrate The desired bitrate in kbps, range 6–510 kbps, default 64 kbps. Receive The receiver always uses the default audio playback device. Auto Start Enable to automatically receive audio on project startup. Reorder Buffer Enable to use a buffer for incoming packets. Useful in situations where the network has packet reordering. Reorder Packets The maximum number of packets to keep in the reorder buffer. Default 5, range 0–4096. Receive Buffer The amount of time that the audio playback system is allowed to buffer, in milliseconds. Default 90 ms, range 5–2000 ms. Max Invalid Packets In A Row The number of invalid packets to receive before accepting them as valid. Default 200. Internally, a packet is invalid if it has an older timestamp than the previous packet. That can happen if the network has a lot of packet reordering, reorder buffer can help to mitigate this. It can also happen if the Streamer restarts, in that case, this setting determines how quickly new audio packets are accepted as valid. If you experience choppy playback due to a jittery network, please try to first increase the receive buffer. Around 80 ms usually works fine on 4G networks. If that does not help, try activating the reorder buffer and experiment with the amount of reorder packets. --- # Chroma Key A Chroma Key control is available for some video inputs. When enabled it allows the removal of backdrops etc based on color (chroma) values. ## Adjustment To adjust the chroma keyer: 1. Make sure that the color value of the chroma key color matches the actual green screen color as well as possible. This is done by observing the transparency of the green and changing the color. Remember to also try to change the hue (slider to the right). 2. Experiment with adjusting the **Sensitivity (HSV)**. The sensitivity is in HSV (**h**ue, **s**aturation, **v**alue). It is recommended to have more sensitivity in hue and saturation than in value. 3. Change Threshold: Cut to remove the edge of the things you want to be visible. The cut threshold controls how close to the green screen things will be fully transparent. 4. Change the Threshold: Blend to set the end of the blending region. There is a region from the fully transparent parts of the image to where the things are fully opaque, adjust the blend threshold to give things a smooth nice edge. 5. Experiment with Color Correction and Threshold: Color to remove green fringes from the parts of the image that are to be kept. Color correction subtracts the key color from the parts of the image that are kept. The color threshold controls how far into the image this is done. ## Theory The difference between the chroma key color and the color of each pixel in the target texture is calculated. This distance is weighted based on a sensitivity value, weighting how much of the hue, saturation and value should be used in the filtering. (The threshold value can only be specified in HSV color space.) Example 1. Threshold Values and Their Effects A threshold of `[1.0, 0.0, 0.0]` will only filter on hue (color tone). A threshold of `[0.0, 1.0, 0.0]` will only filter on saturation (intensity of color). A threshold of `[0.0, 0.0, 1.0]` will only filter on value (lightness of pixel / black and white intensity level). The weighted distance from texture pixel to chroma key color is used to apply filtering depending on which region it is in: - Below **Cut**: The pixel is completely transparent - Between **Cut** and **Blend**: The pixel is blended from transparent to opaque - Above **Blend**: The pixel is fully opaque - Below **Color**: The chroma key color is subtracted from the pixel - Above **Color**: The pixel is not changed The Color Correction parameter determines how much of the chroma key color is to be removed from each pixel. --- # Color Handling Internal video and color processing uses a high precision floating point color format. This maintains the input color quality through color and other adjustments. For Stitched Video, there are built in global color adjustments and three levels of color synchronization. There is also support for adding 3D look up tables (LUTs), a powerful tool offering fine grain color control. Proper color format handling is provided and chroma keying is available for Equirectangular Video and 2D Video. > **NOTE** > All color adjustments are post-adjustments - no changes are made to the cameras' internal parameters. ## Color Formats For many video inputs and outputs there is a Color Format selection available. The selections available are: - YCbCr SD Reduced (BT.601) - YCbCr SD Full (BT.601) - YCbCr HD Reduced (BT.709) - YCbCr HD Full (BT.709) The selection determines which color standard to use in the translation from external source/destination and the high precision format used internally. For most destinations and sources the default value will be ok to use. ## Color Look Up Tables (3D LUT) Color look up tables (LUT) are a very powerful way of adjusting colors, common in professional color manipulation tools. 3D LUTs must be in the .cube format. LUTs can be produced and exported from all color grading packages. Here is a possible workflow when working with colors: 1. Synchronize the colors between the cameras 2. Make global color adjustments to achieve a neutral image (i.e. color correction) 3. Apply a 3D LUT to achieve a specific look (i.e. grading) > **TIP** > A LUT can be reused to apply the same "look" to different scenes, as long as color correction is performed before the LUT is applied. ### Manual Color Adjustment It is possible to manually adjust the individual cameras' red, green and blue color gains. This setting is accessible under the **Color**  **Individual Gain Adjustments** node in the property tree of Stitched Video entities. ### Settings Opacity Determine the transparency of the texture. Useful when combining one texture with a background to create the appearance of partial or full transparency. Use LUT Import and use a Look Up Table (LUT). Curve Adjust contrast and brightness of a texture. #### Basic Adjustments Contrast Change the texture intensity in relation to each other. Brightness Change the Brightness of the texture. Gain Amplification of the pixel values overall texture brightness and contrast. Possible to unlock gain control for separate color values. Hue Change which colors to be dominant in the texture. Saturation Change the texture intensity of all the colors. --- # Command Line Arguments ## Headless (Streamer, Linux only) The `--headless` flag runs the Streamer application in headless mode, meaning the GUI is not rendered to the screen. Useful for running Streamer as a service, e.g. on an embedded system such as the NVIDIA Jetson platform. The flag has no effect on non-Linux platforms. ## Configurator (Streamer) The `--configurator` flag enables a Player application with the Streamer Configurator entity to connect to and configure a Streamer, without an active Remote Streamer connection. This is useful when setting up a headless Streamer on a platform without a monitor. ## Windowless The `--windowless` flag runs the Player or Streamer application in windowless mode, meaning that the window is hidden from the user. The GUI sidebar can be toggled with the **Toggle Hide GUI** shortcut (default `CTRL+H`). ## Allow Multiple Streamers The `--multiple-streamers` flag can be set in order to run multiple streamers on the same computer. ## Project The `--project [path]` flag loads the given project file at startup. > **NOTE** > A project file path can also be passed as a positional argument, but in that case it must appear at the end of the command line (after all flags). Otherwise the path may be consumed as a value for the preceding flag. Using `--project [path]` is unambiguous regardless of position. ## Plugin Parameters The `--plugin-param [key] [value]` flag passes a key/value parameter to plugins. The flag may be repeated to pass multiple parameters. ## License Management The `--activate [key]` flag activates the given license key and exits. Combine with `--force` to override an existing activation. The `--revoke` flag revokes the currently activated license and exits. ## Other The `--help` flag prints a list of all command-line arguments and exits. The `--version` flag prints the application version and git hash and exits. --- # Com Channels Com Channels is the built-in communication channel for user-defined messages between the Player and Streamer. The messages are sent over all available links that have been configurated. The protocol used is UDP so the Com Channels have the same limitations as all other UDP messages. Messages can be sent and received both asynchronously and synced to the application frame rate. The Com Channels are used through the Voysys Plugin SDK, please contact your Voysys representative for price and access. ## Link This tab shows all statistics about the Com Channels messages, this includes the number of transmitted/received messages, send rate, last received message, etc. ![com channels links](_images/com-channels-links.png) ## Message Queues Multiple different messages can be received and sent at the same time, either through different plugins or the same. This tab shows all the different messages that are sent/received and how many of each. The message type will be shown with its identifier. The message name is shown on the sender side. ![com channels message queues](_images/com-channels-message-queues.png) ## Advanced For some more advanced use cases, these settings might need to be tuned to make sure that the com channels work properly, but in most use cases the default values will work. Max Packet Size Set the max size, in bytes, of the UDP packet that contains the com channel messages. Default 1400 bytes, range 256–2047. Queue Size There can be multiple threads listening to Com Channel messages. The minimum number of listeners is one, this is the synchronous listener. Each asynchronous listener will be using its own thread. All messages are distributed to all listeners and each listener has a queue size. This value sets the maximum number of messages that each queue can have. Default 512 per thread, range 1–1024. The synchronous queue will be cleared each frame, however, for asynchronous listeners, it is the thread’s responsibility to empty the queue. Limit Send Rate When enabled it will limit how often an asynchronous message send queue can be flushed with the value set in the `Async Send Rate`. Async Send Rate How often an asynchronous message queue can be flushed, in Hz. Default 120 Hz, range 1–10000. Max Invalid Packets In A Row Messages that have timestamps older than previously received are discarded. This setting sets how many messages in a row must be received before it starts to accept those timestamps as the correct ones. Default 25. One case when this can occur is if one Player is connected to one Streamer, the Player disconnects and another Player on a different PC connects to the Streamer. The Streamer will disregard the messages until it has gotten more than `Max Invalid Packets In A Row` messages in a row. ![com channels advanced](_images/com-channels-advanced.png) > **NOTE** > If only synchronous messages are used and the frame rate is low, it could be a good idea to lower `Max Invalid Packets In A Row`, since otherwise it can take a while before messages get through, which can confuse the user. --- # Configuration Files The software stores a few configuration and license files to disk. The files `key.conf` and `license2.lic` contains your application specific license key and the associated license data, respectively. If you are running Oden Dome Player and have a calibrated dome setup, you will have specific files related to that as well. Below are the operating system specific paths to these files. ## Windows System-wide Config `%LOCALAPPDATA%\oden\oden.conf` License Files, Dome Calibration Data, Global Plugin Settings `C:\ProgramData\OdenVR\` `C:\ProgramData\OdenVRDev\` `C:\ProgramData\Oden_Dome_Player\` `C:\ProgramData\Oden_Streamer\` ## Linux System-wide Config `$HOME/.config/oden/oden.conf` License Files, Dome Calibration Data, Global Plugin Settings `$HOME/.config/oden/OdenVR/` `$HOME/.config/oden/OdenVRDev/` `$HOME/.config/oden/Oden_Dome_Player/` `$HOME/.config/oden/Oden_Streamer/` --- # Coordinate System The software uses a right-handed coordinate system. ![coordinate systems right handed](_images/coordinate-systems-right-handed.png) As you can see from the image, this means that -Z is forward, +Y is up, and +X is right. So, if you want to change the position of the viewport camera or entity, you need to follow this system. Positions are expressed in meters and rotations in degrees. --- # HMD Multiple different head-mounted displays (HMD) are supported, with different backends. The following HMDs are tested and known to work well: - Valve Index - HP Reverb G1/G2 - HTC Vive Pro 1/2 Other HMDs will most likely also work, but have not been tested. ## Settings HMD Selection HMD selection is a dropdown menu that specifies which backend should control the HMD. The following are available: - Any - Oculus - OpenVR - OpenXR - None When selecting "None", the HMD functionality will be disabled. When choosing "Any" the first backend that works with the current headset will be used. Fixed Position If enabled, it will lock the HMD position to the origin (i.e. disable XYZ movement in the HMD world). Fps Cam Track HMD If enabled, will make so the view on screen will match what the user sees in the HMD headset. Draw Background If enabled, the background will be shown in the HMD headset, otherwise it will show the default background color of the HMD. Draw While Inactive This setting enables rendering to the HMD screen even if the headset is not currently used by a user. ### OpenVR Settings Info This tab will show some information about the HMD such as model, resolution, and framerate. Tracking Universe How the HMD is currently used (is the user seated or standing) HMD Navigation When HMD Navigation is enabled, the user can move the whole VR world by pressing both trigger buttons on the VR controllers. Magic Window Advanced function that can allow setting the screen projection to appear as a window through which one can look out. It is strongly recommended not to use this feature without consulting with support first. Draw To Screen Disable the rendering to the screen and only render to the HMD. This will reduce the load on the computer in situations where only the HMD is needed. ### OpenXR Settings FoV Factor Multiplier on the FoV in the HMD. It is strongly recommended not to use this as it causes user nausea and fatigue. Show Calibration Cross Show a cross for each eye which can be used to see how well the HMD is placed relative the wearer’s eyes. ### Oculus Settings FoV Factor Multiplier on the FoV in the HMD. It is strongly recommended not to use this as it causes user nausea and fatigue. Oculus Stats Shows information about the Oculus HMD. ### Controller Inputs Settings for HMD controllers Draw Controllers If enabled, will show the controllers in the VR headset. Control Remapping Control remapping allows the user to remap buttons. Hold down any button or move any axis on the controller and click the button that pops up to add a remapping for that specific button. This can be used when using the same plugin with different HMDs where buttons may have different IDs. Each Button and Axes ID can be mapped to any other value that is desired. For example, the default for button **1** is index **1** which contains the value for that button. If the index is changed to **2** the value for button 1 can now be obtained through index **2** instead. ![hmd controller remap](_images/hmd-controller-remap.png) --- # Hardware Decoder The system supports hardware video decoding of AVC (H.264), HEVC (H.265), AV1, and MJPEG video on NVIDIA (GeForce, Quadro, Jetson), Intel, and AMD (Linux only) platforms. Up-to-date drivers are required for correct operation. ## Windows ### NVIDIA Go to [https://www.nvidia.com/Download/index.aspx](https://www.nvidia.com/Download/index.aspx) and download the latest drivers for your GPU. ## Linux ### NVIDIA Run the following commands to install the (at the time of writing) latest stable NVIDIA drivers. ```bash sudo add-apt-repository restricted sudo apt-update sudo apt-get install nvidia-driver-580 ``` ### AMD Follow the instructions at [https://www.amd.com/en/support/download/linux-drivers.html](https://www.amd.com/en/support/download/linux-drivers.html) for the latest drivers. ## Settings There are some hardware decoder specific settings for supported video inputs. Skip Frame Drops the selected number of frames in a row before decoding. This results in a slower frame rate but eases the load on the decoder. The use case is to reduce latency from a camera by running the camera at a higher framerate than is used for streaming. MJPEG only. --- # License Management License activation requires the computer to be connected to the internet. **One license can be activated on one (and only one) machine at the time.** After a license is activated, the machine no longer needs to be connected to the internet for a certain amount of time (depends on license level, typically 4 weeks). A warning is displayed both on licenses that are soon expiring and on licenses that soon need to be activated online again. The activation of a license will transfer data uniquely identifying the PC that the software is installed on to Voysys. Licenses are handled in the **Help** menu. See [Activate licenses](../start/activate-licenses.md) for the step-by-step activation flow. To transfer a license to another computer first use **Help**  **Revoke current license**. Then use **Help**  **Enter new license key** on another computer. --- # Matte Key A Matte Key control is available for some video inputs. When enabled it uses a separate image or video source as an alpha mask: areas where the matte is dark become transparent, and bright areas remain opaque. Type Selects the matte source. - **None**: Matte Key is disabled. - **Video**: Use another video source in the project as the matte. - **Image**: Use an image file as the matte. Source When **Type** is **Video**, selects which video source to use as the matte. Image File When **Type** is **Image**, opens a dialog to select the matte image. Supported formats: .png, .jpg, .jpeg. --- # Movement While holding the left mouse button, press 'W', 'A', 'S' or 'D' to move the viewport camera forward, left, backward or right, respectively. Press 'Q' to move down and 'E' to move up. Hold Shift while moving to multiply the camera speed by 10, or Shift+Alt to multiply by 100. Hold Ctrl to divide the speed by 10, or Ctrl+Alt to divide by 100. Press the home icon or use the (by default) Ctrl+Q shortcut to return the viewport camera position to the origin. --- # Network The network system can be configured in multiple ways depending on your network setup. By default, the Streamer acts as the initiator of the connection and the Player acts as a responder. Also, a single link is used by default. In this setup, the receive port of the Player must be accessible by the Streamer. ## Settings ![remote streamer network](_images/remote-streamer-network.png) Figure 1. Network settings overview. Bind IP The IP address to bind to when opening the network socket. If nothing or `0.0.0.0` is specified, the address will be assigned automatically by the operating system. Bind Device Linux only. This means that all traffic associated with this link will go through the specified interface. Be aware that this also effectively bypasses any configured network routes on the system. Mode The link mode to use. An Initiator link will try to initiate the connection. A Responder link will listen and then reply to traffic from an Initiator link. More technically, this means that an Initiator link can be behind a NAT and the Responder link must be on a public IP. This restriction can be circumvented by using encryption and routing through a WireGuard server, see [Encryption](#encryption). ### Responder Link Receive Port The network port used to listen to incoming traffic. ### Initiator Link Destination Addr. The address of the corresponding Responder link. Can be either a domain name or an IP address. Destination Port The receive port of the corresponding Responder link. ## Link Stats ![remote streamer link stats](_images/remote-streamer-link-stats.png) Figure 2. Link Stats. If you enable link stats you get the following stats for each link. The first section shows the incoming and outgoing bandwidth categorized by the traffic type. The second section of the link stats shows a graph where each column is a frame and each pixel in that column is the relative timing of a packet in that frame and the top red pixel shows when the first packet of the next frame arrived. ## Encryption ![remote streamer encryption](_images/remote-streamer-encryption.png) Figure 3. Overview of the encryption settings. The encryption tab configures encryption and authentication of the traffic that the application sends using the WireGuard protocol. To set up encryption, first configure the local key pair, then add the public keys of each peer you want to allow communication with. If traffic is relayed through a WireGuard server, the Internal src./dst. settings under **Advanced** must also be configured. Enable Turns encryption on or off for this link. ### Private Key Generate Key Pair Opens a save dialog to generate a new private/public key pair and store it on disk. Set Key Pair Path Opens a file dialog to load an existing key pair from disk. Key Pair Path Path to the key pair file. Can be set directly or filled in by the buttons above. Public Key Read-only view of the public key derived from the loaded key pair. Share this with peers so they can authenticate traffic from this application. ### Allowed Public Keys A list of public keys for the remote endpoints that are allowed to communicate with this application. Use **Add** to append a new entry and **Remove** to delete one. Up to 16 keys can be added. > **NOTE** > Initiator links only use the first public key in the list. ### Advanced Internal src. When relaying traffic through a WireGuard server, set this to the internal IP address of the local endpoint as configured in the WireGuard server. Internal dst. When relaying traffic through a WireGuard server, set this to the internal IP address of the remote endpoint as configured in the WireGuard server. ## P2P P2P enables a link to automatically transition to a peer-to-peer connection if possible. This is useful in order to reduce network latency if connected over a WireGuard server. This has no effect if the connection is already peer-to-peer. Enable Enables the P2P negotiation STUN Server STUN server used to detect the client WAN IP and port. The default server `stun.l.google.com:19302` is freely provided by Google and used for WebRTC in Google Chrome. --- # Output (Streamer) Start/Stop Start and stop the video streaming Resolution Output video resolution. The content of the viewport will be encoded to this resolution Sync to Video Use this to sync to your primary camera to get the lowest latency possible. In a scenario where there is no specific primary camera, for instance when swapping scenes for forward and reverse driving, it is recommended to use our SDK for changing the camera to sync on. Source Syncs the output to the specified video source. Make sure that the selected video source has a frame rate between Max Fps and Min Fps. Max Fps Frame rate is capped to this. Default 70. Min Fps Frame rate cannot go lower than this. Default 10. Frame Rate Output frame rate. Target Bitrate Target encoder bitrate (in Mbps), or maximum bitrate if Bandwidth Control is enabled. Default 10 Mbps. Use FEC Enables Forward Error Correction. Fec Amount Percentage of video data to also send as redundant packets. Min extra packets Minimum FEC packets to send. FEC Bad Link Fade Advanced: Controls how fast the system should classify a link as bad. Encoder Settings Use the default values for optimum latency to performance ratio. Codec Supported codecs are H.264, H.265/HEVC, and AV1. H.265/HEVC is recommended for most use cases. Bandwidth Control Automatically adjusts encoder bitrate depending on network conditions. Requires feedback from a Remote Streamer entity on the Player side. Auto Mode Switch Adjusts output resolution and frame rate dynamically. Can be useful in very poor network conditions. Save Coded Data To File Writes the encoded bitstream to disk at the selected path. ## Audio Streaming See [Audio Streaming](audio-streaming.md) ## Auto Video Packing See [Auto Video Packer](auto-packer.md) --- # Plugins Plugins can be used to extend functionality. This could be everything from integration with a vehicle to displaying information in the 3D view. Plugin files are dynamic library files that have the file ending .dll on Windows and .so on Linux. Plugins can also extend the sidebar GUI which makes it easier to interact with the plugin as shown in the image below. ![plugins overview](_images/plugins-overview.png) To get more information about SDK pricing and how to write plugins, please contact your Voysys representative. ## Types of plugins There are two different kinds of plugins that can be added: **Project Plugins** and **Global Plugins**. In the GUI, the plugin lists are grouped under three headings: **Program Plugins** (plugins loaded from the application or `additional_plugin_path` directories), **Project Plugins** (plugins loaded from the project’s plugin paths), and **Global Plugin Instances** (running instances of global plugins). Project Plugins **Project Plugins** are specific to a certain project file. The plugin will only run after it has been added to the project scene graph. The plugin will be visible to the user as an entity and is added to the project in the same way as any other entity. Global Plugins **Global Plugins** are different from **Project Plugins** in that they are not added to the scene graph. All **Global Plugins** that the software can find will be running regardless of which project is loaded. A **Global Plugin** can be used, for example, to change the project depending on an external signal. ## Adding plugin to your project Adding a plugin file to your project is simple, but depending on whether it is a **Project Plugin** or a **Global Plugin** the steps are different. Project Plugins Add a folder next to the project file and put the plugin files into that folder. Add an entry under the _Plugin Paths_ setting that points to the created folder, then save and reload the project. Now when pressing the _Add Child_ button the plugins are visible at the bottom of the list. Global Plugins Global plugins are loaded at application startup. The dynamic library file must be located in the same directory as the Player or Streamer executable, or in the directory configured by the application setting `additional_plugin_path`. ## Settings Program Plugins The plugins that the software finds in the application directories (next to the executable and in `additional_plugin_path`) are shown here. Each dynamic library file can contain multiple plugins, and to see which plugins are available in each file the tab can be opened. Project Plugins The plugins that the software finds in the _Plugin Paths_ are shown here. Each dynamic library file can contain multiple plugins, and to see which plugins are available in each file the tab can be opened. Global Plugin Instances All global plugins will be visible here. If the global plugin has any GUI elements that can be changed they will be visible here. Plugin Paths A list of paths to folders containing the plugins for the project. Paths can be added or removed. When no path is given, the software looks for plugin files in the same folder as the project file. Paths can be relative or absolute in relation to the project file. There is support for using environment variables, which can be used to have cross-platform projects. To use an environment variable in your path, put the name of the variable between two percentage signs (e.g. `%HOME%`). To see the expanded path, hover over the input box. ![plugins path](_images/plugins-path.png) Figure 1. Expanded plugin path. Hot Reloading When enabled, the software checks if the plugin has been updated and reloads it without the need to reopen the project. A restart of the application is required for changes to this setting to take effect. > **NOTE** > Use of Hot Reloading in production is strongly discouraged. ## Plugin Troubleshoot Guide In the event that a plugin does not show up in the Entity list, follow these steps: ### Windows 1. Dependencies 1. Download and run [Dependencies GUI](https://github.com/lucasg/Dependencies/releases) 2. Open your plugin DLL in Dependencies 3. Look for any unresolved dependencies 2. If the plugin still doesn’t show up, make sure that the plugin is either in the specified _Plugin Paths_ under the Settings header, or in the installation directory 3. Make sure that you use a unique entity ID for your plugin ### Linux 1. Dependencies 1. Open a terminal window in your plugin directory 2. Call `ldd -r -d ./${PLUGIN_PATH}.so` where `${PLUGIN_PATH}` is the path to your plugin 3. Look for any dependencies that are not met and resolve them by installing the appropriate libraries 2. If the plugin still doesn’t show up, make sure that the plugin is either in the specified _Plugin Paths_ under the Settings header or in the installation directory. 3. Make sure that you use a unique entity ID for your plugin --- # Project Settings Project settings contain settings that will be saved to the project file. ![project settings](_images/project-settings.png) ## Settings Background Sets the background mode. There are three different modes: - Default - Default, Only For Orbit Camera - Color Background Color Sets the color for the background in the view. Camera Eye If the project is set up to render different videos to different eyes in e.g. a head-mounted display (HMD), this setting selects which eye is rendered in the viewport on the monitor. Options are **All**, **Left**, or **Right**. Show Grid Selects when a grid is displayed in the view. Options are **Always**, **Only For Orbit Camera**, or **Never**. Grid Height Sets the height (in metres) at which the grid is rendered. Force Feedback Enables force feedback for joysticks that have support for it. Startup Scene Sets which scene in the project that will be launched on startup. ### Auto Video Packing See [Auto Video Packer](auto-packer.md) for settings and a detailed description of the feature. ### View Field of View Sets the field of view of the viewport camera. Position Sets the position of the viewport camera in the 3D space. Rotation Sets the rotation of the viewport camera. Reset View To Project Default Resets the camera settings to the default for the project. Set View As Project Default Sets the current view to be the default view in the project. #### Saved States Save Current State Saves the current state of the view so it can be selected through the 'Saved State' drop down menu. Saved States A saved state can be selected through this drop down menu. Clear All Saved States Removes all saved states from the list. --- # Raw Recording Record all video sources and have the ability to record custom data. For example, control signals in plugins. Single video sources can also be recorded. ## Use Case A raw recording can be used to playback scenarios that have been recorded. For example, if the developer does not have access to the vehicle for testing. ## Recording Start the recording by clicking the **Start Recording** button. The recording will be saved to the destination folder. Destination folder Folder where the recorded video and playback project will be saved to. Create Folder Create a folder on save containing the files of the raw recording. Frameskip Skips frames to reduce framerate in recording to save disk space. Use Ringbuffer Set maximum disk space to be used for recording. When max disk space usage is reached the oldest frames are overwritten. Use Time Based Ringbuffer Changes the setting for max recording to be dependent on the time period of the recording instead of the disk space usage. Size-based and time-based ringbuffers can both be active at the same time. ### Single Entity Raw Recording It is also possible to record a single entity. This will only produce a raw recording of that specific entity. ## Playback To play a raw recording, open the folder containing the raw recording project (.vproj) file and open it. Under **Raw Recording Playback** settings will now appear and the recording playback can be started. Loop Checkbox if the recording should loop. Loop Start/Stop Time Start and stop time of the loop sequence. Min Recording start time. Max Recording stop time. Time Date and time of when the recording was recorded. ### Extract Frames to Disk Extract frames in recording for a specific entity. Start capture by selecting an entity in the drop down menu and pressing the start extraction button that appears. The captures are taken base on the intervals setting configuring the time between captures. If a delay between the frame captures is desired, the wait time setting can be used to delay the frame capture. Destination Folder Folder where the extracted frames will be saved to. Interval Time between frame captures. Wait Time Wait time between intervals. Extraction Frames Number of frames to be extracted. Entity Which entity the frames should be extracted from. ## Important Notes (Corrupted Recording) If the software crashes or is exited while the raw recording is started, the recording might result in corrupted video streams. Make sure to stop the recording before exiting. If the software is started through the terminal and CTRL+C is used to stop, the recording might also be corrupted. ## Conversion .vraw → Other Formats Voysys raw (.vraw) recording format can be converted to other formats using ffmpeg by using the tool provided at [https://github.com/voysys/vraw\_convert](https://github.com/voysys/vraw_convert). --- # Scenes and Entities ## The Scene Graph and its Possibilities Similar to many game engines and 3D applications, a scene in this software is created via a scene graph. All objects in the scene graph are called entities. There is a root entity and everything in the scene will have either the root entity or a descendant of it as its parent. Below most nodes it is possible to add new nodes. This is done by selecting the intended parent node and then clicking the Add Child button. It is also possible to rearrange nodes in the scene graph by clicking and dragging them. All entities have a position, a rotation and a scale. The positions are in meters, the rotations are in degrees and the scale is unitless. Parent parameters are applied to child entities. > **TIP** > It is recommended to add multiple types of entities in a scene graph side by side, as siblings under a common parent (and not put them as children under children). The reason for this is that it is easier to control rotations and positions of side-by-side items. It is recommended to take some time exploring the possibilities of what can be created by adding different types of entities and positioning them in 3D space. ## Entity grouping and positioning Content-less entities (simply called Entity in the Add Child menu) offer a way of organizing the scene graph. Because parent position, rotation and scale parameters are applied to children it is convenient to group some types of entities together in this way. > **TIP** > It is a good idea to group multiple 2D Videos and graphics entities that are intended to stay together under a common parent content-less Entity. Another convenient use of content-less entities is when positioning items. By placing an entity that is to be positioned as the child of a content-less entity there are two sets of rotation, position and scale parameters. The parent (a content-less entity) can position and rotate the child entity to the intended position. The child entity is then rotated in position using its rotation parameters. This can solve certain "gimbal lock" type issues, and in general makes positioning easier. --- # Statistics Statistics tab showing different statistic measurements of the application and entities. ## Performance Metrics Showing the number of milliseconds each rendered frame takes. Average, max and standard deviation is measured for update, draw and GUI loops as well as the total sum of the entire frame. If a plugin is present the metrics is shown for that entity. The graph is plotting the different measured metrics for visual inspection. Frame Time Time for the entire frame. Update Time for update loop. Draw Time for draw calls. Encode Time spent encoding video output (Streamer only). GPU Draw Time spent on the GPU rendering the frame. GUI Time to render GUI. Main thread Listing the main thread CPU load on rolling average. When plugins are loaded, each plugin’s update time is also listed. ## Frame Time Monitoring Monitoring of frame time with a settable threshold. A message is printed to the console each time the frame time is above the threshold with the update, draw, encode and gui metrics. A counter of overruns is shown alongside the setting, with a button to reset it. ### Settings Active Activate the monitoring. Threshold Frame time threshold, in milliseconds. Default 20 ms, range 0–10000 ms. --- # Stitching The GPU assisted automatic stitching mode (GPU Auto) offers control over how the algorithm works. The size and resolution of the depth map can be controlled in four increments: - Low (default) - 64x32x16 - Medium - 128x64x24 - High - 256x128x32 - Ultra High - 512x256x32 > **WARNING** > Increasing the size and resolution of the depth map will have a large impact on the rendering of Stitched Video entities and may cause frame drops. Two distance parameters can be set under the Options node, controlling the minimum and maximum distance that the GPU Auto algorithm will generate in the automatic geometry. It can be a good idea to change these distances depending on what the surrounding looks like. ## Manual Adjustments In some instances GPU Auto will not deliver a perfect stitch. It is possible to manually adjust the stitching in local regions of the scene. 1. Expand the **Stitching**  **Manual Geometry Adjustment** node in the property tree of the Stitched Video entity in the Scene Graph 2. Use the available options to adjust the stitch geometry It is possible to add many manual adjustment regions. It can be a good idea to first add a large region to a problematic area and then smaller regions on top of the larger one. > **CAUTION** > The manual adjustment regions overrides the automatic stitching. **The stitching under a manual adjustment region will not be automatic.** ## Stitch Zone Position Control It is possible to control where the stitch zone is for overlapping cameras. 1. Expand the **Stitching**  **Stitch Zone Position Control** node in the property tree of the Stitched Video entity in the Scene Graph 2. Select the cameras with the stitch zone to be adjusted 3. Click **Add Controls For Camera Pair** to add a control 1. A control for the selected cameras will appear 4. Drag the adjustment value to move the stitch zone --- # Video Inputs Multiple different video inputs are supported. Some will work straight out of the box while others will need additional drivers. Some video inputs are only available on certain platforms but that is stated in the list below. If you have a question about support for certain video input, please contact your Voysys representative. All video inputs have a few settings in common. ![video inputs common settings](_images/video-inputs-common-settings.png) Figure 1. Common settings for video inputs. ID Set an ID on the input to differentiate between multiple inputs. Name and color can be selected for each input. Texture Preview of the texture. Save texture Save the current texture to a .png file. ## Argus (Jetson only) Captures video from cameras connected to NVIDIA Jetson platforms via the Argus / libargus EGL stream API. Provides direct control over the on-board ISP (exposure, gain, white balance, denoise). Camera Selects which connected Argus camera to use. Mode Selects a sensor mode (resolution and frame rate combination) supported by the chosen camera. Start/Stop Starts or stops capturing from the selected camera. Auto Exposure When enabled, the ISP controls exposure automatically. When disabled, the exposure time can be set manually. Exposure Time Manual exposure time, in milliseconds. The valid range depends on the sensor. Auto Analog Gain When enabled, analog gain is controlled automatically. When disabled, the gain can be set manually. Analog Gain Manual analog gain. The valid range depends on the sensor. Auto Digital Gain When enabled, digital gain is controlled automatically. When disabled, the gain can be set manually. Digital Gain Manual digital gain. The valid range depends on the sensor. Exposure Compensation Available when any auto control is enabled. Biases the auto-control target value up or down. AWB Mode White balance mode. Options: **Off**, **Auto**, **Incandescent**, **Fluorescent**, **Warm Fluorescent**, **Daylight**, **Cloudy Daylight**, **Twilight**, **Shade**, **Manual**. WB Gain Per-channel white balance gains (R, G even, G odd, B). Available when **AWB Mode** is **Manual**. Saturation Optional control over the ISP saturation level. Optical Black Optional per-channel black-level offsets. Antibanding Mode Flicker reduction. Options: **Off**, **Auto**, **50 Hz**, **60 Hz**. Denoise Mode ISP denoise. Options: **Off**, **Fast**, **High Quality**. When not **Off**, **Denoise Strength** is available. Edge Enhance Mode ISP edge enhancement. Options: **Off**, **Fast**, **High Quality**. When not **Off**, **Edge Enhance Strength** is available. Camera Crop Adjust the active sensor region (offset and size) used for capture. ## Clone Stream The Clone Stream input clones the video stream from another entity. This is useful when only one video input can be connected to a certain interface at the time. In some instances clone stream is necessary, for instance to get the video from a [Remote Streamer](entity-remote-streamer.md) or [Virtual Camera](entity-virtual-camera.md). Source Which video source that this input should clone from. Focus Region Enable [focus region](entity-2d-video.md#focus-region). Copy To Texture By default, Clone Stream uses the original video source texture when displaying it along with any filters. Copy To Texture changes this behavior to instead make a copy of the cloned texture. This also enables the hard crop functionality. When copy to texture is enabled you can modify any filter applied without changing the source video filter. Hard Crop Crops the size of the texture in GPU memory instead of cropping it during display. ## Direct Show (Windows only) Direct Show is a Windows API for capturing and displaying video sources. It supports many different camera devices. > **NOTE** > If a dedicated input type exists for a device, use that instead for improved performance and lower latency. For example NDI. Device Name The available devices that can be captured. Rescan Devices Rescan for new devices. Rescan And Show All Devices Rescan for new devices and showing all found devices, including devices that we do not recommend using with Direct Show. Resolution The video resolution. Capture Rate Different resolutions can have a specific range of available frame rates. This sets the range and the frame rate setting sets the specific frame rate for the input. Frame Rate The frame rate of the video. Pixel Format The video pixel format. Different pixel format can have different performance. Retry If enabled, the software will continue to try to connect to the camera if it is disconnected, e.g. if a cable is pulled out and then inserted. ## Display Capture Will capture the selected screen. Cursor If enabled, the cursor will be visible in the display capture. Monitor Selects which monitor should be captured. ## FFmpeg A generic FFmpeg-backed input. URL The source URL or path. Input Format Optional explicit FFmpeg input format name (e.g. `mpegts`, `flv`, `rtsp`). Leave empty to let FFmpeg auto-detect. HW Acceleration Enables hardware-accelerated decoding when supported. Live Source When enabled, treats the source as a live stream. Disables looping and seeking. Src Open Timeout Time to wait for the source to start, in seconds. Useful for slow-to-respond sources. Buffer Time Amount of buffered media to keep, in seconds. Loop Loops the source when it reaches the end. Inactive when **Live Source** is enabled. Auto Start Starts the source automatically when the project loads. Options A list of additional `name`/`value` pairs passed to FFmpeg as input options. Use **Add** to append, **Remove** to delete an entry. Playtime Master Optionally synchronise playback time with another FFmpeg input in the project. ## File Plays back a video file (MP4, MKV, AVI, WebM, etc.), with seek and playback controls. Open File Opens a file picker to select the video file. Close Unloads the current file. HW Acceleration Enables hardware-accelerated decoding when supported. Loop Loops the file when it reaches the end. Play On Transition Resumes playback when the scene becomes active. Auto Start Starts the file automatically when the project loads. Buffer Time Amount of buffered media to keep, in seconds. Play / Pause Toggle playback. Play Time Current playback position, displayed as HH:MM:SS.MS. Drag to seek. Progress slider Drag to seek within the duration of the file. ## Flir (Spinnaker) This is the video input for capturing FLIR cameras (USB3 Vision). This input requires a driver to work, contact your Voysys representative to get information about which version is compatible. Try to Reconnect If enabled, will try to reconnect to the select camera if disconnected. Start/Stop Start and stop the camera. > **NOTE** > Only appears after a device is selected. Rescan Devices Rescans the devices on the interfaces that already has been detected. Rescan Devices and Interfaces Rescan devices as well as scanning for new interfaces. Device The available devices. Custom Resolution Make custom resolutions available for the user. Resolution The video capture resolution. Pixel Format The pixel format the camera will send. Not all formats are available on all cameras. Auto Frame Rate If enabled it will automatically set the camera to the highest possible frame rate. Frame Rate The frame rate of the camera, the camera interface does not show available frame rates so we refer to the camera specifications. The console will output an error if the frame rate is not supported. This settings is only visible if "Auto Frame Rate" is disabled. Advanced Center Image When using a resolution lower than the maximum, the camera will send a subset of the image. If "Center Image" is enabled it will put the subset in the center. If disabled, the user can set wherein the sensor the subset should be taken from by changing the "Offset X" and "Offset Y" variables. Binning Binning combines pixels on the camera which makes the image from the camera smaller but uses a larger part of the sensor. This is useful when wanting to reduce the data transmitted from the camera but still get the image from the whole sensor. When changing the binning, the resolution must be changed also. It means that if the max resolution is 3000x4000 pixels and binning is set to 2x2 the selected resolution must be the max resolution divided by the binning, i.e 1500x2000 pixels. Auto Exposure Enables the auto exposure, depending on its state different settings can be set. Enabled If auto exposure is enabled a tab with settings will be visible. It gives the user the ability to set a minimum and maximum value which the auto exposure can work in between. This setting might be needed to make the camera reach its highest frame rate since the minimum exposure time could be too long by default. ![video inputs auto exposure](_images/video-inputs-auto-exposure.png) Figure 2. Auto exposure settings. Disabled When auto exposure is disabled, the user can set the exposure time as well as the gain manually. ![video inputs auto exposure disabled](_images/video-inputs-auto-exposure-disabled.png) Auto WB If enabled, auto-corrects the white balance. When disabled, settings for manually adjusting the white balance are available. Buffer Count The buffer count is the amount of frames the camera can buffer if the software does not read the frame quick enough, for example during a frame stutter. It is recommended to use the default value. Reset on Startup Resets the camera on startup, this can help with weird behaviors such as when the camera is stuck in a specific USB speed mode. This can make the startup of the camera slower. Reset Camera Resets the camera, can be used if the camera is misbehaving. This operation takes a while! ## GigE Receives video from GigE Vision cameras using the GenICam protocol over Ethernet. Serial / IP Select the camera by serial number or IP address. The list is populated from discovery on connected interfaces. Capture Type How frames are received from the network. Options: - **Socket** — standard UDP sockets. Highest compatibility. - **Pcap** — uses libpcap (available when the binary is built with pcap support). - **Oden Filter Driver** — Windows-only, uses the Voysys kernel filter driver for the lowest CPU overhead. Access Mode **Exclusive** takes full control of the camera. **Monitor** taps into the multicast stream from another (master) receiver without configuring the camera. Settings Master Optionally slave this camera’s settings to another GigE input in the project, so changes apply to both. GenICam Parameters A dynamic list of camera-specific parameters exposed by the connected device (exposure, gain, ROI, trigger modes, etc.). The exact set depends on the camera model. Multicast Interface When **Access Mode** is **Monitor**, selects which network interface to receive multicast traffic on. Restart on Stall Automatically reconnects if no frames have been received for a few seconds. Frame Completion Settings Acceptable Issue Ratio A frame is delivered as long as at least this fraction of its packets arrived. Frames with fewer packets are dropped. Default 0.7. Clear Buffers To Black Fill any missing pixel data in incomplete frames with black instead of leaving the previous frame contents. Filter Driver tuning Max Packets Per Transfer Number of packets read per kernel transfer (Oden Filter Driver only). Buffer Size Size of the kernel ring buffer used by the filter driver. ## GStreamer This input will take a regular Gstreamer pipeline and input the video data to Oden. The video data will be put to the `odenvideosink` plugin, the sink can be added into the pipeline as `! odenvideosink processing-deadline=0` or be left out. If it is left out Oden will add it internally. Start Starts the pipeline. HW Decode Enable or disables the hardware decoder for the input. Codec Set the codec for the hardware decoder, available selection is H.264, H.265 and MJPEG. Advanced Exclusive Start Enable exclusive start, sets a time between when different pipeline should start so only one starts at a time. Exclusive Start Duration Time between pipeline starts. Exclusive Start Priority Sets priority, lower number starts earlier. Sync On Sink Sets the property `sync=true` on the gstreamer pipeline if enabled. ![gstreamer](_images/gstreamer.png) Figure 3. Gstreamer input ## HLS Receives HTTP Live Streaming (HLS) playlists in real time. URL The URL of the `.m3u8` playlist. HW Acceleration Enables hardware-accelerated decoding when supported. Src Open Timeout Time to wait for the source to start, in seconds. Buffer Time Amount of buffered media to keep, in seconds. Auto Start Starts the source automatically when the project loads. Start / Stop Begins or ends reception. ## IDS Captures video from IDS uEye cameras (USB3 and GigE), exposing the manufacturer’s image-processing controls (exposure, gain, white balance, trigger modes). Device The IDS camera to use, listed by serial number. Re-init Retries camera initialization. Capture Rate Frame rate, in Hz. The valid range depends on the current sensor configuration. Auto Exposure When enabled, exposure time is controlled by the camera. When disabled, **Exposure Time** can be set manually. Exposure Time Manual exposure time, in milliseconds. Auto Gain When enabled, gain is controlled by the camera. When disabled, **Gain** can be set manually. Gain Manual gain, range 0–100. Auto Reference Target brightness for auto exposure/gain, range 0–255. Auto Speed How aggressively auto exposure/gain reacts to brightness changes, range 0–100. Auto Hysteresis Tolerance band that prevents oscillation around the **Auto Reference** value, range 0–10. White Balance White balance algorithm. Options include **Auto (Kelvin)**, **Auto (Grayworld)**, **sRGB D50/D65**, **CIE RGB E**, **ECI RGB D50**, and **AdobeRGB D65**. Color Temp Manual colour temperature in Kelvin, when applicable. The valid range depends on the camera. Trigger Mode How frames are triggered. Options: - **Normal** — software trigger; the camera streams continuously. - **Master** — the camera outputs a PWM signal that can drive other cameras. - **Slave** — the camera is triggered by an external hardware signal. Slave To When **Trigger Mode** is **Slave**, select which other IDS camera (in Master mode) acts as the trigger source for synchronised exposure. ## NDI Receives NDI (Network Device Interface) streams from compatible senders on the local network. Device The NDI source to receive from. The list is populated from the local NDI source registry. Quality Bandwidth versus quality trade-off. Options: **Lowest** or **Highest**. Start Begins NDI stream reception. ## RTMP Receives RTMP (Real-Time Messaging Protocol) streams. URL The RTMP URL, e.g. `rtmp://host/app/stream`. HW Acceleration Enables hardware-accelerated decoding when supported. Loop Loops the source when it reaches the end (only meaningful for sources of finite duration). Auto Start Starts the source automatically when the project loads. Open Timeout Time to wait for the source to start, in seconds. Buffer Time Amount of buffered media to keep, in seconds. Start Begins reception. Play / Pause Toggle playback, when the stream has a known duration. Play Time Drag to seek within the stream, when seekable. ## RTP Receives raw RTP (Real-time Transport Protocol) packets on a UDP port. Codec The codec of the incoming stream. Options: **MJPEG** or **H.264**. Port UDP port to listen on, range 0–65535. Start / Stop Begins or ends reception. ## RTSP Real-Time Streaming Protocol(RTSP) is a network protocol for video and audio which is often used by IP cameras. ![video inputs rtsp](_images/video-inputs-rtsp.png) Start Start receiving the RTSP stream with the current settings. Url The url to the RTSP server should have similar structure as the following URL `rtsp://127.0.0.1:8554/live`. The structure of the URL consist of an Ip address, a port number and which stream from the server that should be listen to, which is the 'live' part of the example URL. Video Enable or disable the video from the stream. Codec Which incoming codec that the stream uses. Currently supported are H.264 and MJPEG. H.265 over RTSP requires the GStreamer RTSP variant (use "Convert To Raw GStreamer Pipeline" under Advanced). Audio Enable or disable the audio from the stream. Username Some RTSP server requires a username. Password Some RTSP server requires a password. ### Advanced Convert To Raw GStreamer Pipeline Converts all settings to a pure GStreamer pipeline. Sync On Sink GStreamer gives a timestamp when the frame should be displayed, if 'Sync On Sink' is enabled then the frame is presented when the timestamp occurs. > **NOTE** > For live feeds, it is recommended to have 'Sync On Sink' set to disabled. However, for prerecorded video, it is recommended to have it set to enabled. HW Decode Enables the hardware decoding for the codec. ## Spout (Windows Only) Spout is a frame sharing system for Windows. It can receive the texture from other programs that have implemented the Spout protocol. Spout shares the textures over the GPU which means that both systems must use the same GPU. Performance can differ if the sending program uses DirectX since not all GPUs have support for DirectX to OpenGL texture transformation. Whether the GPU has support for it is shown under the 'info' tab. Source The available Spout source that is currently sending on the system. Use Alpha Channel Some programs might use alpha values that does not follow the standard format, therefor this button enable/disable the use of the alpha channel. Log Spout Messages Logs the Spout messages to file, the file will be located in the same location as the project file. Hover over the button to see the exact location. Info Some info about the system and the Spout capabilities. ## Test Source Test source is a video input that contains multiple different videos that can be used as a placeholder for a camera. Resolution The resolution of the test source. Pattern The available pattern to choose from. > **NOTE** > Some of the patterns are static which will make the drop detector kick in, turn off the drop detector when using those! ## V4L2 (Linux only) Video for Linux version 2 (V4L2) is an API for realtime video capture on Linux systems. It supports many USB webcams and other camera devices. Device The camera you want to receive video from. Pixel Format The video pixel format. Resolution The video resolution. Frame Rate The video frame rate. Controls Displayed when the video input is active. Controls various aspects of supported cameras, such as exposure time, brightness, contrast, etc. Advanced Blocking Mode Block and wait for the camera to send us an image. Necessary for certain cameras. Try enabling if you have issues receiving video. Retry Until Success Repeatedly try to establish a connection with the camera until successful. Can be useful if you cannot guarantee that the cameras are running when starting the application. Use Custom Path Use a custom device path. Should not be needed in most cases. Custom Path A custom device path in case your camera does not show up in the list, e.g. `/dev/v4l/DEVICE_ID`. ## Image Renders an image as a video input. Open Image File Open the dialog window to select an image. The supported file formats are .png, .jpeg, .jpg, and .tga. --- # Software Downloads Download stable Oden releases, nightly builds, package checksums, and changelog information. Last validated: 2026-05-25 The Oden download site is [releases.voysys.dev](https://releases.voysys.dev). Use it to download stable releases, nightly builds, and package checksums. For step-by-step installation instructions, see [Install Oden](../start/install-oden.md). ## Release Channels | Channel | Use | Where | | --- | --- | --- | | Stable | A numbered release. Stable releases are listed by version and include product installers, `.sha256` checksum files, and release notes. Use the same stable version on every Oden machine in a deployment. | [Latest Release and Older Versions](https://releases.voysys.dev). | | Nightly | A date-based build such as `2026-05-04`. Nightlies may contain unstable features and should only be used for testing. | [Nightly Builds](https://releases.voysys.dev/nightly/) | ## Products Each stable or nightly version page groups downloads by product: - Oden Fleet Streamer - Oden Streamer - OdenVR - Oden Dome Player If a product is not available for a platform, use another platform package or choose a version that includes the package you need. ## Platform Packages | Platform | Package type | | --- | --- | | Windows x64 | MSI installer | | Ubuntu x64 | Debian package compatible with Ubuntu 20.04 and up. | | NVIDIA Jetson arm64 | Debian package tied to JetPack major version. | For Jetson, choose the package that matches the device’s JetPack version. Current release pages map JetPack package labels such as `4.6`, `5.1`, `6.1`, and `7.1` to the corresponding arm64 package filenames when those builds are available. ## Checksums Every generated package link has a matching `SHA` link that points to `.sha256`. Download the checksum file with the package when you need to verify the download before installing. ```shell sha256sum -c oden-vr__amd64.deb.sha256 ``` The Linux install script also downloads the matching `.sha256` file and verifies it with `sha256sum -c` before installing. ## Linux Install Script For Ubuntu and Jetson systems, the releases site publishes [`install.sh`](https://releases.voysys.dev/install.sh). The script installs the latest stable release if nothing else is specified. ```shell curl -fsSL https://releases.voysys.dev/install.sh | sh ``` ```shell curl -fsSL https://releases.voysys.dev/install.sh | sh -s -- fleet-streamer curl -fsSL https://releases.voysys.dev/install.sh | sh -s -- streamer curl -fsSL https://releases.voysys.dev/install.sh | sh -s -- vr ``` ```shell curl -fsSL https://releases.voysys.dev/install.sh | sh -s -- --release 2.48.1 ``` ## Nightly Builds Use a nightly only when you need to test a fix or new feature before the next stable release. > **WARNING** > Nightly builds may contain unstable features and changes that have not been validated as a stable release. Use a stable release for normal installations unless Voysys has directed you to use a nightly. Download nightlies from [releases.voysys.dev/nightly/](https://releases.voysys.dev/nightly/). Nightly pages use a date-based public build identifier. For example, a nightly shown as `2026-05-04` on the download site uses `20260504` in package filenames and URLs. Do not mix stable releases, older stable releases, and nightlies in the same deployment unless Voysys has told you to do so. ## Changelog Stable version pages include a What’s New section. The full changelog is available at [releases.voysys.dev/changelog](https://releases.voysys.dev/changelog/). Stable Oden releases use numeric versions such as `2.48.1`. We go to great lengths to always be backwards compatible but using the same stable version is the best way to avoid compatibility issues.