LSL Coding Examples

There are essentially two types of programs interacting with LSL: programs that provide data, such as a data source that represents a particular acquisition device, and programs that consume data (and occasionally mixtures of the two), such as a viewer, a recorder, or a program that takes some action based on real-time data.

The main difference between LSL and other data transport interfaces is that it is not connection-oriented (although the underlying implementation uses connection-oriented transport). It is closer to a “publish-subscribe” model. A data producer creates a named “outlet” object (perhaps with meta-data) and pushes samples into it without ever caring about who is listening. So functionally it is offering a stream of data plus some meta-data about it.

A data consumer who is interested in a particular type of stream queries the network for a matching one (“resolves it”), for example based on the name, type or some other content-based query and then creates an “inlet” object to receive samples from the stream. It can also separately obtain the meta-data of the stream. The consumer then pulls out samples from the stream. The sequence of samples that the consumer sees is in order, without omissions (unless a buffer’s memory is exhausted), and type-safe. The data is buffered at both endpoints if there are transmission delays anywhere (e.g., interrupted network connection) but otherwise delivered as fast as the system allows.

The objects and functions to perform these tasks are provided by a single cross-platform library (liblsl). The library comes with a C header file, a C++ header file and wrapper classes for other languages.

Note: if you have trouble establishing communication between these programs across different computers especially on Windows, take a look at the NetworkConnectivity page and read the Network Troubleshooting section.

API Documentation

It is recommended that you clone the repository to get the respective code. The documentation is at the following locations:

The API documentation covers all classes, functions and types and should hopefully leave no questions unanswered. Note that a typical application will only need a small subset of the API (as used in the example programs).

C Example Programs: Basic to Advanced

These two example programs illustrate the bread-and-butter use of LSL as it is executing in almost any device module that comes with the distribution:
These two example programs illustrate a more special-purpose use case, namely sending arbitrary string-formatted data at irregular sampling rate. Such streams are used by programs that produce event markers, for example:
The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is here. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently.

C++ Example Programs: Basic to Advanced

These two example programs illustrate the shortest amount of code that is necessary to get a C++ program linked to LSL:
These two example programs demonstrate how to write more complete LSL clients in C++ (they are 1:1 equivalents of the corresponding C programs):
These two programs transmit their data at the granularity of chunks instead of samples. This is mostly a convenience matter, since inlets and outlets can be configured to automatically batch samples into chunks for transmission. Note that for LSL the data is always a linear sequence of samples and data that is pushed as samples can be pulled out as chunks or vice versa. They also show how structs can be used to represent the sample data, instead of numeric arrays (which is mostly a syntactic difference):
These two example programs illustrate a more special-purpose use case, namely sending arbitrary string-formatted data at irregular sampling rate. Such streams are used by programs that produce event markers, for example. These are 1:1 equivalents of the corresponding C programs:
The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is here. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently.

C/C++ Special-Purpose Example Programs

These programs illustrate some special use cases of LSL that are also relevant for C programmers. See the lsl_c.h header for the corresponding C APIs (they are very similar to the C++ code shown here).

This example illustrates in more detail how streams can be resolved on the network:
This example shows how to query the full XML meta-data of a stream (which may be several megabytes large):
This example shows how to obtain time-correction values for a given stream. These time-correction values are offsets (in seconds) that are used to remap any stream’s timestamps into the own local clock domain (just by adding the offset to the timestamp):

Python Example Programs: Basic to Advanced

These examples show how to transmit a numeric multi-channel time series through LSL:
The following examples show how to send and receive data in chunks, which can be more convenient. The data sender also demonstrates how to attach meta-data to the stream.
These examples show a special-purpose use case that is mostly relevant for stimulus-presentation programs or other applications that want to emit ‘event’ markers or other application state. The stream here is single-channel and has irregular sampling rate, but the value per channel is a string:
The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is here. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently.

MATLAB Example Programs: Basic to Advanced

These examples show how to transmit a numeric multi-channel time series through LSL:
These examples do the same as before, but now transmit the data at the granularity of chunks. For the purposes of network transmission the same effect can be achieved by creating the inlet or outlet with an extra argument to indicate that multiple samples should be batched into a chunk for transmission. However, since MATLAB’s interpreter is relatively slow, the library calls should be made in a vectorized manner, i.e. at chunk granularity, whenever possible (at least for high-rate streams). Note that for LSL the data is always a linear sequence of samples and data that is pushed as samples can be pulled out as chunks or vice versa:
These examples show a special-purpose use case that is mostly relevant for stimulus-presentation programs or other applications that want to emit ‘event’ markers or other application state. The stream here is single-channel and has irregular sampling rate, but the value per channel is a string:
The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is here. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently.

Java Example Programs: Basic to Advanced

These examples show how to transmit a numeric multi-channel time series through LSL:
The following examples show how to transmit data in form of chunks instead of samples, which can be more convenient.
These examples show a special-purpose use case that is mostly relevant for stimulus-presentation programs or other applications that want to emit ‘event’ markers or other application state. The stream here is single-channel and has irregular sampling rate, but the value per channel is a string:
The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is here. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently.

C# Example Programs: Basic to Advanced

These examples show how to transmit a numeric multi-channel time series through LSL:
The following examples show how to transmit data in form of chunks instead of samples, which can be more convenient.
These examples show a special-purpose use case that is mostly relevant for stimulus-presentation programs or other applications that want to emit ‘event’ markers or other application state. The stream here is single-channel and has irregular sampling rate, but the value per channel is a string:
The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is here. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently.

Real-World Example Programs

These sample codes are from actual ‘production’ software that is used to do data transmission:
  • KinectMocap: multi-channel signal with body joint positions and meta-data.
  • Input: irregular marker stream based on keyboard inputs.
  • BAlert: reading from an EEG device in a separate thread.
  • EyeLink: reading from an eye tracker in Python.

Also, all applications in the Apps directory are open-source and can serve as examples, and most of them are very similar in how they pass on data to LSL.