Unity Lsl Issues on Macos

Greg Wilding did a spike on this last year, capturing findings here:

Overview

LSL’s resolve_streams() is unable to find streams in a Unity environment on macOS (x86 or arm64). This prevents a program running inside Unity from receiving data via LSL.

Strangely, LSL works fine going the other way. A program in Unity can create an LSL outlet and send data without issue, ex: sending markers from Unity to bci-essentials-python.

Outside of Unity, LSL works just fine on macOS. The examples included with PyLSL and liblsl-Csharp all behave as expected. Building the liblsl binary using Xcode on macOS also works fine. See Test liblsl-Csharp and See if reinstalling Unity fixes liblsl problems.

In a Windows environment, resolve_streams() sometimes fails. In particular, unit tests fail randomly when running as a large batch. This may be a sign that the issue is also present on Windows, but only when multiple calls are made. See Why are Bessy Unity tests failing on macOS? for details.

Details

The Unity environment obtains LSL support via the LSL4Unity package. It provides the C# bindings (LSL.cs) and pre-complied liblsl binaries for all supported platforms, including macOS. The C# bindings are identical to what’s provided in liblsl-Csharp, which works on macOS. As a sanity check, the liblsl binaries from LSL4Unity were swapped with versions known to work on macOS. The result was the same - resolve_streams() was not able to find streams within Unity.

Strangely, the exact same liblsl binary works in liblsl-Csharp examples. This shows that the issue has something to do with the way Unity handles Dotnet / C# code. Perhaps it’s related to the way MonoBehavior objects execute?

The key symptom is that resolve_streams() doesn’t wait for data when reading UDP sockets to discover streams. The read functions don’t block, they just fall through. This happens no matter what timeout value is provided. There must be something different about the way Unity supports blocking reads / async reads.

Building notes

See liblsl repo for build instructions. You can get cmake via a conda environment, then use cmake to build the Xcode configuration:

You can instrument the library (ex: print out “I’m here”) by compiling your own liblsl and leveraging its logging facilities:

Installing a hand built liblsl into Unity can be done using symbolic links or copying the .dylib binaries into the correct location in a Unity project (ex: Library/PackageCache/com.labstreaminglayer.lsl4unity@xxx/Plugins/LSL/macOS/arm64).