/** Example program that demonstrates how to send a multi-channel time series with proper
meta-data, and also some other advanced features. */
use lsl;
use lsl::ExPushable; // trait used for push_sample_ex method
use rand::Rng; // since we're sending random data
fn main() -> Result<(), lsl::Error> {
// This will be our stream declaration: we set the stream name to BioSemi, the content-type to
// EEG, 8 channels, 100 Hz, and float-valued data. The last argument should be a serial number
// or some stable identifier of the data source that's unique within your network (you can
// omit it, but if you do, receivers of your data wouldn't seamlessly resume if you stop and
// restart your program).
let mut info = lsl::StreamInfo::new(
"BioSemi", "EEG", 8, 100.0,
lsl::ChannelFormat::Float32, "myid234365")?;
// Next we append some meta-data. If use use a data type for which there are existing naming
// conventions (see https://github.com/sccn/xdf/wiki/Meta-Data#stream-content-types), we
// strongly advise to follow those for max interoperability. If you have other data and want to
// contribute to standardizing LSL meta-data for it, PRs against that spec are always encouraged.
let mut channels = info.desc().append_child("channels");
// here we're declaring some channel names for our 8 channels
for c in &["C3", "C4", "Cz", "FPz", "POz", "CPz", "O1", "O2"] {
channels.append_child("channel")
.append_child_value("label", c)
.append_child_value("unit", "microvolts")
.append_child_value("type", "EEG");
}
// Next we create a stream outlet. This makes our stream visible on the network.
// We can have the data transmitted in chunks to reduce network bandwidth, and here we use 20
// samples per chunk, and the default max buffer size of 360 seconds.
let outlet = lsl::StreamOutlet::new(&info, 20, 360)?;
println!("Now streaming data...");
let mut rng = rand::thread_rng();
loop {
// make a new random 8-channel sample (if we used a different value type here, then LSL
// will internally convert it to the type declared in the StreamInfo)
let sample: Vec<f32> = (0..8).map(|_| rng.gen_range(-15.0, 15.0)).collect();
// This is what you can do if you knew that your data was on average 53ms old by the time
// you submitted it to LSL (e.g., due to driver delays): you back-date the timestamp
let stamp = lsl::local_clock() - 0.053;
// now let's send it with that stamp (pushthrough is overridden by our chunk_size on the outlet)
// note that you can submit data of a type that differs from what's declared as the channel
// format (it will be converted into what's declared as the channel format)
outlet.push_sample_ex(&sample, stamp, true)?;
// wait a bit until we send the next sample
// note that, in practice, your actual samples per second isn't going to be exactly what
// you declared in the stream info -- that's why that info calls it the "nominal" sampling
// rate, as opposed to the *effective* sampling rate of the data
std::thread::sleep(std::time::Duration::from_millis(10));
}
}