diff --git a/docs/conf.py b/docs/conf.py index 5cf7b7d..9f57d17 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -49,4 +49,6 @@ 'repo': ('https://github.com/%s', None), 'lslrepo': ('https://github.com/labstreaminglayer/App-%s', None), 'lslrelease': ('https://github.com/labstreaminglayer/App-%s/releases', 'Download %s'), + # liblsl's own documentation (a sub-project of this site): :liblsl:`guide/linking.html` + 'liblsl': ('https://labstreaminglayer.readthedocs.io/projects/liblsl/%s', None), } diff --git a/docs/dev/LSL_INSTALL_ROOT.rst b/docs/dev/LSL_INSTALL_ROOT.rst index 41dcb74..9528766 100644 --- a/docs/dev/LSL_INSTALL_ROOT.rst +++ b/docs/dev/LSL_INSTALL_ROOT.rst @@ -1,25 +1,11 @@ :orphan: -.. role:: cmd(code) - :language: bash - ``LSL_INSTALL_ROOT`` ==================== -To import the LSL library in a separate CMake build, you need to set the -the **absolute path** to the `‘installed’ LSL -directory <#install-directory-tree>`__ in the ``LSL_INSTALL_ROOT`` -variable (e.g. :cmd:`-DLSL_INSTALL_ROOT=C:/LSL/build/install/`) or add the -**absolute path** to the\ ``LSL/cmake`` subfolder of the `‘installed’ -LSL directory <#install-directory-tree>`__ to your ``CMAKE_PREFIX_PATH`` -(:cmd:`list(APPEND CMAKE_MODULE_PATH "C:/path/to/LSL/build/install/cmake/")`). - -CMake looks for the file -``${LSL_INSTALL_ROOT}/LSL/share/LSL/LSLConfig.cmake``, so make sure your -``LSL_INSTALL_ROOT`` has the files listed in `the previous -section <#installed-directory-tree>`__. +Many LSL apps accept ``-DLSL_INSTALL_ROOT=`` when configuring with CMake. It is a hint for +``find_package(LSL)`` and should point to a liblsl install prefix: the folder that contains +``lib/`` and ``include/``, e.g. an extracted release archive or the result of ``cmake --install``. +Adding the same folder to ``CMAKE_PREFIX_PATH`` works for any CMake project. -By default, apps should look in ``../../LSL/liblsl/build/install`` so if -you have a ``build`` folder in each submodule (``LSL/liblsl/build``, -``Apps/Examples/build`` etc.) and installed ``liblsl`` first, CMake -automatically finds liblsl. +See :liblsl:`Using liblsl in your project ` for all the ways to find and link liblsl. diff --git a/docs/dev/app_build.rst b/docs/dev/app_build.rst index a2d34ca..c50ab82 100644 --- a/docs/dev/app_build.rst +++ b/docs/dev/app_build.rst @@ -79,13 +79,12 @@ Always be sure to read the specific application build instructions first. * If using command line * Start the build process (:cmd:`cmake --build . --config Release --target install`) - * (see also :ref:`cmakeinstalltarget`) * If using Visual Studio >=2017 built-in CMake utilities * Use the menu :guilabel:`Build > Install > ApplicationName` This will create a distribution tree in the folder specified by -:ref:`CMAKE_INSTALL_PREFIX ` similar to this: +``CMAKE_INSTALL_PREFIX`` similar to this: ‘installed’ directory tree ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/dev/app_dev.rst b/docs/dev/app_dev.rst index f888942..2f17174 100644 --- a/docs/dev/app_dev.rst +++ b/docs/dev/app_dev.rst @@ -31,24 +31,18 @@ Or see below for full applications. C++ apps -------- -The recommended way to get liblsl is to simply download the latest release from -`the release page `__. -You may need to click on the black arrow to expand the list of assets. - -If you are using CMake, pass the :doc:`LSL_INSTALL_ROOT` argument set to the location where your -liblsl file installed / unpacked to. -And your application should use something like the following line to find liblsl: +With CMake, either let CMake build liblsl as part of your app (``FetchContent``) or use an +installed liblsl (a `release download `__, a package +manager, or your own build) with ``find_package``: .. code-block:: cmake - find_package(LSL 1.13.0 REQUIRED - HINTS ${LSL_INSTALL_ROOT} - "${CMAKE_CURRENT_LIST_DIR}/../../LSL/liblsl/build/" - "${CMAKE_CURRENT_LIST_DIR}/../../LSL/liblsl/build/install" - PATH_SUFFIXES share/LSL - ) + find_package(LSL REQUIRED) # configure with -DCMAKE_PREFIX_PATH= if needed + target_link_libraries(${PROJECT_NAME} PRIVATE LSL::lsl) -Then you can link your target to liblsl with ``target_link_libraries(${PROJECT_NAME} PRIVATE LSL::lsl)``. +:liblsl:`Using liblsl in your project ` covers both ways, shipping liblsl +with your app (DLLs, RPATHs, macOS frameworks) and the ``LSLCMake`` helper functions. +Many existing apps also accept :doc:`LSL_INSTALL_ROOT` as a hint for where liblsl is. For a more complete example to help you get started with a C++ acquisition app, take a look at the `AppTemplate_cpp_qt `__, a small example that provides a solid groundwork for at least the following parts: diff --git a/docs/dev/build_android.rst b/docs/dev/build_android.rst index 5a16452..73d9fd6 100644 --- a/docs/dev/build_android.rst +++ b/docs/dev/build_android.rst @@ -1,64 +1,8 @@ +:orphan: + Building for Android #################### -Prerequisites -============= - -You'll need: the `Android SDK `__ -(in doubt, install the whole `Android Studio `__). -With it, install (preferred) the most recent NDK version or a specific NDK version you need. - -.. note:: **Unity**: Each Unity version needs liblsl to be compiled with a specific NDK version, - e.g. NDK 16 for Unity 2019.2. For a list, consult the - `Unity docs, section "Change the Android NDK path" `__ - - Generally, an NDK installed with the Android SDK manager is preferred, - because the SDK and some support files are newer. - -Make sure the NDK is installed in a path without spaces. -If it is already installed, use start Powershell as Administrator and create a link: - - :samp:`New-Item -ItemType SymbolicLink -Path "C:\\NDK" -Target "C:\\Space Path\\NDK"` - -At the time of writing this, :ref:`buildenvcmake` shipped with the Android SDK -is too old, so you need to install a recent version. - -Building liblsl -=============== - -Open a Terminal / Developer Command Prompt and retrieve the needed packages: - -.. code:: bash - - git clone --depth=1 https://github.com/sccn/labstreaminglayer.git - git submodule update --init LSL/liblsl LSL/liblsl-Java - -Next, chdir to the `labstreaminglayer/LSL/liblsl-Java` subdirectory -and configure your environment in the :file:`local.properties`: - -.. code:: bash - - ndk.dir=C\:\\Users\\user\\AppData\\Local\\Android\\Sdk\\ndk\\16.1.4479499 - android.ndkVersion=16.1.4479499 - sdk.dir=C\:\\Users\\user\\AppData\\Local\\Android\\Sdk - cmake.dir=C\:\\Program Files\\CMake - -.. note:: For older NDK versions without C++11 support, the alternative STL - has to be enabled with the CMake option `"-DANDROID_STL=c++_static"` in - :file:`build.gradle` - - -Make sure to escape all special characters and double-check the paths. - -After that, you can start the build from the command line: - -.. code:: bash - - gradlew assembleRelease - -After some time, this will create :file:`build/outputs/aar/liblsl-Java-Release.aar`. -Open it with 7zip (or rename it to `liblsl.zip`) and extract the `jni/` folder -containing the native libraries. - -.. note:: For Android apps, you can add the `.aar` file as dependency, no need to mess - with the `.so` files. \ No newline at end of file +Building liblsl for Android (with the NDK toolchain, or from an Android Studio project's +``CMakeLists.txt``) is described in :liblsl:`Building liblsl `. +For Java/Kotlin apps see the :doc:`language bindings <../info/language_wrappers>`. diff --git a/docs/dev/build_full_tree.rst b/docs/dev/build_full_tree.rst index 331092c..fd17d5f 100644 --- a/docs/dev/build_full_tree.rst +++ b/docs/dev/build_full_tree.rst @@ -1,240 +1,8 @@ :orphan: -.. role:: cmd(code) - :language: bash - Building LabStreamingLayer Full Tree -==================================== - -This guide is intended only for advanced developers who intend to work - on multiple projects and/or the core library simultaneously. - -Project Structure ------------------ - -This main `labstreaminglayer repository `__ -contains only the general project structure and references (“`git -submodules `__”) to -the liblsl C/C++ library -(`LSL/liblsl `__), -various language bindings (e.g. -`LSL/liblsl-Python `__), -the Apps to stream data from several types of devices -including a template examples, and the :lslrepo:`LabRecorder`.: - -.. code:: bash - - labstreaminglayer - ├── Apps - │ ├── AMTI ForcePlate - │ ├── LabRecorder - │ ├── [several other apps] - │ └── Wiimote - └── LSL - ├── liblsl - │ ├── include - │ ├── lslboost - │ ├── project - │ ├── src - │ └── testing - ├── liblsl-Matlab - ├── liblsl-Python - └── liblsl-Java - -To get the project source code using Git, see :doc:`full_tree`. - - -Dependencies (optional) ------------------------ - -The core ``liblsl`` does not have any external dependencies. - -Different language bindings or apps have their own dependencies so -please consult those projects’ build instructions. - -Many apps depend on :ref:`Qt5`, :ref:`boost`, and many use :ref:`buildenvcmake` -build system. -Follow the instructions to set up your :doc:`build_env`. - -Build instructions ------------------- - -In tree builds (recommended) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Create the build directory - -- You can use a GUI file manager to do this part or you can do it by - command line as below. -- Open a Terminal/shell/Command Prompt and change to the - labstreaminglayer directory. - - - If the build directory is already there then delete it - - - Windows: :cmd:`rmdir /S build`; Others: :cmd:`rm -Rf build` - -1. Configure the project using :ref:`buildenvcmake` - -- Option 1 - Visual Studio 2017 or later - - - Open the :file:`CMakeLists.txt` file in Visual Studio - (:guilabel:`File->Open->CMake`) - - Change CMake settings via :guilabel:`CMake->Change CMake Settings` - - - See `Common Cmake Settings <#common-cmake-options>`__ below - - - Change the selected project from the drop-down menu (:guilabel:`x64-Debug`, - :guilabel:`x64-Release`). - This will trigger a CMake re-configure with the new variables. - -- Option 2 - Using commandline. - - - Open a Terminal window or, on Windows, a ‘Developer Command Prompt - for VS2017’ (or 2019, as needed) - - Run cmake with appropriate `commandline options <#common-cmake-options>`__. - -- Option 3 - Using the GUI - - - Open a terminal/shell/command prompt and change to the - labstreaminglayer directory (:cmd:`cmake-gui -S . -B build`) - - Do an initial :guilabel:`Configure`. - Agree to create the directory if asked. - - Select your compiler and click Finish. - - Use the interface to set or add options/paths (:guilabel:`Add Entry`). - - - :ref:`Qt5` if the guessed path is not right - - :ref:`Boost` if the default was not correct - - A path where redistributable binaries get copied - (``CMAKE_INSTALL_PREFIX``) - - Build type (``CMAKE_BUILD_TYPE``, either ``Release`` or - ``Debug``). You can change this in Visual Studio later. - - Click on :guilabel:`Configure` again to confirm changes. - - - Click on :guilabel:`Generate` to create the build files / Visual Studio - Solution file - -2. Build the project -- If using command line - - - Start the build process - (:cmd:`cmake --build . --config Release --target install` - (see also :ref:`cmakeinstalltarget`) - -- If using Visual Studio 2017 built-in CMake utilities - - - Use the CMake menu > Install > LabStreamingLayer - -This will create a distribution tree in the folder specified by -:ref:`CMAKE_INSTALL_PREFIX ` similar to this: - -‘installed’ directory tree -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: bash - - ├── AppX - │ ├── AppX.exe - │ ├── liblsl64.dll - │ ├── Qt5Xml.dll - │ ├── Qt5Gui.dll - │ └── AppX_configuration.ini - ├── AppY - │ ├── AppY.exe - │ ├── AppY_conf.exe - │ ├── liblsl64.dll - │ └── example.png - ├── examples - │ ├── CppReceive.exe - │ ├── CppSendRand.exe - │ ├── SendDataC.exe - │ ├── liblsl64.dll - └── LSL - ├── share - │ ├── LSL - │ │ ├── LSLCMake.cmake - │ │ ├── LSLConfig.cmake - │ │ └── LSLCMake.cmake - ├── include - │ ├── lsl_c.h - │ └── lsl_cpp.h - └── lib - ├── liblsl64.dll - ├── liblsl64.lib - └── lslboost.lib - -On Unix systems (Linux+OS X) the executable’s library path is changed to -include :file:`../LSL/lib/` and the executable folder (:file:`./`) so common -libraries (Qt, Boost) can be distributed in a single library directory -or put in the same folder. -On Windows, the library is copied to (and searched in) the executable folder. - -The resulting folder :file:`LSL` contains three subfolders: - -- :file:`cmake` contains the exported build configuration - (:file:`LSLConfig.cmake`) that can be used to import the library in `out - of tree builds <#out-of-tree-builds>`__. -- :file:`include` contains the include headers for C (:file:`lsl_c.h`) and C++ - (:file:`lsl_cpp.h`) programs. -- :file:`lib` contains the library files. To run a program, you need the - :file:`liblslXY.dll` (Windows) or :file:`.so` (Linux) or :file:`.dylib` (MacOS). - -Common CMake Options --------------------- - -(See :ref:`cmakeclioptions`). - -- App dependencies (required by some apps). See :ref:`lslbuildenv` for more info. - - - ``-DQt5_DIR=/lib/cmake/Qt5`` - - ``-DBOOST_ROOT=`` - - - liblsl comes with its own boost used by itself, but it is not - uncommon for apps to require ‘normal’ boost. - -- Install root (see :doc:`LSL_INSTALL_ROOT`) - - - Not necessary for in-tree builds. - -Here are some example cmake commands: - -- Chad’s Windows build: - ``cmake .. -G "Visual Studio 14 2015 Win64" -DQt5_DIR=C:\Qt\5.11.1\msvc2015_64\lib\cmake\Qt5 -DBOOST_ROOT=C:\local\boost_1_67_0 -DLSLAPPS_LabRecorder=ON -DLSLAPPS_XDFBrowser=ON -DLSLAPPS_OpenVR=ON`` -- Chad’s Mac build: - ``cmake .. -DQt5_DIR=$(brew --prefix qt)/lib/cmake/Qt5/ -DLSLAPPS_LabRecorder=ON -DLSLAPPS_Benchmarks=ON -DLSLAPPS_XDFBrowser=ON`` - -Configure CMake options in VS 2017 / VS 2019 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you are using Visual Studio 2017’s built-in CMake Tools then the -default options would have been used to configure the project. To set -any variables you have to edit a file. Use the CMake menu > Change CMake -Settings > LabStreamingLayer. This will open a json file. For each -configuration of interest, add a ‘variables’ entry with a list of -key/value pairs. For example, under ``"name": "x64-Release",`` and -immediately after ``"ctestCommandArgs": ""`` add the following: - -:: +#################################### - , - "variables": [ - { - "name": "Qt5_DIR", - "value": "C:\\Qt\\5.11.1\\msvc2015_64\\lib\\cmake\\Qt5 " - }, - { - "name": "BOOST_ROOT", - "value": "C:\\local\\boost_1_67_0" - }, - { - "name": "LSLAPPS_LabRecorder", - "value": "ON" - }, - { - "name": "LSLAPPS_Benchmarks", - "value": "ON" - }, - { - "name": "LSLAPPS_XDFBrowser", - "value": "ON" - } - ] +The `labstreaminglayer repository `__ collects the apps as git +submodules. Build each app from its own repository (see :doc:`app_build`) and get liblsl from a release +or with CMake's FetchContent (see :liblsl:`Using liblsl in your project `). diff --git a/docs/dev/cmake.rst b/docs/dev/cmake.rst index 2e707e4..c58afc1 100644 --- a/docs/dev/cmake.rst +++ b/docs/dev/cmake.rst @@ -1,114 +1,11 @@ +:orphan: .. _buildenvcmake: CMake -===== +##### -`CMake `_ is the most widely used C++ build system, so -liblsl and most labstreaminglayer apps use it to build binaries for all -major platforms. - -.. _cmakeclioptions: - -Command Line Options --------------------- - -The basic options for the first run, i.e. to create a build folder and apply -some settings are: - -.. program:: cmake - -.. option:: -S path/to/the/build/folder - - (optional, if not set the current working directory is used) - -.. option:: -B path/to/the/build/directory - - where the build files will be written - -.. option:: -DVARIABLENAME=value - - Set a CMake variable, e.g. :samp:`cmake -D{CMAKE_BUILD_TYPE}={Release}`. - -.. option:: -G "Generator" - - See :ref:`cmakegenerators` - -:samp:`cmake -S . -B build -DLSL_UNITTESTS=1 -G Ninja`. - -.. _cmakecommonoptions: - -Common Variables -^^^^^^^^^^^^^^^^ - -Some often used CMake variables: - -- :doc:`cmake:variable/CMAKE_INSTALL_PREFIX` (default: :file:`build/install`) -- :doc:`cmake:variable/CMAKE_BUILD_TYPE` (default: ``Release``) -- :doc:`LSL_INSTALL_ROOT` -- :ref:`QT5_DIR ` - -.. _cmakegenerators: - -Generators -^^^^^^^^^^ - -On the first run, a :doc:`CMake Generator ` -can be specified via the :option:`-G` option to set the native build system. -The defaults are ``Makefiles`` on Unix and a Visual Studio version on Windows. - -Example: :command:`cmake -G "Visual Studio 16 2019"` - - -Building a project ------------------- - -Once a build folder is populated successfully, the binaries can be built either -with the native build system (e.g. ``ninja install``, ``msbuild …``) or you can -let CMake figure out which build system is used and how to run it via -:samp:`cmake --build path/to/build/folder --config Release -j --target install`. - -See :ref:`cmake:build tool mode`. - -Targets -------- - -A :doc:`target ` is either a binary to be -built (e.g. the ``liblsl`` target builds :file:`lsl.dll` on Windows, the -``LabRecorder`` target builds :file:`LabRecorder.exe` and so on), a command -to be run or an internal CMake target. - -The most important CMake targets are: - -``clean`` -^^^^^^^^^ - -:command:`cmake --build . --target clean` removes all built binaries but keeps -the CMake configuration. - -.. _cmakeinstalltarget: - -``install`` -^^^^^^^^^^^ - -CMake places built binary files as well as build sideproducts in a build -folder that should be separate from the source directory. -To copy only the needed files (and additional library files they depend on) -to a folder you can share with colleagues or copy onto another PC, you need to -‘install’ them. -This doesn’t mean ‘installing’ them in a traditional sense (i.e., with Windows -installers or package managers on Linux / OS X, see -:ref:`cmakepackagetarget` for that), but only copying them to a separate folder -and fixing some hardcoded paths in the binaries. - - -.. _cmakepackagetarget: - -``package`` -^^^^^^^^^^^ - -CMake can create packages for installed targets, e.g. ZIP files, -:doc:`Windows installers` or -:doc:`Debian / Ubuntu packages`. - -See :doc:`the CPack manual` for more information. +LSL is built with `CMake `__. See the +`CMake documentation `__ for a general introduction, and +:liblsl:`Building liblsl ` and :liblsl:`Using liblsl in your project ` +for liblsl's options and CMake package. diff --git a/docs/dev/dev_guide.rst b/docs/dev/dev_guide.rst index 053a162..dfd7eca 100644 --- a/docs/dev/dev_guide.rst +++ b/docs/dev/dev_guide.rst @@ -11,8 +11,7 @@ developer's guide. The labstreaminglayer source code is similarly split into Apps and LSL (core library and language interfaces), each of which comprises several submodules. -One could work with the repository, submodules and all, as a :doc:`full_tree`, but this is not recommended. -Most developers will be better working on individual apps or individual language interfaces. +Most developers work on individual apps or individual language interfaces, each in its own repository. :doc:`app_dev` -------------- @@ -31,10 +30,10 @@ See :doc:`examples` for a broader overview of example programs and general programming tips and tricks. Also make sure to glance over the :doc:`../info/faqs`. -:doc:`lib_dev` --------------- +liblsl +------ -:doc:`The guide ` is for you if you are: +The :liblsl:`liblsl documentation ` is for you if you are: - trying to build liblsl for a platform that does not already have a release @@ -43,7 +42,10 @@ Also make sure to glance over the :doc:`../info/faqs`. - trying to use liblsl in a language that does not already have an interface - - `Already supported: Android, C#, Java, Matlab, Python `_ + - See the :doc:`existing language bindings <../info/language_wrappers>` first. + +- curious how liblsl works on the network (discovery, the data protocol, time synchronization, recovery): + see :liblsl:`How liblsl works `. diff --git a/docs/dev/full_tree.rst b/docs/dev/full_tree.rst index 9dd2802..7511a39 100644 --- a/docs/dev/full_tree.rst +++ b/docs/dev/full_tree.rst @@ -1,90 +1,8 @@ :orphan: -.. role:: cmd(code) - :language: bash - Working With The LabStreamingLayer Repository -============================================= - -See also https://git-scm.com/book/en/v2/Git-Tools-Submodules - -This repository doesn’t contain the apps, just links to their respective -submodules (i.e. ``Apps/AppTemplate_cpp_qt`` is found at commit ``abc123def`` of -``https://github.com/labstreaminglayer/AppTemplate_cpp_qt``). - -Recommended git settings ------------------------- - -To avoid mistakes, consider changing the following git settings, either -for this repository (:cmd:`git config --add setting.name value`) or for all -repositories (:cmd:`git config --global --add ...`). - -- ``pull.rebase`` ``true``: insert new commits *before* your commits, - so no merge commits are created -- ``push.recurseSubmodules`` ``check``: abort pushing to the main - repository if you haven’t pushed the submodules you’re trying to - reference -- ``push.recurseSubmodules`` ``on-demand``: automatically push - submodules you’re updating - -Git cookbook ------------- - -Some operations have to be done differently than in a normal repository: - -Initial cloning, checking out *all* submodules: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - :cmd:`git clone --recurse-submodules git@github.com:labstreaminglayer/labstreaminglayer.git` - -Adding a submodule: -~~~~~~~~~~~~~~~~~~~ - -:cmd:`git submodule add https://github.com//.git Apps/AppXY` - -Don’t use URLs like ``ssh://git@github.com//`` -because they can’t be checked out anonymously. -Change them *in your local tree* with -:cmd:`git remote set-url origin ssh://...` after -checking them out. - -If you're using bash, you can ``cd`` to the subdirectory and set your local -remote with -:cmd:`git remote set-url origin git@github.com:labstreaminglayer/App-${PWD##*/}` - -Check out a single submodule: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:cmd:`git submodule update --init ` - -Update a submodule -~~~~~~~~~~~~~~~~~~ - -set the referenced commit to the newest: -:cmd:`git submodule update --remote --rebase ` (rebase local changes) or - -:cmd:`git submodule update --remote --merge ` (merge local changes) - -Change the commit that’s referenced in this repository: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Commit and push changes in the App repository: - -.. code:: bash - - cd Apps/XY - git add . - git commit -m'Message' - git push - - -From the main repository, update the reference: -:cmd:`git add Apps/XY` - -Commit and push as usual: - -.. code:: bash +############################################# - git add Apps/XY - git commit -m'Update references' - git push --recurse-submodules=on-demand +The `labstreaminglayer repository `__ collects the apps as git +submodules. Build each app from its own repository (see :doc:`app_build`) and get liblsl from a release +or with CMake's FetchContent (see :liblsl:`Using liblsl in your project `). diff --git a/docs/dev/lib_dev.rst b/docs/dev/lib_dev.rst index 60c8d18..374599b 100644 --- a/docs/dev/lib_dev.rst +++ b/docs/dev/lib_dev.rst @@ -1,228 +1,15 @@ -Library Development -################### - -.. note:: Stop reading if you just want to... - - - stream data from one of the :doc:`../info/supported_devices` or record data with the - LabRecorder. You can download pre-built releases for the apps and LabRecorder from each - repositories release page. - - - create or use a program to stream or receive data via the LabStreamingLayer. You can - download a liblsl release following instructions on the - `liblsl repository `_ - -Follow this guide if you... - -- want to add / modify core liblsl - - - Please create a `GitHub issue `__ - first to ask for advice and to get pre-approval if you would like your - modification to be included in the official library. - -- want to build liblsl for a device / OS with no official release (e.g. an embedded Linux device) +:orphan: .. _build_liblsl: -Building liblsl -*************** - -Before attempting to build liblsl, please make sure you have configured your :doc:`build_env`. - -This part of the guide describes the process of building liblsl from source -for Windows, Mac OS, and Linux. Since liblsl is cross-platform (it is written -in standard C++ and its dependencies are all cross-platform), this process should be pretty -straightforward. The following paragraphs provide a step-by-step instruction of -the build process on all three platforms. - -Getting the source -================== - -Open a Terminal / Developer Command Prompt and cd to a convenient location to download and build the library. - -:samp:`git clone --depth=1 https://github.com/sccn/liblsl.git` - -The resulting folder structure is as follows. - -.. code:: bash - - (working directory) - └── liblsl - ├── {...} - ├── include - ├── lslboost - ├── project - ├── src - └── testing - -Configuring the liblsl project -============================== - -.. note:: - Most popular IDEs have integrated CMake support. Typically, all that is necessary is to open - the root liblsl folder (i.e., the folder containing :file:`CMakeLists.txt`) and select the - appropriate CMake options in the IDE. - If you wish to use the IDE's integrated cmake, then you do not need to follow the - terminal commands below. - -.. code:: bash - - cd liblsl - cmake -S . -B build -G - -Note: call :samp:`cmake -G` without a generator name to get a list of available -generators. -I have used :samp:`cmake -S . -B build -G "Visual Studio 16 2019" -A x64 -DCMAKE_INSTALL_PREFIX="build/install"` - -If you used a generator, you can now open the IDE project file. Then build the install target. - -Alternatively, you can build directly from command line: -:samp:`cmake --build build -j --config Release --target install` - -In either case, this will create an ``install`` folder in your build folder. -This ``install`` folder is your :doc:`LSL_INSTALL_ROOT` that you might use in when -:doc:`building other applications.` - -Build options for liblsl -************************ - -There are several liblsl-specific build options. -All of them can be set either in the GUI (cmake-gui or IDE) or on the -command line (:samp:`cmake -D{foo}={bar}`). - -.. option:: CMAKE_INSTALL_PREFIX - - This is not an LSL-provided option, but it's a common and important option when building the install target. - See the `official documentation `_. - This argument is often necessary on Windows because otherwise it will attempt to install into C:\Program Files - which will fail without administrative rights. A good value to pass is "build/install". - -.. option:: LSL_DEBUGLOG - - Enable (lots of) additional debug messages. Defaults to OFF. - -.. option:: LSL_BUILD_EXAMPLES - - The liblsl distributions includes several example programs. - Enabling this option builds them alongside liblsl. - -.. option:: LSL_BUILD_STATIC - - By default, a shared library (`.so` on Unix, `.dylib` on OS X and `.dll` on - Windows) is built. This also exports a static library. - -.. option:: LSL_LEGACY_CPP_ABI - - Once upon a time there was a C++-ABI, but it only worked under very specific - circumstances and created hard to debug errors otherwise. Don't enable this - unless you know exactly what you are doing. - -.. option:: LSL_FORCE_FANCY_LIBNAME - - By default, CMake decides what to name the library (see :ref:`liblslarch`). - On Windows this is :file:`lsl.{}` - and for Unix (Linux/Mac) it is :file:`liblsl.{}`. - Enabling this option will force the library to be named - :file:`liblsl{}.{}` - on all platforms. - -.. option:: LSL_UNITTESTS - - liblsl includes two types of unittests: internal tests, that check that - various internal components work as intended, and external tests that - test the API as programs would. - -.. option:: LSL_UNIXFOLDERS - - Macs, Unix / Android systems and distributions like Anaconda have a specific - directory layout (binaries in :file:`{prefix}/bin`, includes in - :file:`{prefix}/include` and so on), whereas Windows users prefer - everything in a single folder. - If enabled, the :doc:`LSL_INSTALL_ROOT` folder will have a layout as it - should be on Unix systems. - -.. option:: LSL_WINVER - - Change the minimum targeted Windows version, defaults to `0x0601` for - Windows 7. - -.. option:: LSL_OPTIMIZATIONS - - Enable some more compiler optimizations. Defaults to ON. - -.. option:: LSL_BUNDLED_PUGIXML - - Use the bundled pugixml by default. Defaults to ON. - -Modifying liblsl -**************** - -First read :doc:`the introduction ` to learn about LSL components and classes. -:doc:`The C++ API documentation ` is a work-in-progress but might also be a good reference. - -Updating Boost -************** - -liblsl uses boost. -Because embedding liblsl in an application that links to an other Boost version (notably Matlab) -causes runtime errors, we bundle a subset of boost in -`lslboost`. - -To update the included lslboost, install Boost bcp and use the `update_lslboost.sh` script. - -Building liblsl language bindings -********************************* - -The most notable language bindings are `pylsl (Python) `_ and `liblsl-Matlab `_. See their respective pages for building guides. - -See also the repositories for `CSharp `_, `Unity Custom Package `_, `Rust `_, `Java `_, and `Julia (external) `_. - -Full Tree Dev -************* - -For advanced users (mostly core developers), it might be useful to simultaneously develop multiple apps and/or libraries. For this, please see the :doc:`full_tree` documentation to setup the lib and app tree, -then follow the build instructions in :doc:`build_full_tree`. - -Maintaining package manager ports -********************************* - -Ports of liblsl are available via a number of third-party package managers. -When new releases of liblsl are published, -these ports can be updated using the following steps: - -vcpkg -===== - -vcpkg ports are managed in the `microsoft/vcpkg `_ repository on GitHub -and changes or additions are submitted in the form of pull requests. -For a general overview of vcpkg, see https://github.com/microsoft/vcpkg/tree/master/docs. - -The liblsl port is maintained at https://github.com/microsoft/vcpkg/tree/master/ports/liblsl. - -- For new liblsl releases where no changes have been made in the CMake build scripts, - it should be enough to update the library versions in `vcpkg.json `_ - and in `portfile.cmake `_. - -- If there have been changes in the CMake build scripts, portfile.cmake may need to be adapted accordingly. - If any dependencies have changed (e.g. the version of Boost), the dependency information in vcpkg.json needs to be updated, as well. - -Conan -===== - -Conan packages are managed in the `conan-io/conan-center-index `_ repository on GitHub -and changes or additions are submitted in the form of pull requests. -For a general overview of the Conan package maintenance process, see `Adding Packages to ConanCenter `_. - -The liblsl port is maintained at https://github.com/conan-io/conan-center-index/tree/master/recipes/liblsl. - -- For new liblsl releases where no changes have been made in the CMake build scripts, - it should be enough to add the new library version to `config.yml `_ - and to `conandata.yml `_. +Library Development +################### -- If there have been changes in the CMake build scripts, `conanfile.py `_ may need to be adapted accordingly. - If any dependencies have changed (e.g. the version of Boost), the dependency information in conanfile.py needs to be updated, as well. +Building, configuring and modifying liblsl is now documented with liblsl itself: -homebrew -======== +* :liblsl:`Building liblsl `: options and platform notes (Linux, ARM, macOS, Windows, MinGW, iOS, Android) +* :liblsl:`Using liblsl in your project ` +* :liblsl:`How liblsl works ` +* :liblsl:`Maintaining package ports ` (vcpkg, Conan, conda-forge, Homebrew) -No documentation yet. -See https://github.com/labstreaminglayer/homebrew-tap +Before changing liblsl, please open an `issue `__ to discuss it. diff --git a/docs/index.rst b/docs/index.rst index 7e18aca..6352913 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,10 +7,12 @@ LabStreamingLayer's Documentation info/intro info/getting_started + info/getting_lsl info/user_guide info/supported_devices - info/language_wrappers + info/tools info/viewers + info/language_wrappers info/network-connectivity info/lslapicfg info/eeglab @@ -21,18 +23,23 @@ LabStreamingLayer's Documentation :maxdepth: 1 :caption: Developer's Guide - dev/doc_syntax dev/dev_guide - dev/app_build dev/app_dev - dev/build_android - dev/lib_dev - dev/cmake + dev/app_build + dev/examples + dev/doc_syntax + +liblsl documentation +-------------------- -External documentation ----------------------- +How liblsl, the core library, works and how to build it and use it in C/C++ programs is documented +with liblsl: -- :doc:`C++ API documentation ` +- :liblsl:`Getting liblsl `, :liblsl:`using it in your project ` + and :liblsl:`building it ` +- :liblsl:`Configuration (lsl_api.cfg) ` +- :liblsl:`How liblsl works `: discovery, the data protocol, time synchronization, recovery +- :doc:`C/C++ API reference ` Indices and tables ================== diff --git a/docs/info/getting_lsl.rst b/docs/info/getting_lsl.rst new file mode 100644 index 0000000..55bd628 --- /dev/null +++ b/docs/info/getting_lsl.rst @@ -0,0 +1,49 @@ +Getting LSL +########### + +What you need depends on what you want to do: + +* **Record or view streams, or stream from a supported device:** download the application. + :doc:`LabRecorder ` and the :doc:`device apps ` have ready-made + downloads on their release pages, and they include the library. +* **Write a program in Python, MATLAB, C#, Java, ...:** install the + :doc:`language binding `. Most bindings bundle liblsl or tell you where + to get it (e.g. ``pip install pylsl``). +* **Write a program in C or C++, or build a binding:** use liblsl directly, as described below. + +liblsl +====== + +liblsl is the C/C++ library that every LSL application and binding uses. Its own documentation +covers in detail how to :liblsl:`get it `, +:liblsl:`use it in your project ` and +:liblsl:`build it `. In short: + +* **Build it with your project.** C/C++ projects using CMake can add liblsl with + ``FetchContent`` and link the ``LSL::lsl`` target. This always gives you exactly the version + you ask for, built with your compiler. +* **Release downloads.** Every `liblsl release `__ + has builds for Windows (x64, x86, ARM64, and MinGW), Ubuntu (``.deb``, x64/ARM), macOS (an + installer for ``lsl.framework``) and an ``xcframework`` for macOS and iOS. These are built and + tested by the liblsl repository's own CI. +* **Package managers.** liblsl is also available from: + + * `conda-forge `__: ``conda install -c conda-forge liblsl`` + * `vcpkg `__: ``vcpkg install liblsl`` + * `Conan `__ + * `Homebrew `__: ``brew install labstreaminglayer/tap/lsl`` + + .. warning:: + These packages are maintained separately from liblsl and are updated by hand after each + release, so they are often one or more releases behind (check the version they offer). + The best-supported routes are the release downloads and building liblsl with your project + through its CMake integration, which liblsl's CI tests on every change. + +Apps and the full source tree +============================= + +Applications live in their own repositories under +`github.com/labstreaminglayer `__; each has a release page +with downloads and a README with build instructions. The +`labstreaminglayer repository `__ collects them all as +git submodules together with this documentation. diff --git a/docs/info/intro.rst b/docs/info/intro.rst index d83a10f..9f52e78 100644 --- a/docs/info/intro.rst +++ b/docs/info/intro.rst @@ -110,4 +110,5 @@ time-synchronization information). Developer Information ===================== -Please see the separate developer documentation :doc:`../dev/dev_guide`. +Please see the separate developer documentation :doc:`../dev/dev_guide`, and the +:liblsl:`liblsl documentation ` for how the core library works and how to build it and use it from C/C++. diff --git a/docs/info/language_wrappers.rst b/docs/info/language_wrappers.rst index 9d29910..dfc9386 100644 --- a/docs/info/language_wrappers.rst +++ b/docs/info/language_wrappers.rst @@ -1,15 +1,125 @@ -liblsl language wrappers -######################## - -* `C `__ -- This is the primary liblsl interface -* `C++ `__ -- Comes with liblsl -* `Python `__ -* `Matlab `__ -* `C# `__ -* `Unity `__ -* `Java `__ -* `Android `__ -* `rust `__ -* `Generic SWIG `__ -* `Julia `__ -* `Dart `__ (`pub.dev package `__) +Language Bindings +################# + +liblsl is a C library with a C++ wrapper (both documented in the +:liblsl:`liblsl documentation `). Other languages use it through bindings. +The *official* bindings are maintained under the +`labstreaminglayer GitHub organization `__. +*Community* bindings are maintained by others; they are listed here because we know of them, +not as an endorsement, and their completeness and upkeep vary (the year of the last change is +given as a hint). To add one, edit this page and open a pull request. + +Official +******** + +.. list-table:: + :header-rows: 1 + :widths: 15 35 50 + + * - Language + - Project + - Notes + * - C / C++ + - `liblsl `__ + - The library itself: ``lsl_c.h`` and the header-only ``lsl_cpp.h``. + * - Python + - `pylsl `__ + - ``pip install pylsl``; ctypes wrapper around liblsl. + * - MATLAB + - `liblsl-Matlab `__ + - MEX wrappers. + * - C# + - `liblsl-Csharp `__ + - A single file (``LSL.cs``) using P/Invoke; you provide ``lsl.dll``. + * - Unity + - `LSL4Unity `__ + - Unity package with the C# binding and the native plugin. + * - Unreal Engine + - `plugin-UE4 `__ + - Also on the Unreal Marketplace. + * - Java + - `liblsl-Java `__ + - JNA wrapper; also used on Android. + * - Rust + - `liblsl-rust `__ + - crates ``lsl`` / ``lsl-sys`` (last published 2020). + * - Android + - `liblsl-Android `__ + - Older Android Studio build of liblsl and the Java binding (2020). For new apps, build liblsl + from your app's ``CMakeLists.txt`` (see :liblsl:`Building liblsl `). + * - Other (SWIG) + - `liblsl-Generic `__ + - SWIG interface files for generating further bindings (2018). + +Community +********* + +.. list-table:: + :header-rows: 1 + :widths: 15 35 50 + + * - Language + - Project + - Notes + * - Python + - `MNE-LSL `__ + - ``pip install mne-lsl``; has its own low-level binding (``mne_lsl.lsl``) plus real-time tools for MNE-Python. + * - C# + - `SharpLSL `__ + - NuGet ``SharpLSL``; cross-platform. (2026) + * - C# (Bonsai) + - `emotional-cities/lsl `__ + - NuGet ``EmotionalCities.Lsl``. (2023) + * - C# (vvvv) + - `LSL4VVVV `__ + - For vvvv gamma. (2022) + * - C# + - `Diademics LibLSL `__ + - (2022) + * - Dart / Flutter + - `liblsl.dart `__ + - `pub.dev liblsl `__; full C API via FFI, builds liblsl from source. (2026) + * - Dart / Flutter + - `Bridging-Labs `__ + - pub.dev ``lsl_bindings`` / ``lsl_flutter``. (2025) + * - JavaScript (Capacitor, Cordova) + - `capacitor-lsl `__, + `cordova-plugin-lsl `__ + - Outlets only, for Android and iOS apps. (2026) + * - Node.js + - `node-labstreaminglayer `__ + - npm ``node-labstreaminglayer``. (2025) + * - Node.js + - `@neurodevs/node-lsl `__ + - Outlets only. (2026) + * - Node.js + - `lsl.js `__, `node-lsl `__ + - Older; partial API. (2023, 2019) + * - Julia + - `LSL.jl `__ + - Julia package ``LSL``; liblsl from ``liblsl_jll``. (2026) + * - LabVIEW + - `liblsl-LabVIEW `__ + - (2019) + * - Pure Data + - `PdLSL `__ + - Inlet and outlet externals. (2019) + * - openFrameworks + - `ofxLSL `__ + - Incomplete. (2022) + * - Swift + - `LabStreamingLayer `__ + - Minimal wrapper. (2020) + * - Odin + - `lslodin `__ + - Experimental, macOS. (2026) + +Reimplementations +***************** + +These implement the LSL protocol themselves instead of using liblsl. They may differ from liblsl +in behavior and compatibility; check how they are tested before relying on them. + +* Rust: `labstream `__ (exports liblsl's C API), + `rlsl `__ (C API, Python bindings and a WebSocket bridge) +* Swift: `SwiftLSL `__ (receiving only) diff --git a/docs/info/lslapicfg.rst b/docs/info/lslapicfg.rst index ea2de56..e050285 100644 --- a/docs/info/lslapicfg.rst +++ b/docs/info/lslapicfg.rst @@ -1,288 +1,23 @@ LSL configuration files -======================= +####################### -The liblsl library can be configured with configuration files. +liblsl reads an optional configuration file, ``lsl_api.cfg``, that changes how it behaves on +the network: the ports it uses, which part of the network it searches for streams, a list of +known computers to query directly, and logging and timing settings. Applications don't need to +know about it. -Configuration File Locations ----------------------------- +The full reference, including where liblsl looks for the file, its syntax and every setting with +its default, is in the liblsl documentation: :liblsl:`Configuration (lsl_api.cfg) `. -There are four possible locations where such a config file will be found by the library (liblsl): +A common example: telling every computer in a lab about the others (useful when multicast +discovery doesn't work on the network), and keeping two experiments on the same network apart: -- :file:`/etc/lsl_api/lsl_api.cfg` (Unix); - :file:`C:\\etc\\lsl_api\\lsl_api.cfg` (Windows). - This is a global directory that is visible to all applications from all users - on a given computer. -- :file:`~/lsl_api/lsl_api.cfg` (Unix); - :file:`%HOMEPATH%\\lsl_api\\lsl_api.cfg` (Windows). - This is a user-specific directory that is visible for all applications of - that user. - No administrator rights are usually necessary to edit it. -- :file:`$PWD/lsl_api.cfg`. - This is a program-specific location: the file needs to be in the working - directory of the program (for example right next to the binary). - This allows to customize LSL behavior on a program-by-program basis. +.. code-block:: ini -.. versionadded:: 1.13 -.. envvar:: LSLAPICFG + [lab] + KnownPeers = {192.168.1.17, 192.168.1.18} + SessionID = my-experiment -- the file specified in the environment variable :envvar:`LSLAPICFG` - This is a shell-specific location. - On Linux / OS X you can set the env variable either before the program - invocation (:command:`LSLAPICFG=/tmp/specialconf1.cfg ./LabRecorder`) or as - an export (:command:`export LSLAPICFG=/tmp/specialconf1.cfg`) to apply it to - all programs started afterwards from this shell session. - -For the above settings, the more local settings files have the higher -precedence, so a program-specific file overrides a user-specific file, which -overrides the global file. - -Configuration File Contents ---------------------------- - -The configuration file is formatted like a Windows .ini file. - -The ground truth configuration parsing options can be found by reading the -liblsl/api_config.cpp file's `load_from_file` function: -https://github.com/sccn/liblsl/blob/master/src/api_config.cpp#L84 - -The following contains the default settings of LSL that can be pasted -into a file as-is, although it is usually a good idea to specify only the -subset of parameters that you would like to override (to allow for future -corrections to the default settings). - -.. code:: bash - - [ports] - ; This port is used by machines to advertise and request streams. - MulticastPort = 16571 - - ; This is where the range of ports to serve data and service information begins (growing upwards according to the PortRange). - BasePort = 16572 - - ; Ports from the BasePort to BasePort+Portrange-1 are assigned to both TCP data ports (on the even ports, if the BasePort is odd) - ; and UDP service ports (on odd ports, if BasePort is even); since these ports are occupied in pairs, there can effectively be - ; PortRange/2 stream outlets coexisting on a single machine. A new outlet will occupy a successively higher pair of ports when - ; lower ones are occupied. The number of coexistant outlets can be increased by increasing this number. However, note that if - ; multicast and broadcast or all UDP transmission are disabled on some router, the peers will need to "manually" scan this range, - ; which can be slow on such a network. Also note that, to communicate with external parties, the port range needs to be open in the - ; respective firewall configurations. - PortRange = 32 - - ; How to treat IPv6: can be "disable" (then only v4 is used), or "allow" (then both are used side by side) or "force" (then only v6 is used). - IPv6 = allow - - [multicast] - ; The scope within which one's outlets and inlets are visible to each other. This can be machine (local to the machine), - ; link (local to the subnet), site (local to the site as defined by local policy), organization (e.g., campus), or global. - ; Always use only the smallest scope that works for your goals. This setting effectively merges the contents of - ; MachineAdresses, LinkAddresses, SiteAddresses, OrganizationAddresses, and GlobalAddresses, and sets the packet - ; TTL to one of the settings: 0, 1, 24, 32, or 255. If you share streams with remote collaborators, consider using the - ; KnownPeers setting under [lab] (thus listing their machines directly, which is more likely to work than internet-scale - ; multi-casting). Another possibility is to use the AddressesOverride and TTLOverride settings to avoid pulling in every - ; site at intermediate scopes. - ResolveScope = site - - ; ListenAddress = "" - ; IPv6MulticastGroup = 113D:6FDD:2C17:A643:FFE2:1BD1:3CD2 - - ; These are the default address pools for VisibilityScope. The following lists of addresses are merged according - ; to the VisibilityScope setting to yield the set of addresses considered for communication. - ; Note that making an uninformed/unfortunate address choice can interfere with your site's operations. - MachineAddresses = {FF31:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2} - LinkAddresses = {255.255.255.255, 224.0.0.183, FF02:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2} - SiteAddresses = {239.255.172.215, FF05:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2} - OrganizationAddresses = {} ; old = {239.192.172.215, FF08:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2} - GlobalAddresses = {} - - ; This allows you to override the addresses calculated by VisibilityScope. To communicate conveniently with a remote party without negotiating - ; the involved hostnames, you may choose a privately agreed-on multicast address of the appropriate scope here. - AddressesOverride = {} - - ; This setting allows you to override the packet time-to-live setting. If you intend to use multicast with a custom address to conveniently - ; communicate with a specific remote party, you may set this to a sufficiently high level (255 for international collaboration). - TTLOverride = -1 - - [lab] - ; This setting mainly serves as a fallback in case that your network configuration does not permit multicast/broadcast communication. - ; By listing the names or IP addresses of your lab's machines here (both stream providers and stream users) and make the file available - ; on all involved machines, you can bypass the need for multicasting. This setting can also be used to link a small collection of machines - ; across the internet, provided that the firewall settings of each party permit communication (forward the BasePort to BasePort+PortRange ports). - KnownPeers = {} - - ; This is the default "vanilla" session id; modify it to logically isolate your recording acitities from others within the scope. - ; The session id should not be relied on as a "password" to hide one's data from unprivileged users; use operating-system and - ; network settings for this purpose. Note that you machine still gets to see some traffic from other activities if within the scope. - SessionID = default - - [tuning] - ; This setting offers fine control over various intervals and constants in LSL. - ; We apologize that there is not more documentation for these settings at this time. - ; Brief descriptions can be found in https://github.com/sccn/liblsl/blob/master/src/api_config.h#L149-L200 - ; UseProtocolVersion = not set, read from common.h. - WatchdogCheckInterval = 15.0 - WatchdogTimeThreshold = 15.0 - MulticastMinRTT = 0.5 - MulticastMaxRTT = 3.0 - UnicastMinRTT = 0.75 - UnicastMaxRTT = 5.0 - ContinuousResolveInterval = 0.5 - TimerResolution = 1 - MaxCachedQueries = 100 - TimeUpdateInterval = 2.0 - TimeUpdateMinProbes = 6 - TimeProbeCount = 8 - TimeProbeInterval = 0.064 - TimeProbeMaxRTT = 0.128 - OutletBufferReserveMs = 5000 - OutletBufferReserveSamples = 128 - SendSocketBufferSize = 0 - InletBufferReserveMs = 5000 - InletBufferReserveSamples = 128 - ReceiveSocketBufferSize = 0 - SmoothingHalftime = 90.0 - ForceDefaultTimestamps = false - - [log] - ; the log level. Only messages at this level or below will be logged - ; -2: errors - ; -1: warnings - ; 0: information - ; 1-9: increasingly less important details - ; When liblsl is built with LSL_DEBUGLOG=On, the levels 1-9 will log more details - ; The log looks like this: - ; Date and time | runtime | thread ID | source location | level | Log message - ; 2020-11-11 08:54:08.696 ( 3.132s) [ A5247740] inlet_connection.cpp:46 WARN| The stream named 'timesync' can't be recovered automatically if its provider crashes because it doesn't have a unique source ID - level = -2 - ; liblsl can also write all log messages to a file specified here. By default, log messages will be appended - file = - -Changing the port ranges ------------------------- - -To change just the port range to, say 3051 - 3068, create a config file with -the following content: - -.. code:: bash - - [ports] - MulticastPort = 3051 - BasePort = 3052 - PortRange = 16 - -This type of change would only be necessary if you can move LSL to a port range -that is allowed through or forwarded by the router or firewall -(or the administrator). - -Changing the multicast scope ----------------------------- -Under some circumstances your recording environment might include a large -number of routers. -Service discovery between routers is a case that is not handled particularly -well by current network installations (it requires correct company-wide -multicast settings), but in cases where it works, you can expand or contract -the scope within which two machines will see each other's streams. - -The boundaries of these scopes are defined by the network administrators, but -they have the common names `machine`, `link`, `site`, `organization`, and -`global`. - -The default scope used by LSL is `site`. -To change it to `organization`, use a config file like the following one: - -.. code:: bash - - [multicast] - ResolveScope = organization - -In some cases it can also be helpful to reduce the scope to `link` -(which is the local router), for example when you have many concurrent -recording operations that you would like to generally separate from each other -(some one experimenter should not see the others' streams). -In a local lab, the :ref:`lab.KnownPeers ` option is usually a -better choice, though. - -Usually this is not necessary because between-router multicast is often not -configured properly anyway. - -Note that under the hood the multicast scopes are implemented by sets of -multicast addresses (which have the scope encoded in their address). -Independently of the scope you can customize the addresses themselves, for -example to adhere to local administrative rules. -See the full config file for the relevant variable names. - -.. _lslapicfg_lab: - -Defining the Local Laboratory ------------------------------ -It is possible to define what constitutes the local laboratory network in a -very fine-grained manner, if necessary (for example if one router was shared -between 10 labs, each of which involves a number of machines, or if a single -recording operation is coordinated across the internet between countries). - -There are two mechanisms for this. - -The `KnownPeers` setting allows to explicitly list the IP addresses or -hostnames of the involved machines. - -The following file contains an example: - -.. code:: bash - - [lab] - KnownPeers = {192.168.1.17, 137.243.177.26, testing.ucsd.edu} - -With this setting any type of service discovery issues due to router -configuration can be worked around. -Note that at the same time you might want to disable the multicast discovery by -restricting the ResolveScope to machine (the local machine) if the goal is to -prevent interference. - -The other mechanism does not involve the physical machines but is a purely -logical partitioning of the network into separate and independent recording -environments. -This is accomplished by assigning a non-default value to the SessionID option. -You only ever see streams hosted by clients that have the same SessionID. - -Below is an example: - -.. code:: bash - - [lab] - SessionID = lab-001b - -This way, you can assign a different session id per machine, or per user, or -per application to bypass any sort of unwanted stream visibility between -concurrent recording operations. -Note, that the SessionID is not a security feature, however. - -You are still be able to intercept packets involved in a session that is not -yours. - -Logging -------- - -In case something's not working and you want to investigate it or produce a -helpful bug report, `liblsl` can log details of the normal operation and -errors to the terminal or a log file: - -.. code:: bash - - [log] - level = 0 - file = lsllog.txt - -Tuning ------- - -The following settings have been found to help the robustness of wireless transmission. - -.. code:: bash - - [tuning] - TimeProbeMaxRtt = 0.100 - TimeProbeInterval = 0.010 - TimeProbeCount = 10 - TimeUpdateInterval = 0.25 - MulticastMinRTT = 0.100 - MulticastMaxRTT = 30 - +Put this file at ``~/lsl_api/lsl_api.cfg`` (or ``/etc/lsl_api/lsl_api.cfg`` for all users) on +every computer. Settings that affect discovery, such as the ports and ``SessionID``, must be +the same on all computers. diff --git a/docs/info/network-connectivity.rst b/docs/info/network-connectivity.rst index f156867..407ed1b 100644 --- a/docs/info/network-connectivity.rst +++ b/docs/info/network-connectivity.rst @@ -23,11 +23,17 @@ The connections that are required by LSL to work in its default settings are - (`FF02:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2`) - `FF05:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2` - - (`FF08113D:6FDD:2C17:A643:FFE2:1BD1:3CD2`) + - (`FF08:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2`) - (`FF0E:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2`) - `224.0.0.1`, `224.0.0.183`, `239.255.172.215` -- TCP and UDP connections to the ports 16572-16604 +- TCP and UDP connections to the ports 16572-16603 (``BasePort`` 16572 and ``PortRange`` 32 in the + :doc:`configuration file `) +- UDP replies to the inlet's time-synchronization probes, which come back to an OS-chosen port + (a stateful firewall matches them to the outgoing probe) + +The exact ports and directions for the outlet and the inlet computer are listed in liblsl's +:liblsl:`stream discovery ` documentation. To test whether the firewall is at issue, turn off both any personal firewall that you may have enabled, and then also turn off the Windows default firewall @@ -163,6 +169,51 @@ Note that the interface name may also be an interface index as printed by valid_lft forever preferred_lft forever +Same-Machine Discovery (Loopback) +********************************* + +Streams produced and consumed on the *same* machine are discovered over the +loopback interface using the machine-local address ``127.0.0.1`` (configurable +via the ``MachineAddresses`` setting in the ``[multicast]`` section of the +:doc:`configuration file `). + +``127.0.0.1`` is a *unicast* address, not a multicast group. Historically this +caused a subtle problem: when several outlets run on one machine, a unicast +discovery query sent to the shared port ``16571`` is delivered by the OS to only +**one** of the listening sockets, so only one local stream would resolve and +which one depended on socket bind order (restarting programs would shuffle which +stream was visible). This is the cause behind reports such as +`liblsl#92 `_, +`#28 `_, and +`#207 `_. + +liblsl 1.18 and newer fix this automatically: in addition to querying +``16571``, the resolver also probes each machine address across the per-stream +service-port range (``16572``–``16603``), where every stream owns its own socket. +No configuration or routing changes are needed — all local streams are +discoverable regardless of bind order. + +The same applies to any other program bound to port ``16571`` with address reuse, +such as the ``socat`` command above: while it runs, it can receive unicast queries +meant for outlets on that machine. Stop it once you are done testing. + +.. note:: + + **Advanced (optional).** If you instead want *true* multicast semantics on the + loopback interface — for example to avoid the unicast probe entirely, or for + container/network-namespace setups where each stream lives in its own + namespace — you can add a multicast route to the loopback device on Linux: + + .. code:: bash + + $ sudo ip route add multicast 224.0.0.0/4 dev lo + + With this route in place, link-scope multicast groups (e.g. ``224.0.0.183``) + are delivered to every local listener over loopback, so you may also remove + ``127.0.0.1`` from ``MachineAddresses`` and raise the ``ResolveScope`` to + ``link``. This is **not required** for normal same-machine use and is + Linux-specific; the default behavior above already handles the common case. + Customizing Network Features of LSL *********************************** All network features used by LSL clients (such as the ports) can be customized @@ -180,10 +231,10 @@ necessary. In order to enable a connection between two separate networks, there might be a number of firewalls that might block traffic. Let's identify these points: -- Forward outbound ports :samp:`16571 - 16604` for TCP/UDP on the Outlet's OS Firewall -- Forward ports :samp:`16571 - 16604` for TCP/UDP on the Outlet's Endpoint (Router) -- Forward ports :samp:`16571 - 16604` for TCP/UDP on the Inlet's Endpoint (Router/Virtual Firewall) -- Forward inbound ports :samp:`16571 - 16604` for TCP/UDP on the Inlet's OS Firewall +- Forward outbound ports :samp:`16571 - 16603` for TCP/UDP on the Outlet's OS Firewall +- Forward ports :samp:`16571 - 16603` for TCP/UDP on the Outlet's Endpoint (Router) +- Forward ports :samp:`16571 - 16603` for TCP/UDP on the Inlet's Endpoint (Router/Virtual Firewall) +- Forward inbound ports :samp:`16571 - 16603` for TCP/UDP on the Inlet's OS Firewall Keep in mind that there are many possible setups for local networks. There may be additional firewalls or network layers blocking your stream. If you believe this to be the case, please @@ -196,8 +247,9 @@ streaming device. It is often a requirement that a local network device has a st IP address in order to have its ports forwarded. Once all ports are forwarded on both sides, both outlet and inlet IP addresses need -to be added to the :samp:`KnownPeers` setting in the configuration file. This will override -the multicast discovery mechanism and only allow pairing between those endpoints. While +to be added to the :samp:`KnownPeers` setting in the configuration file. liblsl then also sends +discovery queries directly (unicast) to those computers; multicast discovery keeps running +alongside. While you're in the file, make sure the :samp:`SessionID` setting is something other than default for debugging and courtesy purposes. @@ -229,5 +281,5 @@ Wireless Connections ******************** There are some settings that can be modified to help LSL perform more reliably across -wireless networks. Please see the [tuning] section at the bottom of the :doc:`lslapicfg` -documentation for more information. +wireless networks; see :liblsl:`Tune for wireless networks ` +in the liblsl configuration reference. diff --git a/docs/info/supported_devices.rst b/docs/info/supported_devices.rst index 8b05740..77e8dd0 100644 --- a/docs/info/supported_devices.rst +++ b/docs/info/supported_devices.rst @@ -1,5 +1,8 @@ -Supported Devices and Tools -########################### +Supported Devices +################# + +This page lists hardware with LSL support. Software that works with any LSL stream (recording, +viewers, stimulus presentation software, analysis) is on the :doc:`tools` page. **For device applications and tools hosted on GitHub, please make sure to read the respective repository's README and to check the release page for downloads.** @@ -152,21 +155,6 @@ Supported Stimulation Hardware The following stimulation devices (TMS, TDCS / TACS) have LSL support: * `Soterix Medical MXN-33 Transcranial Electrical Stimulator `__ -Supported Stimulus Presentation Software -**************************************** -The following stimulus presentations systems are usable out of the box with LSL: - * `EventIDE `__ - * `E-Prime 3.0 `__ - * `iMotions `__ - * `Neurobehavioral Systems Presentation `__ - * Psychopy (using LSL for Python) - * PsychToolbox (using LSL for MATLAB) - * `Reiz `__ - * `Simulation and Neuroscience Application Platform (SNAP) `__ - * `SuperLab X7 `__ - * Unity (using `LSL4Unity `_ or liblsl C#) - * Unreal Engine (`Marketplace `__, `GitHub `__) - Miscellaneous Hardware ********************** The following miscellaneous hardware is supported: diff --git a/docs/info/time_synchronization.rst b/docs/info/time_synchronization.rst index 888fda9..604f9ad 100644 --- a/docs/info/time_synchronization.rst +++ b/docs/info/time_synchronization.rst @@ -61,7 +61,7 @@ Besides correcting for the clock domain, the XDF importer will, by default, as t Online Smoothing ---------------- -To smooth the time stamps online, multiple algorithms can be used. The simplest one is double exponential smoothing, which is relatively easy to implement in an online data processing system, although it should be noted that during the first few minutes of operation (up to 5) the resulting time stamps will still have a considerable error (above 1 ms). The forgetting factors of this algorithm need to be set depending on the sampling rate of the data and the amplitude of the jitter in the raw stamps, and can require some tuning until the desired accuracy is reached. A better alternative is Recursive Least Squares (RLS), which has essentially optimal convergence behavior, although it will still take a minute or two of warmup until the jitter after smoothing reaches an acceptable level (<1ms) in realistic settings. To achieve this precision, the forget factor should be set such that a sample that is 30 seconds old will have an effective weighting of 1/2 (this depends on the sampling rate); one can also use 60 or as much as 120 seconds to further increase the precision -- however, too large values can fail to track sufficiently fast non-linear clock drift due to room or computer temperature changes (empirically, a half time of x seconds will be able to track clock rate fluctuations that change on the order of 10*x seconds or more slowly). This algorithm will also be built-in for optional use in a future version of liblsl. Other algorithms, such as QR-RLS and the Kalman filter can also be used and will perform similarly to RLS (note: some formulations of RLS have numerical difficulties, depending on the order of operations, and should not be used as they can 'blow up' after a few minutes of use). +To smooth the time stamps online, multiple algorithms can be used. The simplest one is double exponential smoothing, which is relatively easy to implement in an online data processing system, although it should be noted that during the first few minutes of operation (up to 5) the resulting time stamps will still have a considerable error (above 1 ms). The forgetting factors of this algorithm need to be set depending on the sampling rate of the data and the amplitude of the jitter in the raw stamps, and can require some tuning until the desired accuracy is reached. A better alternative is Recursive Least Squares (RLS), which has essentially optimal convergence behavior, although it will still take a minute or two of warmup until the jitter after smoothing reaches an acceptable level (<1ms) in realistic settings. To achieve this precision, the forget factor should be set such that a sample that is 30 seconds old will have an effective weighting of 1/2 (this depends on the sampling rate); one can also use 60 or as much as 120 seconds to further increase the precision -- however, too large values can fail to track sufficiently fast non-linear clock drift due to room or computer temperature changes (empirically, a half time of x seconds will be able to track clock rate fluctuations that change on the order of 10*x seconds or more slowly). liblsl has this built in: enable it on an inlet with the ``proc_dejitter`` post-processing flag. Its half-time is the ``SmoothingHalftime`` setting (default 90 seconds) in the :doc:`configuration file `; see :liblsl:`time synchronization ` for how liblsl measures offsets and post-processes time stamps. Other algorithms, such as QR-RLS and the Kalman filter can also be used and will perform similarly to RLS (note: some formulations of RLS have numerical difficulties, depending on the order of operations, and should not be used as they can 'blow up' after a few minutes of use). Manual Synchronization With Non-LSL Clocks ========================================== diff --git a/docs/info/tools.rst b/docs/info/tools.rst new file mode 100644 index 0000000..d76ead4 --- /dev/null +++ b/docs/info/tools.rst @@ -0,0 +1,57 @@ +LSL Tools and Applications +########################## + +Besides the :doc:`device apps `, many tools work with any LSL stream. +This list is not complete; to add a tool, edit this page and open a pull request on the +`labstreaminglayer repository `__. + +Recording +********* + +* :lslrepo:`LabRecorder` records any number of streams, with their metadata and clock + offsets, to a single `XDF `__ file. + It is the standard way to record LSL data. + +Viewing +******* + +Real-time viewers (StreamViewer, MNE-LSL, LSL Viewer, SigVisualizer, ...) and offline viewers +for XDF files are listed on the :doc:`viewers` page. + +Working with recordings (XDF) +***************************** + +* `pyxdf `__: load XDF files in Python. +* `xdf-Matlab `__: load XDF files in MATLAB. +* `libxdf `__: C++ library for loading XDF files. +* `SigViewer `__ and + `MNELAB `__ open XDF files directly. +* :doc:`EEGLAB ` imports XDF files and can receive LSL streams. + +Real-time processing +******************** + +* `MNE-LSL `__: real-time streaming and processing with + MNE-Python, including a player that replays recordings as LSL streams. +* `Timeflux `__: a framework for real-time + biosignal pipelines with LSL input and output. +* :doc:`OpenViBE ` can receive and send LSL streams. + +Stimulus presentation software +****************************** + +The following stimulus presentation systems are usable out of the box with LSL, mostly to send +event markers: + +* `EventIDE `__ +* `E-Prime 3.0 `__ +* `iMotions `__ +* `Neurobehavioral Systems Presentation `__ +* PsychoPy (using LSL for Python) +* Psychtoolbox (using LSL for MATLAB) +* `Reiz `__ +* `Simulation and Neuroscience Application Platform (SNAP) `__ +* `SuperLab X7 `__ +* Unity (using `LSL4Unity `__ or liblsl C#) +* Unreal Engine (`GitHub `__, + `Marketplace `__) diff --git a/docs/info/user_guide.rst b/docs/info/user_guide.rst index a83eed0..61400f6 100644 --- a/docs/info/user_guide.rst +++ b/docs/info/user_guide.rst @@ -21,12 +21,12 @@ An outlet creates a group of UDP sockets on which it listens for incoming conten In particular, outlets listen via UDP on the multicast port (16571) for broadcast and multicast queries. Multiple sockets are created for this purpose, each of which listens on a different multicast address; these include both IPv4 and IPv6 addresses of the desired scope (for robustness to network conditions). The sockets are served from a single thread using asynchronous I/O for efficiency. While this still sounds like a lot of overhead, note that this thread is in waiting state for most of the time. -In addition, outlets create a single regular (unicast) UDP socket that listens for content queries on a free port in the port range 16572-16604. This is a fallback in case the broadcast/multicast service discovery is disabled. This socket not only handles content queries but also responds to time estimation packets (used by inlets to estimate clock synchronization when a transmission is ongoing). +In addition, outlets create a single regular (unicast) UDP socket that listens for content queries on a free port in the port range 16572-16603. Resolvers query it directly for machine-local streams and for the computers listed in ``KnownPeers``. This socket not only handles content queries but also responds to time estimation packets (used by inlets to estimate clock synchronization when a transmission is ongoing). TCP Data Transmission --------------------- -In addition each outlet creates a TCP server socket on a free port in the port range 16572-16604 to accept actual data transmission requests. There are two types of transmission requests: a request for streaming data (such a connection would be established when an inlet is used to pull samples from a particular provider) and a request for meta-data (such a connection would be established when an inlet is used to retrieve the full meta-data of a stream). TCP servers can also in principle handle service discovery, but are not used for this purpose due to the relative inefficiency of this. +In addition each outlet creates a TCP server socket on a free port in the port range 16572-16603 to accept actual data transmission requests. There are two types of transmission requests: a request for streaming data (such a connection would be established when an inlet is used to pull samples from a particular provider) and a request for meta-data (such a connection would be established when an inlet is used to retrieve the full meta-data of a stream). TCP servers can also answer discovery queries; this is only used when the optional ``ResolveOverTCP`` setting is turned on, because it is slow. An outlet can handle an arbitrary number of parallel connections to serve any number of listeners. @@ -34,7 +34,7 @@ Resolve Operations ================== When a client creates a Stream :term:`Resolver` to resolve a stream with desired properties on the lab network, it issues a resolve operation. -A resolve operation temporarily opens a range of UDP sockets through which queries are sent to the broadcast, multicast or unicast addresses that are configured as active. It also opens a UDP socket to receive result packets on a free port. The resolve operation emits a packet across each channel in a brief burst and waits for responses, then sends the next burst. This is repeated until the required conditions are fulfilled (e.g., service was found, timeout, etc.). +A resolve operation temporarily opens a UDP socket per IP version through which queries are sent to the broadcast, multicast or unicast addresses that are configured as active; replies come back to the same socket. The resolve operation emits a packet across each channel in a brief burst and waits for responses, then sends the next burst. This is repeated until the required conditions are fulfilled (e.g., service was found, timeout, etc.). Inlets ====== @@ -62,3 +62,9 @@ Here we talk about important functions like the local clock (:cpp:func:`lsl_local_clock`), a function to query a time offset (:cpp:func:`lsl_time_correction_ex`) and a function to get the library version used by the loaded library (:cpp:func:`lsl_library_version`). + +Further reading +=============== + +liblsl's documentation describes the mechanisms in detail, with the exact messages, ports and +timings: :liblsl:`How liblsl works `.