Skip to main content
Host-file and device-local recordings use the same MCAP schema and replay through the same API.

Two targets

Host-file recording

Write the live stream to a local MCAP file:
While recording, the SDK drains the IMU on every grab() so the file carries all queued samples even when retrieve_imu() is never called. If the process stops calling grab(), no new host frames are recorded. close() finalizes an active host file.

Device-local recording

Record to the M1, disconnect the host, and retrieve the file later:
An empty name has the M1 generate rec_<utc>_<seq>. Device-local recording cannot start while another recording, upload, update, or conflicting health sweep is active. Manage sessions over any control link (USB or BLE):
download_recording() uses the control link in chunks and does not require WiFi. A failed transfer leaves the partial file at the destination, and a re-run resumes it after verifying it belongs to the same recording; the file is not a valid MCAP until a run returns SUCCESS. delete_recording() returns immediately and reclaims large files in the background. Deleting the session that is currently recording returns DEVICE_BUSY, indicating that the call can be retried once the session stops rather than that it failed outright. When a recording call is refused, last_error_message() reports the device’s specific reason; the ERROR_CODE provides only the category.

Stop reasons and power loss

A recording continues until it is stopped, until storage reaches the reserve (10% of the recording store, at which point the session finalizes cleanly on its own), or until power is lost. RecordingStatus::stopped_reason says why a completed session ended: USER, DISK_FULL, WRITE_ERROR, or INTERRUPTED for a power cut. It reads UNSPECIFIED while recording and from firmware older than v00.09.16. After a power loss the M1 recovers the interrupted session on its next boot. An unencrypted recording is salvaged into a normal, listed, downloadable MCAP covering everything flushed up to roughly 250 ms before the cut. An encrypted one cannot be repaired on the device (the ciphertext is opaque to it), so it is listed with RecordingStatus::partial set and served as-is: download_recording() and uploads move the partial bytes, and ef-decrypt recovers everything up to the cut with a truncated-tail warning.

Encrypted recordings

Recordings can be AES-256-GCM encrypted at rest under a per-device key. RecordingStatus::encrypted reports whether a stored recording is, read off the container on disk rather than from the current setting, so it stays correct for recordings written before that setting last changed. Neither download_recording() nor an upload decrypts: the bytes move as they are stored, so an encrypted recording arrives as ciphertext and needs the key before any MCAP reader will open it. Decrypt on the host with ef-decrypt. Setting up a key, and reading a file back, are covered in Access Control and Encryption.

Uploading from the device

With WiFi provisioned, the M1 can upload a stopped recording with HTTP PUT:
The URL must use HTTP or HTTPS and accept a PUT of the complete file. upload_recording() starts a background transfer and returns after the M1 accepts the job.

Location metadata

Each recording carries a LocationFix. Set the persistent device location once with dev.set_location(lat, lon), or override per-session via RecordingParameters:
The per-session override does not change the persistent device location.