Skip to content
EcoSimLab
DeutschEnglish
Docs navigation
Tool docs

Recording-Pipeline

The four steps of a recording — MQTT command from the StudyControlApp, OBS recording through the OBSController, the cockpit_recording flag in the telemetry log, and the manual FFmpeg step.

Part of: Recording-Pipeline

This page describes the Recording-Pipeline as a sequence of four steps. Each section names the repository, what happens there, and what you do. No repository holds the whole chain, so it is documented here.

All statements come from the code, checked on 2026-09-18 in the repositories study-control-app, beamngpy (package EcoSimlabPy) and obscontroller. The OBSController is not public. Step 4 is not in any repository.

Prerequisites

  • OBS Studio with the WebSocket server enabled. The OBSController connects to it. Password authentication must be off (obscontroller/README.md).
  • An MQTT broker. All three steps talk over the same broker.
  • The OBSController binary and its .env file. The .env file sets RECORDING_CONTROL_TOPIC, MQTT_BROKER and OBS_WS. The status topic defaults to from_obs_controller/recording_status.
  • A running trip in the StudyControlApp. The recording button is bound to a trip and to its participant and treatment.
  • FFmpeg for step 4.

Step 1 — Start and stop the recording from the StudyControlApp

Repository: study-control-app (packages/frontend/src/features/execution/composables/useCockpitRecording.ts).

The frontend publishes one MQTT message on the topic from_sca_frontend/recording_control. The payload holds the required field recording and an optional file name:

{
  "recording": true,
  "options": {
    "fileName": "tripID:7-subjectId:3-treatmentId:1-driverProfile:NONE"
  }
}

The app builds the file name from the trip, the participant, the treatment and the driver profile. Without a profile, the label is NONE.

What you do: Open the trip, then select the recording button. The button toggles: it sends recording: true when no recording runs, and recording: false when one runs.

The app does not read the state from OBS. It polls the backend endpoint getCockpitRecordingStatus, which returns the flag of the latest telemetry row of the trip (packages/backend/src/domains/execution/data.repository.ts). The button therefore reports success only after step 3 has delivered the flag.

Step 2 — The OBSController records in OBS Studio

Repository: obscontroller (Go, internal GitLab, not public).

The controller subscribes to the control topic and drives OBS over the WebSocket API (main.go, function handleRecordingControl):

  1. It parses the payload. If the JSON is invalid or the field recording is missing, it logs one line and leaves the recording untouched.
  2. It reads the current OBS recording state. It only acts on a real change of state.
  3. Before a start, it writes options.fileName into the OBS profile setting Output/FilenameFormatting. A failure here only warns, because the recording matters more than its name.
  4. It starts or stops the recording and publishes the new state on from_obs_controller/recording_status.

What you do: Start the controller next to OBS Studio before the trip. Check its log if the recording does not start.

The controller is not public. To get the binary or the source, ask the team.

Step 3 — The flag cockpit_recording in the telemetry log

Repository: beamngpy, package EcoSimlabPy.

EcoSimLabPy subscribes to from_obs_controller/recording_status (EcoSimlabPy/api/v2_topics.py). It stores the field recording as cockpit_recording (EcoSimlabPy/vehicle/vehicle_controller.py) and puts it into the control state of every tick. The flag is part of the state contract (EcoSimlabPy/contract/beamng_state_v2.py) and is therefore in every message of the driving data.

The StudyControlApp reads the flag into the telemetry row as cockpitRecording (packages/backend/src/domains/execution/beamngState.v2Reader.ts) and stores it with the trip.

What you do: Nothing during the run. After the run, use the flag to cut the driving data to the recorded part. The flag is false for every tick outside the recording.

Step 4 — Post-processing with FFmpeg to Full HD

No repository. Manual work.

OBS Studio writes the file in the resolution of the recorded scene. The video studies need Full HD. The conversion runs with FFmpeg outside of all three repositories.

What you do: Convert the file yourself after the study. There is no script and no documented command line for this step in study-control-app, beamngpy or obscontroller.

Result data

Artifact Where Name
Video file The OBS recording folder From options.fileName, unless OBS placeholders change it
Driving data The StudyControlApp database, per trip Column cockpitRecording per row

The video and the driving data are two files. The flag is the only link between them.

Open questions

  • The FFmpeg step has no script and no documented command line. The target resolution is Full HD; the exact call is not recorded anywhere.
  • The OBSController is not public and has no license. A short repository document follows when the repository is public.
  • OBS replaces characters that the file system forbids. Which file names the StudyControlApp produces in such a case is unchecked.