How liblsl works: overview
This section describes what liblsl does on the network and inside your process. It is for people debugging connection problems, writing a compatible implementation, or changing liblsl. For the concepts behind LSL (streams, metadata, synchronization) start with the LSL introduction.
The pieces
API object |
Role |
Internal class |
|---|---|---|
|
Describes a stream: name, type, channel count and format, nominal rate, |
|
|
Publishes one stream: answers discovery queries and time probes, and sends samples to every connected inlet. |
|
resolver ( |
Finds outlets on the network that match a query. |
|
|
Connects to one outlet, receives its samples, keeps the connection alive and measures the clock offset. |
|
A stream is identified by its uid, a random UUID created with the outlet. The
source_id set by the application should identify the data source (e.g. a device serial
number) and stay the same across restarts; inlets use it to find a restarted outlet
(see connection recovery).
What runs where
flowchart LR
subgraph Outlet process
app1[push_sample / push_chunk] --> sb[(send buffer)]
sb --> tcp[TCP server<br/>data port]
udp[UDP servers<br/>discovery + time probes]
end
subgraph Inlet process
res[resolver] -. UDP query .-> udp
conn[inlet connection<br/>+ watchdog] --> data[data thread]
conn --> time[time thread]
data --> q[(sample queue)] --> app2[pull_sample / pull_chunk]
end
data == TCP streamfeed ==> tcp
time -. UDP time probes .-> udp
An outlet starts, for each enabled IP version (IPv4/IPv6):
a UDP service socket on a free port that answers discovery queries sent directly to it and time-synchronization probes;
UDP responders on the shared discovery port (16571 by default) that answer multicast and broadcast discovery queries;
one TCP server on a free data port that serves stream data, the full stream info and the short info.
Two IO threads run these servers (one for data, one for discovery and time). Each connected
inlet gets a session on the TCP server. In the default (asynchronous) mode,
push_sample copies the sample into a send buffer, and each session’s transfer thread sends it
from its own queue. In synchronous mode (transp_sync_blocking) push_sample writes to all
connected sockets directly, without a copy.
A resolver sends discovery queries in waves over UDP (multicast, broadcast and unicast) and
collects the replies, each of which contains the outlet’s short stream_info with its
addresses and ports. See stream discovery.
An inlet is a facade over four parts:
the connection, which holds the resolved
stream_info, tracks whether the outlet is alive (a watchdog thread) and re-resolves it when it disappears;the info receiver, which fetches the full stream info (with
desc) over TCP on demand;the data receiver, whose thread opens the TCP streamfeed, parses incoming samples into a queue that
pull_sample/pull_chunkread from, and reconnects after errors (see data transport);the time receiver, whose thread exchanges UDP probes with the outlet to estimate the clock offset returned by
time_correction()(see time synchronization).
Threads start lazily: an inlet only connects when you first open the stream, pull data or ask
for its info, and only starts time synchronization on the first time_correction() call or when
clock-sync post-processing is enabled.
Lifetime of a connection
sequenceDiagram
participant O as Outlet
participant R as Resolver
participant I as Inlet
O->>O: bind UDP service, responders, TCP data port
R->>O: discovery query (UDP)
O-->>R: short stream info (UDP)
R-->>I: stream_info (addresses, ports, uid)
I->>O: LSL:streamfeed request (TCP)
O-->>I: header + test samples, then samples
I->>O: LSL:timedata probes (UDP), every few seconds
O-->>I: probe replies
Note over I,O: if the outlet disappears: watchdog notices,<br/>inlet re-resolves by source_id and reconnects
Configuration
Ports, discovery scope, known peers, IPv4/IPv6, time-probe timing and buffer sizes can be changed with a configuration file; see Configuration.
Where to look in the code
Topic |
Files |
|---|---|
Public API |
|
Outlet |
|
Discovery |
|
Inlet |
|
Samples and wire format |
|
Stream info XML |
|
Configuration |
|