@neurodevs/node-lsl 19.0.0 → 22.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/README.md +6 -6
  2. package/build/__tests__/AbstractPackageTest.d.ts +12 -11
  3. package/build/__tests__/AbstractPackageTest.js +32 -34
  4. package/build/__tests__/AbstractPackageTest.js.map +1 -1
  5. package/build/__tests__/impl/{BleDeviceController.test.d.ts → BleGattController.test.d.ts} +3 -3
  6. package/build/__tests__/impl/{BleDeviceController.test.js → BleGattController.test.js} +68 -70
  7. package/build/__tests__/impl/BleGattController.test.js.map +1 -0
  8. package/build/__tests__/impl/BleObserverController.test.d.ts +12 -0
  9. package/build/__tests__/impl/BleObserverController.test.js +62 -0
  10. package/build/__tests__/impl/BleObserverController.test.js.map +1 -0
  11. package/build/__tests__/impl/{LslEventMarkerEmitter.test.d.ts → LslEventMarkerOutlet.test.d.ts} +3 -3
  12. package/build/__tests__/impl/{LslEventMarkerEmitter.test.js → LslEventMarkerOutlet.test.js} +45 -46
  13. package/build/__tests__/impl/LslEventMarkerOutlet.test.js.map +1 -0
  14. package/build/__tests__/impl/LslJsonOutlet.test.d.ts +14 -0
  15. package/build/__tests__/impl/LslJsonOutlet.test.js +118 -0
  16. package/build/__tests__/impl/LslJsonOutlet.test.js.map +1 -0
  17. package/build/__tests__/impl/LslStreamInfo.test.js +2 -3
  18. package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
  19. package/build/__tests__/impl/LslStreamInlet.test.d.ts +3 -5
  20. package/build/__tests__/impl/LslStreamInlet.test.js +13 -47
  21. package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
  22. package/build/__tests__/impl/LslStreamOutlet.test.js +7 -13
  23. package/build/__tests__/impl/LslStreamOutlet.test.js.map +1 -1
  24. package/build/__tests__/impl/LslWebSocketBridge.test.js +9 -11
  25. package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
  26. package/build/__tests__/impl/UsbDeviceController.test.js.map +1 -1
  27. package/build/__tests__/impl/WindowedClockRegressor.test.js +1 -1
  28. package/build/__tests__/impl/WindowedClockRegressor.test.js.map +1 -1
  29. package/build/assertions.js +1 -1
  30. package/build/assertions.js.map +1 -1
  31. package/build/impl/LslEventMarkerOutlet.d.ts +35 -0
  32. package/build/impl/{LslEventMarkerEmitter.js → LslEventMarkerOutlet.js} +2 -2
  33. package/build/impl/LslEventMarkerOutlet.js.map +1 -0
  34. package/build/impl/LslJsonOutlet.d.ts +33 -0
  35. package/build/impl/LslJsonOutlet.js +44 -0
  36. package/build/impl/LslJsonOutlet.js.map +1 -0
  37. package/build/impl/LslStreamInfo.d.ts +7 -7
  38. package/build/impl/LslStreamInfo.js.map +1 -1
  39. package/build/impl/LslStreamInlet.d.ts +63 -21
  40. package/build/impl/LslStreamInlet.js +221 -65
  41. package/build/impl/LslStreamInlet.js.map +1 -1
  42. package/build/impl/LslStreamOutlet.d.ts +16 -16
  43. package/build/impl/LslStreamOutlet.js +32 -36
  44. package/build/impl/LslStreamOutlet.js.map +1 -1
  45. package/build/impl/LslWebSocketBridge.d.ts +10 -10
  46. package/build/impl/LslWebSocketBridge.js.map +1 -1
  47. package/build/impl/clocks/WindowedClockRegressor.js.map +1 -0
  48. package/build/impl/controllers/{BleDeviceController.d.ts → BleGattController.d.ts} +10 -10
  49. package/build/impl/controllers/{BleDeviceController.js → BleGattController.js} +19 -19
  50. package/build/impl/controllers/BleGattController.js.map +1 -0
  51. package/build/impl/controllers/BleObserverController.d.ts +20 -0
  52. package/build/impl/controllers/BleObserverController.js +37 -0
  53. package/build/impl/controllers/BleObserverController.js.map +1 -0
  54. package/build/impl/controllers/UsbDeviceController.d.ts +9 -9
  55. package/build/impl/controllers/UsbDeviceController.js +7 -7
  56. package/build/impl/controllers/UsbDeviceController.js.map +1 -1
  57. package/build/index.d.ts +43 -31
  58. package/build/index.js +52 -39
  59. package/build/index.js.map +1 -1
  60. package/build/scripts/{runLslEventMarkerEmitter.js → runEventMarkerOutlet.js} +4 -3
  61. package/build/scripts/runEventMarkerOutlet.js.map +1 -0
  62. package/build/scripts/{runLslStreamOutlet.js → runLslOutlet.js} +1 -1
  63. package/build/scripts/runLslOutlet.js.map +1 -0
  64. package/build/scripts/runMuse.js +2 -2
  65. package/build/scripts/runMuse.js.map +1 -1
  66. package/build/testDoubles/{BleController/FakeBleController.d.ts → BleGatt/FakeBleGatt.d.ts} +6 -6
  67. package/build/testDoubles/{BleController/FakeBleController.js → BleGatt/FakeBleGatt.js} +8 -8
  68. package/build/testDoubles/BleGatt/FakeBleGatt.js.map +1 -0
  69. package/build/testDoubles/{BleController/SpyBleController.d.ts → BleGatt/SpyBleGatt.d.ts} +4 -4
  70. package/build/testDoubles/{BleController/SpyBleController.js → BleGatt/SpyBleGatt.js} +3 -3
  71. package/build/testDoubles/BleGatt/SpyBleGatt.js.map +1 -0
  72. package/build/testDoubles/BleObserver/FakeBleObserver.d.ts +10 -0
  73. package/build/testDoubles/BleObserver/FakeBleObserver.js +20 -0
  74. package/build/testDoubles/BleObserver/FakeBleObserver.js.map +1 -0
  75. package/build/testDoubles/ClockRegressor/FakeClockRegressor.d.ts +1 -1
  76. package/build/testDoubles/{EventMarkerEmitter/FakeEventMarkerEmitter.d.ts → EventMarkerOutlet/FakeEventMarkerOutlet.d.ts} +4 -4
  77. package/build/testDoubles/{EventMarkerEmitter/FakeEventMarkerEmitter.js → EventMarkerOutlet/FakeEventMarkerOutlet.js} +7 -7
  78. package/build/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.js.map +1 -0
  79. package/build/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.d.ts +10 -0
  80. package/build/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.js +23 -0
  81. package/build/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.js.map +1 -0
  82. package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.d.ts +9 -0
  83. package/build/testDoubles/{EventMarkerEmitter/ThrowingEventMarkerEmitter.js → EventMarkerOutlet/ThrowingEventMarkerOutlet.js} +2 -2
  84. package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.js.map +1 -0
  85. package/build/testDoubles/JsonOutlet/FakeJsonOutlet.d.ts +10 -0
  86. package/build/testDoubles/JsonOutlet/FakeJsonOutlet.js +20 -0
  87. package/build/testDoubles/JsonOutlet/FakeJsonOutlet.js.map +1 -0
  88. package/build/testDoubles/{StreamInfo/FakeStreamInfo.d.ts → LslInfo/FakeLslInfo.d.ts} +4 -4
  89. package/build/testDoubles/{StreamInfo/FakeStreamInfo.js → LslInfo/FakeLslInfo.js} +7 -7
  90. package/build/testDoubles/LslInfo/FakeLslInfo.js.map +1 -0
  91. package/build/testDoubles/LslInfo/SpyLslInfo.d.ts +10 -0
  92. package/build/testDoubles/{StreamInfo/SpyStreamInfo.js → LslInfo/SpyLslInfo.js} +4 -4
  93. package/build/testDoubles/LslInfo/SpyLslInfo.js.map +1 -0
  94. package/build/testDoubles/{StreamInlet/FakeStreamInlet.d.ts → LslInlet/FakeLslInlet.d.ts} +4 -4
  95. package/build/testDoubles/{StreamInlet/FakeStreamInlet.js → LslInlet/FakeLslInlet.js} +12 -11
  96. package/build/testDoubles/LslInlet/FakeLslInlet.js.map +1 -0
  97. package/build/testDoubles/LslInlet/SpyLslInlet.d.ts +4 -0
  98. package/build/testDoubles/{StreamInlet/SpyStreamInlet.js → LslInlet/SpyLslInlet.js} +2 -2
  99. package/build/testDoubles/LslInlet/SpyLslInlet.js.map +1 -0
  100. package/build/testDoubles/{StreamOutlet/FakeStreamOutlet.d.ts → LslOutlet/FakeLslOutlet.d.ts} +5 -5
  101. package/build/testDoubles/{StreamOutlet/FakeStreamOutlet.js → LslOutlet/FakeLslOutlet.js} +8 -8
  102. package/build/testDoubles/LslOutlet/FakeLslOutlet.js.map +1 -0
  103. package/build/testDoubles/LslWsBridge/FakeLslWsBridge.d.ts +14 -0
  104. package/build/testDoubles/{WebSocketBridge/FakeWebSocketBridge.js → LslWsBridge/FakeLslWsBridge.js} +14 -14
  105. package/build/testDoubles/LslWsBridge/FakeLslWsBridge.js.map +1 -0
  106. package/build/testDoubles/LslWsBridge/SpyLslWsBridge.d.ts +4 -0
  107. package/build/testDoubles/{WebSocketBridge/SpyLslWebSocketBridge.js → LslWsBridge/SpyLslWsBridge.js} +2 -2
  108. package/build/testDoubles/LslWsBridge/SpyLslWsBridge.js.map +1 -0
  109. package/build/testDoubles/UsbDevice/FakeUsbDevice.d.ts +12 -0
  110. package/build/testDoubles/UsbDevice/FakeUsbDevice.js +25 -0
  111. package/build/testDoubles/UsbDevice/FakeUsbDevice.js.map +1 -0
  112. package/build/testDoubles/consts.d.ts +2 -12
  113. package/build/testDoubles/consts.js +0 -20
  114. package/build/testDoubles/consts.js.map +1 -1
  115. package/build/testDoubles/generateRandomOutletOptions.d.ts +2 -2
  116. package/build/testDoubles/generateRandomOutletOptions.js.map +1 -1
  117. package/package.json +5 -4
  118. package/src/__tests__/AbstractPackageTest.ts +35 -42
  119. package/src/__tests__/impl/{BleDeviceController.test.ts → BleGattController.test.ts} +45 -47
  120. package/src/__tests__/impl/BleObserverController.test.ts +72 -0
  121. package/src/__tests__/impl/{LslEventMarkerEmitter.test.ts → LslEventMarkerOutlet.test.ts} +33 -37
  122. package/src/__tests__/impl/LslJsonOutlet.test.ts +135 -0
  123. package/src/__tests__/impl/LslStreamInfo.test.ts +8 -9
  124. package/src/__tests__/impl/LslStreamInlet.test.ts +21 -79
  125. package/src/__tests__/impl/LslStreamOutlet.test.ts +17 -25
  126. package/src/__tests__/impl/LslWebSocketBridge.test.ts +15 -19
  127. package/src/__tests__/impl/UsbDeviceController.test.ts +2 -2
  128. package/src/__tests__/impl/WindowedClockRegressor.test.ts +1 -1
  129. package/src/assertions.ts +1 -2
  130. package/src/impl/{LslEventMarkerEmitter.ts → LslEventMarkerOutlet.ts} +17 -17
  131. package/src/impl/LslJsonOutlet.ts +87 -0
  132. package/src/impl/LslStreamInfo.ts +7 -9
  133. package/src/impl/LslStreamInlet.ts +305 -81
  134. package/src/impl/LslStreamOutlet.ts +62 -59
  135. package/src/impl/LslWebSocketBridge.ts +15 -18
  136. package/src/impl/controllers/{BleDeviceController.ts → BleGattController.ts} +23 -28
  137. package/src/impl/controllers/BleObserverController.ts +62 -0
  138. package/src/impl/controllers/UsbDeviceController.ts +14 -16
  139. package/src/index.ts +64 -44
  140. package/src/scripts/{runLslEventMarkerEmitter.ts → runEventMarkerOutlet.ts} +3 -2
  141. package/src/scripts/runMuse.ts +2 -2
  142. package/src/testDoubles/{BleController/FakeBleController.ts → BleGatt/FakeBleGatt.ts} +14 -14
  143. package/src/testDoubles/{BleController/SpyBleController.ts → BleGatt/SpyBleGatt.ts} +5 -5
  144. package/src/testDoubles/BleObserver/FakeBleObserver.ts +28 -0
  145. package/src/testDoubles/ClockRegressor/FakeClockRegressor.ts +1 -1
  146. package/src/testDoubles/{EventMarkerEmitter/FakeEventMarkerEmitter.ts → EventMarkerOutlet/FakeEventMarkerOutlet.ts} +11 -11
  147. package/src/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.ts +31 -0
  148. package/src/testDoubles/{EventMarkerEmitter/ThrowingEventMarkerEmitter.ts → EventMarkerOutlet/ThrowingEventMarkerOutlet.ts} +5 -5
  149. package/src/testDoubles/JsonOutlet/FakeJsonOutlet.ts +25 -0
  150. package/src/testDoubles/{StreamInfo/FakeStreamInfo.ts → LslInfo/FakeLslInfo.ts} +9 -9
  151. package/src/testDoubles/{StreamInfo/SpyStreamInfo.ts → LslInfo/SpyLslInfo.ts} +5 -5
  152. package/src/testDoubles/{StreamInlet/FakeStreamInlet.ts → LslInlet/FakeLslInlet.ts} +15 -14
  153. package/src/testDoubles/LslInlet/SpyLslInlet.ts +10 -0
  154. package/src/testDoubles/{StreamOutlet/FakeStreamOutlet.ts → LslOutlet/FakeLslOutlet.ts} +11 -14
  155. package/src/testDoubles/{WebSocketBridge/FakeWebSocketBridge.ts → LslWsBridge/FakeLslWsBridge.ts} +19 -19
  156. package/src/testDoubles/LslWsBridge/SpyLslWsBridge.ts +9 -0
  157. package/src/testDoubles/UsbDevice/FakeUsbDevice.ts +34 -0
  158. package/src/testDoubles/consts.ts +3 -23
  159. package/src/testDoubles/generateRandomOutletOptions.ts +2 -2
  160. package/build/__tests__/impl/BleDeviceController.test.js.map +0 -1
  161. package/build/__tests__/impl/LslEventMarkerEmitter.test.js.map +0 -1
  162. package/build/consts.d.ts +0 -11
  163. package/build/consts.js +0 -21
  164. package/build/consts.js.map +0 -1
  165. package/build/impl/LslEventMarkerEmitter.d.ts +0 -35
  166. package/build/impl/LslEventMarkerEmitter.js.map +0 -1
  167. package/build/impl/WindowedClockRegressor.js.map +0 -1
  168. package/build/impl/controllers/BleDeviceController.js.map +0 -1
  169. package/build/impl/workers/inlet/LslStreamInlet.worker.d.ts +0 -22
  170. package/build/impl/workers/inlet/LslStreamInlet.worker.js +0 -42
  171. package/build/impl/workers/inlet/LslStreamInlet.worker.js.map +0 -1
  172. package/build/impl/workers/inlet/StreamInletWorker.d.ts +0 -73
  173. package/build/impl/workers/inlet/StreamInletWorker.js +0 -253
  174. package/build/impl/workers/inlet/StreamInletWorker.js.map +0 -1
  175. package/build/impl/workers/outlet/LslStreamOutlet.worker.d.ts +0 -32
  176. package/build/impl/workers/outlet/LslStreamOutlet.worker.js +0 -82
  177. package/build/impl/workers/outlet/LslStreamOutlet.worker.js.map +0 -1
  178. package/build/scripts/discoverMuse.js +0 -40
  179. package/build/scripts/discoverMuse.js.map +0 -1
  180. package/build/scripts/runLslEventMarkerEmitter.js.map +0 -1
  181. package/build/scripts/runLslStreamOutlet.d.ts +0 -1
  182. package/build/scripts/runLslStreamOutlet.js.map +0 -1
  183. package/build/scripts/testDestroyOutlet.d.ts +0 -1
  184. package/build/scripts/testDestroyOutlet.js +0 -4
  185. package/build/scripts/testDestroyOutlet.js.map +0 -1
  186. package/build/testDoubles/BleController/FakeBleController.js.map +0 -1
  187. package/build/testDoubles/BleController/SpyBleController.js.map +0 -1
  188. package/build/testDoubles/EventMarkerEmitter/FakeEventMarkerEmitter.js.map +0 -1
  189. package/build/testDoubles/EventMarkerEmitter/SpyEventMarkerEmitter.d.ts +0 -10
  190. package/build/testDoubles/EventMarkerEmitter/SpyEventMarkerEmitter.js +0 -23
  191. package/build/testDoubles/EventMarkerEmitter/SpyEventMarkerEmitter.js.map +0 -1
  192. package/build/testDoubles/EventMarkerEmitter/ThrowingEventMarkerEmitter.d.ts +0 -9
  193. package/build/testDoubles/EventMarkerEmitter/ThrowingEventMarkerEmitter.js.map +0 -1
  194. package/build/testDoubles/StreamInfo/FakeStreamInfo.js.map +0 -1
  195. package/build/testDoubles/StreamInfo/SpyStreamInfo.d.ts +0 -10
  196. package/build/testDoubles/StreamInfo/SpyStreamInfo.js.map +0 -1
  197. package/build/testDoubles/StreamInlet/FakeStreamInlet.js.map +0 -1
  198. package/build/testDoubles/StreamInlet/SpyStreamInlet.d.ts +0 -4
  199. package/build/testDoubles/StreamInlet/SpyStreamInlet.js.map +0 -1
  200. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js.map +0 -1
  201. package/build/testDoubles/UsbController/FakeUsbController.d.ts +0 -12
  202. package/build/testDoubles/UsbController/FakeUsbController.js +0 -25
  203. package/build/testDoubles/UsbController/FakeUsbController.js.map +0 -1
  204. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.d.ts +0 -14
  205. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.js.map +0 -1
  206. package/build/testDoubles/WebSocketBridge/SpyLslWebSocketBridge.d.ts +0 -4
  207. package/build/testDoubles/WebSocketBridge/SpyLslWebSocketBridge.js.map +0 -1
  208. package/build/testDoubles/WorkerThreads/FakeWorker.d.ts +0 -27
  209. package/build/testDoubles/WorkerThreads/FakeWorker.js +0 -67
  210. package/build/testDoubles/WorkerThreads/FakeWorker.js.map +0 -1
  211. package/src/consts.ts +0 -21
  212. package/src/impl/workers/inlet/LslStreamInlet.worker.ts +0 -74
  213. package/src/impl/workers/inlet/StreamInletWorker.ts +0 -348
  214. package/src/impl/workers/outlet/LslStreamOutlet.worker.ts +0 -144
  215. package/src/scripts/discoverMuse.ts +0 -50
  216. package/src/scripts/testDestroyOutlet.ts +0 -5
  217. package/src/testDoubles/EventMarkerEmitter/SpyEventMarkerEmitter.ts +0 -31
  218. package/src/testDoubles/StreamInlet/SpyStreamInlet.ts +0 -10
  219. package/src/testDoubles/UsbController/FakeUsbController.ts +0 -34
  220. package/src/testDoubles/WebSocketBridge/SpyLslWebSocketBridge.ts +0 -9
  221. package/src/testDoubles/WorkerThreads/FakeWorker.ts +0 -99
  222. /package/build/impl/{WindowedClockRegressor.d.ts → clocks/WindowedClockRegressor.d.ts} +0 -0
  223. /package/build/impl/{WindowedClockRegressor.js → clocks/WindowedClockRegressor.js} +0 -0
  224. /package/build/scripts/{discoverMuse.d.ts → runEventMarkerOutlet.d.ts} +0 -0
  225. /package/build/scripts/{runLslEventMarkerEmitter.d.ts → runLslOutlet.d.ts} +0 -0
  226. /package/src/impl/{WindowedClockRegressor.ts → clocks/WindowedClockRegressor.ts} +0 -0
  227. /package/src/scripts/{runLslStreamOutlet.ts → runLslOutlet.ts} +0 -0
@@ -6,8 +6,8 @@ import {
6
6
  CHANNEL_FORMATS_MAP,
7
7
  } from '@neurodevs/ndx-native'
8
8
 
9
- export default class LslStreamInfo implements StreamInfo {
10
- public static Class?: StreamInfoConstructor
9
+ export default class LslStreamInfo implements LslInfo {
10
+ public static Class?: LslInfoConstructor
11
11
 
12
12
  public readonly name: string
13
13
  public readonly type: string
@@ -22,7 +22,7 @@ export default class LslStreamInfo implements StreamInfo {
22
22
 
23
23
  private lsl = LiblslAdapter.getInstance()
24
24
 
25
- protected constructor(options: StreamInfoOptions) {
25
+ protected constructor(options: LslInfoOptions) {
26
26
  const {
27
27
  name = `lsl-stream-info-${generateId()}`,
28
28
  type = generateId(),
@@ -46,7 +46,7 @@ export default class LslStreamInfo implements StreamInfo {
46
46
  this.appendChannelsToStreamInfo()
47
47
  }
48
48
 
49
- public static Create(options: StreamInfoOptions) {
49
+ public static Create(options: LslInfoOptions) {
50
50
  return new (this.Class ?? this)(options)
51
51
  }
52
52
 
@@ -81,7 +81,7 @@ export default class LslStreamInfo implements StreamInfo {
81
81
  }
82
82
  }
83
83
 
84
- export interface StreamInfo {
84
+ export interface LslInfo {
85
85
  destroy(): void
86
86
  readonly name: string
87
87
  readonly type: string
@@ -94,11 +94,9 @@ export interface StreamInfo {
94
94
  readonly infoHandle: InfoHandle
95
95
  }
96
96
 
97
- export type StreamInfoConstructor = new (
98
- options: StreamInfoOptions
99
- ) => StreamInfo
97
+ export type LslInfoConstructor = new (options: LslInfoOptions) => LslInfo
100
98
 
101
- export interface StreamInfoOptions {
99
+ export interface LslInfoOptions {
102
100
  channelNames: string[]
103
101
  channelFormat: ChannelFormat
104
102
  sampleRateHz: number
@@ -1,37 +1,75 @@
1
- import { Worker } from 'node:worker_threads'
1
+ import {
2
+ handleLslError,
3
+ InfoHandle,
4
+ InletHandle,
5
+ LiblslAdapter,
6
+ } from '@neurodevs/ndx-native'
7
+ import {
8
+ JsExternal,
9
+ unwrapPointer,
10
+ createPointer,
11
+ DataType,
12
+ freePointer,
13
+ PointerType,
14
+ } from 'ffi-rs'
2
15
 
3
- export default class LslStreamInlet implements StreamInlet {
4
- public static Class?: StreamInletConstructor
5
- public static Worker = Worker
16
+ export default class LslStreamInlet implements LslInlet {
17
+ public static Class?: LslInletConstructor
6
18
  public static waitAfterOpenStreamMs = 100
7
- public static setTimeout = setTimeout
19
+ public static lsl = LiblslAdapter.getInstance()
20
+ public static handleLslError = handleLslError
21
+ public static freePointer = freePointer
22
+
23
+ public isRunning = false
8
24
 
9
25
  private sourceId: string
10
26
  private chunkSize: number
11
27
  private maxBufferedMs: number
12
28
  private pullTimeoutMs: number
13
29
  private openStreamTimeoutMs: number
14
- private waitAfterOpenStreamMs: number
15
30
  private waitBetweenPullsMs: number
16
31
  private flushInletOnStop: boolean
17
32
  private onData: OnDataCallback
18
33
 
19
- private worker!: Worker
20
- private workerReady = false
34
+ private infoHandle!: InfoHandle
35
+ private inletHandle!: InletHandle
36
+ private channelCount!: number
37
+
38
+ private pullMethod!: () => {
39
+ samples: number[] | undefined
40
+ timestamps: number[] | undefined
41
+ }
42
+
43
+ private sampleBuffer!: Buffer<ArrayBuffer>
44
+ private sampleBufferRef!: JsExternal[]
45
+ private sampleBufferPtr!: JsExternal
46
+
47
+ private timestampBuffer!: Buffer<ArrayBuffer>
48
+ private timestampBufferRef!: JsExternal[]
49
+ private timestampBufferPtr!: JsExternal
50
+
51
+ private pullErrorBuffer!: Buffer<ArrayBuffer>
52
+ private pullErrorBufferRef!: JsExternal[]
53
+ private pullErrorBufferPtr!: JsExternal
54
+
55
+ private openStreamErrorBuffer!: Buffer<ArrayBuffer>
56
+ private openStreamErrorBufferRef!: JsExternal[]
57
+ private openStreamErrorBufferPtr!: JsExternal
21
58
 
22
59
  private readonly sixMinutesInMs = 360 * 1000
23
60
  private readonly aboutOneYearInMs = 32000000 * 1000
24
61
 
25
- public isRunning = false
62
+ private readonly bytesPerFloat = 4
63
+ private readonly bytesPerDouble = 8
64
+ private readonly bytesPerI32 = 4
26
65
 
27
- protected constructor(options: StreamInletOptions, onData: OnDataCallback) {
66
+ protected constructor(options: LslInletOptions, onData: OnDataCallback) {
28
67
  const {
29
68
  sourceId,
30
69
  chunkSize,
31
70
  maxBufferedMs,
32
71
  pullTimeoutMs,
33
72
  openStreamTimeoutMs,
34
- waitAfterOpenStreamMs,
35
73
  waitBetweenPullsMs,
36
74
  flushInletOnStop,
37
75
  } = options ?? {}
@@ -41,114 +79,301 @@ export default class LslStreamInlet implements StreamInlet {
41
79
  this.maxBufferedMs = maxBufferedMs ?? this.sixMinutesInMs
42
80
  this.pullTimeoutMs = pullTimeoutMs ?? 0
43
81
  this.openStreamTimeoutMs = openStreamTimeoutMs ?? this.aboutOneYearInMs
44
- this.waitAfterOpenStreamMs = waitAfterOpenStreamMs ?? this.defaultWaitMs
45
82
  this.waitBetweenPullsMs = waitBetweenPullsMs ?? 1
46
83
  this.flushInletOnStop = flushInletOnStop ?? true
47
84
  this.onData = onData
48
-
49
- this.createWorkerThread()
50
85
  }
51
86
 
52
87
  public static async Create(
53
- options: StreamInletOptions,
88
+ options: LslInletOptions,
54
89
  onData: OnDataCallback
55
90
  ) {
56
91
  return new (this.Class ?? this)(options, onData)
57
92
  }
58
93
 
59
- private createWorkerThread() {
60
- this.worker = new this.Worker(
61
- new URL('./workers/inlet/LslStreamInlet.worker.js', import.meta.url)
94
+ public async startPulling() {
95
+ if (this.isRunning) {
96
+ console.warn('Skipping startPulling: inlet is already running!')
97
+ return
98
+ }
99
+
100
+ this.isRunning = true
101
+
102
+ await this.createInlet()
103
+ void this.pullLoop()
104
+ }
105
+
106
+ private async createInlet() {
107
+ this.infoHandle = this.resolveInfoHandle()
108
+ this.inletHandle = this.doCreateInlet()
109
+ this.channelCount = this.getChannelCount()
110
+
111
+ this.allocateWritableBuffers()
112
+ this.setPullMethod()
113
+
114
+ this.openStream()
115
+ }
116
+
117
+ private resolveInfoHandle() {
118
+ const handles = this.resolveByProp()
119
+
120
+ if (handles.length === 0) {
121
+ this.throwNoStreamFound()
122
+ } else if (handles.length > 1) {
123
+ this.warnMultipleStreamsFound()
124
+ }
125
+ return handles[0]
126
+ }
127
+
128
+ private resolveByProp() {
129
+ return this.lsl.resolveByProp({
130
+ prop: 'source_id',
131
+ value: this.sourceId,
132
+ })
133
+ }
134
+
135
+ private throwNoStreamFound() {
136
+ throw new Error(`No stream info for sourceId "${this.sourceId}"`)
137
+ }
138
+
139
+ private warnMultipleStreamsFound() {
140
+ console.warn(
141
+ `Multiple stream infos for sourceId "${this.sourceId}", using the first one.`
62
142
  )
143
+ }
63
144
 
64
- this.worker.on('message', (msg) => {
65
- const { type } = msg
66
-
67
- switch (type) {
68
- case 'ready': {
69
- this.workerReady = true
70
- break
71
- }
72
- case 'data': {
73
- const { payload } = msg
74
- const { samples, timestamps } = payload
75
-
76
- this.onData(samples, timestamps)
77
- break
78
- }
79
- case 'error': {
80
- const { error } = msg
81
- throw new Error(error)
82
- }
83
- default:
84
- throw new Error(`Unknown message type: ${type}`)
85
- }
145
+ private doCreateInlet() {
146
+ return this.lsl.createInlet({
147
+ infoHandle: this.infoHandle,
148
+ maxBufferedMs: this.maxBufferedMs,
86
149
  })
87
150
  }
88
151
 
89
- public async startPulling() {
90
- if (!this.isRunning) {
91
- this.isRunning = true
92
- this.postCreate()
93
-
94
- while (!this.workerReady) {
95
- await new Promise((resolve) =>
96
- LslStreamInlet.setTimeout(resolve, 10)
97
- )
152
+ private getChannelCount() {
153
+ return this.lsl.getChannelCount({ infoHandle: this.infoHandle })
154
+ }
155
+
156
+ private allocateWritableBuffers() {
157
+ this.allocateDataBuffer()
158
+ this.allocateTimestampBuffer()
159
+ this.allocatePullErrorBuffer()
160
+ this.allocateOpenStreamErrorBuffer()
161
+ }
162
+
163
+ private allocateDataBuffer() {
164
+ this.sampleBuffer = Buffer.alloc(
165
+ this.channelCount * this.chunkSize * this.bytesPerFloat
166
+ )
167
+
168
+ this.sampleBufferRef = createPointer({
169
+ paramsType: [DataType.U8Array],
170
+ paramsValue: [this.sampleBuffer],
171
+ })
172
+
173
+ this.sampleBufferPtr = unwrapPointer(this.sampleBufferRef)[0]
174
+ }
175
+
176
+ private allocateTimestampBuffer() {
177
+ this.timestampBuffer = Buffer.alloc(
178
+ this.chunkSize * this.bytesPerDouble
179
+ )
180
+
181
+ this.timestampBufferRef = createPointer({
182
+ paramsType: [DataType.U8Array],
183
+ paramsValue: [this.timestampBuffer],
184
+ })
185
+
186
+ this.timestampBufferPtr = unwrapPointer(this.timestampBufferRef)[0]
187
+ }
188
+
189
+ private allocatePullErrorBuffer() {
190
+ this.pullErrorBuffer = Buffer.alloc(this.bytesPerI32)
191
+
192
+ this.pullErrorBufferRef = createPointer({
193
+ paramsType: [DataType.U8Array],
194
+ paramsValue: [this.pullErrorBuffer],
195
+ })
196
+
197
+ this.pullErrorBufferPtr = unwrapPointer(this.pullErrorBufferRef)[0]
198
+ }
199
+
200
+ private allocateOpenStreamErrorBuffer() {
201
+ this.openStreamErrorBuffer = Buffer.alloc(this.bytesPerI32)
202
+
203
+ this.openStreamErrorBufferRef = createPointer({
204
+ paramsType: [DataType.U8Array],
205
+ paramsValue: [this.openStreamErrorBuffer],
206
+ })
207
+
208
+ this.openStreamErrorBufferPtr = unwrapPointer(
209
+ this.openStreamErrorBufferRef
210
+ )[0]
211
+ }
212
+
213
+ private setPullMethod() {
214
+ this.pullMethod =
215
+ this.chunkSize === 1 ? this.pullSample : this.pullChunk
216
+ }
217
+
218
+ private pullSample = () => {
219
+ const timestampSec = this.doPullsample()
220
+
221
+ if (timestampSec > 0) {
222
+ return {
223
+ samples: this.readSamplesFromBuffer(),
224
+ timestamps: [timestampSec],
98
225
  }
226
+ }
227
+ return { samples: undefined, timestamps: undefined }
228
+ }
99
229
 
100
- this.postStartPulling()
101
- } else {
102
- console.warn('Skipping startPulling: inlet is already running!')
230
+ private doPullsample() {
231
+ return this.lsl.pullSample({
232
+ inletHandle: this.inletHandle,
233
+ sampleBufferPtr: this.sampleBufferPtr,
234
+ sampleBufferElements: this.channelCount,
235
+ timeoutMs: this.pullTimeoutMs,
236
+ errorCodePtr: this.pullErrorBufferPtr,
237
+ })
238
+ }
239
+
240
+ private readSamplesFromBuffer() {
241
+ const floats = new Float32Array(
242
+ this.sampleBuffer.buffer,
243
+ this.sampleBuffer.byteOffset,
244
+ this.chunkSize * this.channelCount
245
+ )
246
+ return Array.from(floats)
247
+ }
248
+
249
+ private pullChunk = () => {
250
+ const firstTimestampSec = this.doPullChunk()
251
+
252
+ if (firstTimestampSec > 0) {
253
+ return {
254
+ samples: this.readSamplesFromBuffer(),
255
+ timestamps: this.readTimestampsFromBuffer(),
256
+ }
103
257
  }
258
+ return { samples: undefined, timestamps: undefined }
104
259
  }
105
260
 
106
- private postCreate() {
107
- this.worker.postMessage({
108
- type: 'createInlet',
109
- payload: {
110
- sourceId: this.sourceId,
111
- chunkSize: this.chunkSize,
112
- maxBufferedMs: this.maxBufferedMs,
113
- openStreamTimeoutMs: this.openStreamTimeoutMs,
114
- waitAfterOpenStreamMs: this.waitAfterOpenStreamMs,
115
- pullTimeoutMs: this.pullTimeoutMs,
116
- waitBetweenPullsMs: this.waitBetweenPullsMs,
117
- flushInletOnStop: this.flushInletOnStop,
118
- },
261
+ private doPullChunk() {
262
+ return this.lsl.pullChunk({
263
+ inletHandle: this.inletHandle,
264
+ sampleBufferPtr: this.sampleBufferPtr,
265
+ sampleBufferElements: this.chunkSize * this.channelCount,
266
+ timestampBufferPtr: this.timestampBufferPtr,
267
+ timestampBufferElements: this.chunkSize,
268
+ timeoutMs: this.pullTimeoutMs,
269
+ errorCodePtr: this.pullErrorBufferPtr,
119
270
  })
120
271
  }
121
272
 
122
- private postStartPulling() {
123
- this.worker.postMessage({ type: 'startPulling' })
273
+ private readTimestampsFromBuffer() {
274
+ const doubles = new Float64Array(
275
+ this.timestampBuffer.buffer,
276
+ this.timestampBuffer.byteOffset,
277
+ this.chunkSize
278
+ )
279
+ return Array.from(doubles)
280
+ }
281
+
282
+ private openStream() {
283
+ this.lsl.openStream({
284
+ inletHandle: this.inletHandle,
285
+ timeoutMs: this.openStreamTimeoutMs,
286
+ errorCodePtr: this.openStreamErrorBufferPtr,
287
+ })
288
+ }
289
+
290
+ private async pullLoop() {
291
+ while (this.isRunning) {
292
+ await this.pullDataOnce()
293
+ await this.waitBetweenPulls()
294
+ }
295
+ }
296
+
297
+ private async pullDataOnce() {
298
+ const { samples, timestamps } = this.pullMethod()
299
+ this.handleLslErrorIfPresent()
300
+
301
+ if (samples && timestamps) {
302
+ this.onData(samples, timestamps)
303
+ }
304
+ }
305
+
306
+ private handleLslErrorIfPresent() {
307
+ const errorCode = this.pullErrorBuffer.readInt32LE()
308
+ this.handleLslError(errorCode)
309
+ }
310
+
311
+ private async waitBetweenPulls() {
312
+ await new Promise((r) => setTimeout(r, this.waitBetweenPullsMs))
313
+ }
314
+
315
+ public flushInlet() {
316
+ this.lsl.flushInlet({ inletHandle: this.inletHandle })
124
317
  }
125
318
 
126
319
  public stopPulling() {
127
320
  this.isRunning = false
128
- this.worker.postMessage({ type: 'stopPulling' })
321
+ this.closeStream()
322
+
323
+ if (this.flushInletOnStop) {
324
+ this.flushInlet()
325
+ }
129
326
  }
130
327
 
131
- public flushInlet() {
132
- this.worker.postMessage({ type: 'flushInlet' })
328
+ private closeStream() {
329
+ this.lsl.closeStream({ inletHandle: this.inletHandle })
133
330
  }
134
331
 
135
332
  public destroy() {
136
333
  if (this.isRunning) {
137
334
  this.stopPulling()
138
335
  }
139
- this.worker.postMessage({ type: 'destroyInlet' })
336
+
337
+ this.doDestroyInlet()
338
+ this.freeNativePointers()
339
+ }
340
+
341
+ private doDestroyInlet() {
342
+ this.lsl.destroyInlet({ inletHandle: this.inletHandle })
343
+ }
344
+
345
+ private freeNativePointers() {
346
+ this.freePointer({
347
+ paramsType: [
348
+ DataType.U8Array,
349
+ DataType.U8Array,
350
+ DataType.U8Array,
351
+ DataType.U8Array,
352
+ ],
353
+ paramsValue: [
354
+ this.openStreamErrorBufferPtr,
355
+ this.sampleBufferPtr,
356
+ this.timestampBufferPtr,
357
+ this.pullErrorBufferPtr,
358
+ ],
359
+ pointerType: PointerType.CPointer,
360
+ })
361
+ }
362
+
363
+ private get lsl() {
364
+ return LslStreamInlet.lsl
140
365
  }
141
366
 
142
- private get defaultWaitMs() {
143
- return LslStreamInlet.waitAfterOpenStreamMs
367
+ private get handleLslError() {
368
+ return LslStreamInlet.handleLslError
144
369
  }
145
370
 
146
- private get Worker() {
147
- return LslStreamInlet.Worker
371
+ private get freePointer() {
372
+ return LslStreamInlet.freePointer
148
373
  }
149
374
  }
150
375
 
151
- export interface StreamInlet {
376
+ export interface LslInlet {
152
377
  startPulling(): Promise<void>
153
378
  stopPulling(): void
154
379
  flushInlet(): void
@@ -156,17 +381,16 @@ export interface StreamInlet {
156
381
  readonly isRunning: boolean
157
382
  }
158
383
 
159
- export type StreamInletConstructor = new (
160
- options: StreamInletOptions,
384
+ export type LslInletConstructor = new (
385
+ options: LslInletOptions,
161
386
  onData: OnDataCallback
162
- ) => StreamInlet
387
+ ) => LslInlet
163
388
 
164
- export interface StreamInletOptions {
389
+ export interface LslInletOptions {
165
390
  sourceId: string
166
391
  chunkSize: number
167
392
  maxBufferedMs?: number
168
393
  openStreamTimeoutMs?: number
169
- waitAfterOpenStreamMs?: number
170
394
  pullTimeoutMs?: number
171
395
  waitBetweenPullsMs?: number
172
396
  flushInletOnStop?: boolean