recorder.h header exposes three classes: RecorderInterface, Recorder, and AsyncRecorder. All three are in the basis namespace (via using aliases from basis::recorder).
RecorderInterface
RecorderInterface is the abstract base class. It defines the four operations every recorder must support:
RecorderInterface in tests — for example, to assert that a specific topic was or was not recorded, or to capture messages in memory instead of writing to disk.
Recorder — synchronous writes
Recorder is the basic implementation. It writes directly to an mcap::McapWriter on the calling thread.
Start(output_name) creates a file named <output_name>.mcap inside recording_dir. The MCAP profile is set to "basis".
Stop() (also called by the destructor) closes and flushes the file.
Split(new_name) closes the current file and opens a new one. Use this for rolling recordings.
Example: recording a single unit
AsyncRecorder — background writes
AsyncRecorder wraps a Recorder and moves disk I/O to a dedicated background thread using an MPSC queue. WriteMessage() enqueues the payload and returns immediately; the worker thread drains the queue.
Start() opens the file via the inner Recorder and starts the worker thread.
Stop() sets the stop flag and joins the worker thread, then closes the inner Recorder. If drain_queue_on_stop is true (the default), the worker flushes all enqueued messages before joining.
RegisterTopic() is protected by a mutex because it is called from the publishing thread while the worker thread may be running.
Choosing Recorder vs AsyncRecorder
Recorder | AsyncRecorder | |
|---|---|---|
| Write path | Synchronous, on publish thread | Asynchronous, background thread |
| Publish latency | Adds disk I/O latency | Minimal — enqueue only |
| Message ordering | Always in-order | In-order within the MPSC queue |
| Suitable for | Tests, low-frequency topics | Production, high-frequency topics |
Topic filtering with regex patterns
Both classes accept atopic_patterns argument: a vector of (string, regex) pairs. A topic is recorded only if at least one regex matches. The string member is the human-readable pattern source; the regex is the compiled form.
To record all topics, pass Recorder::RECORD_ALL_TOPICS (the default) or an empty vector:
Attaching a recorder to a Unit
Pass aRecorderInterface* to Unit::CreateTransportManager(). The transport manager forwards the recorder to each publisher it creates; every serialized message destined for the network is also handed to the recorder.
RecordingSettings in launch files
You can configure recording declaratively in a launch YAML file. The RecordingSettings struct maps directly to a recording block:
LaunchDefinition carries an optional RecordingSettings:
launch.yaml
When
async is true, an AsyncRecorder is created and shared across all units in the process. When false, a synchronous Recorder is used instead.Next steps
Deterministic replay
Feed a recorded MCAP file back through a Unit’s handlers to reproduce a robot run exactly
Testing overview
How Basis’s execution model enables both unit testing and replay-based testing