BrainAccessLslOutlet

class BrainAccessLslOutlet(streamName: String, sourceId: String, channels: List<String>, srate: Int, hasAccel: Boolean, hasGyro: Boolean, impedance: Boolean, outputMode: OutputMode = OutputMode.NORMAL)

An LSL StreamOutlet for one BrainAccess device, fed EegChunks.

The outlet has a fixed channel count = EEG channels (+ 3 accelerometer columns when the hardware has one, + 3 gyroscope columns when it has one) + one contact_<label> companion per EEG channel, float32, at the device sample rate, with per-channel metadata (label/unit/type) so downstream LSL consumers get a self-describing stream. Each push emits a whole packet's worth of samples in a single native push_chunk call (samples timestamped by LSL at push time).

Column layout: [EEG…][Accel_x, Accel_y, Accel_z]?[Gyro_x, Gyro_y, Gyro_z]?[contact_<EEG label>…]. IMU columns carry the units EegChunk delivers — accelerometer in m/s^2, gyroscope in deg/s, the BrainAccess C/Python SDK's contract — so a consumer that trusts the metadata (BrainAccess Board auto-ranges an m/s^2 trace) scales the motion data correctly. Channel types follow BrainAccess Board's own outlet: EEG columns EEG, accelerometer columns Accel (Board routes only Accel/ACC channels to its motion panel), gyroscope columns Gyroscope. The contact companions (type contact, unit value, 1.0 = electrode connected) mirror what Board publishes for its own headsets, so a Board receiving this stream gates the traces by electrode contact exactly as it does for local hardware. They come LAST so consumers that index EEG/IMU columns by position are unaffected — only channel_count grows.

NOTE: liblsl is provided by the consumer at runtime (this module compiles against it compileOnly; the native library ships separately in the distribution zip). Constructing this class on a classpath without liblsl + its .so will throw UnsatisfiedLinkError/ NoClassDefFoundError — guard at the call site if LSL is optional in your app.

outputMode is published as the output_mode description field (normal / test_signal), so a consumer can tell the ADS1299 test signal from electrode data without trusting the stream name.

push is not thread-safe (drive it from a single coroutine/thread), but close is idempotent and safe to race against itself: consumer teardown paths (user toggle vs. link-drop teardown) can overlap, and a double lsl_destroy_outlet is a native double-free (SIGABRT).

Constructors

Link copied to clipboard
constructor(streamName: String, sourceId: String, channels: List<String>, srate: Int, hasAccel: Boolean, hasGyro: Boolean, impedance: Boolean, outputMode: OutputMode = OutputMode.NORMAL)

Types

Link copied to clipboard
object Companion

Functions

Link copied to clipboard
fun close()
Link copied to clipboard
fun push(chunk: EegChunk)

Push every sample in chunk (EEG columns first, then accel x/y/z, then gyro x/y/z, then the contact companions) as one LSL chunk. No-op for an empty chunk. The chunk's column count must match this outlet's. EegChunk.contact is one flag per channel for the whole chunk, so the same 1.0 / 0.0 row is repeated on every sample of the chunk.