Problems with LSLClient in mne_realtime

I’ve been working on a system that establishes a seamless connection between my primary PC, equipped with the MNE and Python tools (Master), and my laptop. The laptop runs the openViBE Acquisition server, which is linked to a BCI headset (Slave).

My primary goal is to enable the Slave system to transmit EEG data to the Master system through the LSL (Lab Streaming Layer) protocol. Once received, this data will undergo a series of processing steps utilizing the realtime_mne library.

Here are the specifications I’ve set for the Acquisition server:

I’ve followed the guidance in the MNE documentation to visualize real-time EEG data using LSL. I made some modifications to the provided code, removing the MockLSLStream component. The resulting code is shown below:

# Author: Teon Brooks <teon.brooks@gmail.com>
#
# License: BSD (3-clause)
import matplotlib.pyplot as plt
from mne_realtime import LSLClient

print(__doc__)

# this is the host id that identifies your stream on LSL
host = 'eeg_stream'
# this is the max wait time in seconds until client connection
wait_max = 5

# For this example, let's use the mock LSL stream.
_, ax = plt.subplots(1)
n_epochs = 5

# main function is necessary here to enable script as own program
# in such way a child process can be started (primarily for Windows)
if __name__ == '__main__':
    with LSLClient(info='eeg', host=host, wait_max=wait_max) as client:
        client_info = client.get_measurement_info()
        sfreq = int(client_info['sfreq'])

        # let's observe ten seconds of data
        for ii in range(n_epochs):
            print('Got epoch %d/%d' % (ii + 1, n_epochs))
            plt.cla()
            epoch = client.get_data_as_epoch(n_samples=sfreq)
            epoch.average().plot(axes=ax)
            plt.pause(1.)
        plt.draw()
print('Streams closed')

and this what was printed in the console until it thrown an traceback:

Client: Waiting for server to start
Looking for LSL stream eeg_stream...
eeg_stream not found in streams: ['(0xe92637cf, 0x5efba8a2)', '(0x028b313d, 0x9e9fd28f)']
Looking for LSL stream eeg_stream...
eeg_stream not found in streams: ['(0xe92637cf, 0x5efba8a2)', '(0x028b313d, 0x9e9fd28f)']
Looking for LSL stream eeg_stream...
eeg_stream not found in streams: ['(0xe92637cf, 0x5efba8a2)', '(0x028b313d, 0x9e9fd28f)']
Looking for LSL stream eeg_stream...
eeg_stream not found in streams: ['(0xe92637cf, 0x5efba8a2)', '(0x028b313d, 0x9e9fd28f)']
Looking for LSL stream eeg_stream...
eeg_stream not found in streams: ['(0xe92637cf, 0x5efba8a2)', '(0x028b313d, 0x9e9fd28f)']
Looking for LSL stream eeg_stream...
eeg_stream not found in streams: ['(0xe92637cf, 0x5efba8a2)', '(0x028b313d, 0x9e9fd28f)']
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[1], line 21
     18 # main function is necessary here to enable script as own program
     19 # in such way a child process can be started (primarily for Windows)
     20 if __name__ == '__main__':
---> 21     with LSLClient(info='eeg', host=host, wait_max=wait_max) as client:
     22         client_info = client.get_measurement_info()
     23         sfreq = int(client_info['sfreq'])

File c:\Users\pc\Anaconda3\envs\EEGenv\lib\site-packages\mne_realtime\base_client.py:76, in _BaseClient.__enter__(self)
     74         time.sleep(0.1)
     75 else:
---> 76     self._connection_error()
     78 if not self.info:
     79     self.info = self._create_info()

File c:\Users\pc\Anaconda3\envs\EEGenv\lib\site-packages\mne_realtime\lsl_client.py:114, in LSLClient._connection_error(self)
    111 pylsl = _check_pylsl_installed(strict=True)
    112 extra = (f' Available streams on {self.host} from resolve_streams():\n'
    113          f'{pylsl.resolve_streams()}')
--> 114 super()._connection_error(extra)

File c:\Users\pc\Anaconda3\envs\EEGenv\lib\site-packages\mne_realtime\base_client.py:85, in _BaseClient._connection_error(self, extra)
     84 def _connection_error(self, extra=''):
---> 85     raise RuntimeError(f'Could not connect to Client.{extra}')

RuntimeError: Could not connect to Client. Available streams on eeg_stream from resolve_streams():
[, ]

Despite this, I successfully connected to the stream using the pylsl library. Here’s the snippet that worked for me:

import pylsl

# Resolve the LSL stream
streams = pylsl.resolve_stream("name", "eeg_stream")
# Check if the stream is found
if len(streams) == 0:
    print("LSL stream not found")
    exit()

# Create an inlet to receive data from the LSL stream
inlet = pylsl.stream_inlet(info=streams[0])

# Start receiving data
while True:
    # Get a chunk of samples from the LSL stream
    samples, timestamps = inlet.pull_chunk()

    # Process the received samples
    for sample, timestamp in zip(samples, timestamps):
        print(sample)

This pylsl script flawlessly printed out the received EEG data.

I’m eager to hear your thoughts and insights on resolving the issue with the realtime_mne code. Your assistance is greatly appreciated!

I had a quick look to the LSLClient code, and it looks like the stream is resolved by source_id and not by name. Thus, the host argument should correspond to the source_id of the LSL stream you are trying to connect to.

Mathieu

1 Like

Okay, do you know how exactly know the source_id of the LSL stream?
or should I make this change to MNE’s source code to accept the name

The source_id is an attribute in the StreamInfo, just like the name. There is a non-zero chance that it’s going to be empty…

streams = pylsl.resolve_stream("name", "eeg_stream")
sinfo = streams[0]
print (sinfo.source_id())

I think the code snippet above should work?

Mathieu

2 Likes