@neurodevs/node-lsl 17.1.1 → 18.1.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 (198) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.vscode/launch.json +54 -57
  3. package/.vscode/settings.json +61 -66
  4. package/.vscode/tasks.json +98 -129
  5. package/README.md +20 -44
  6. package/build/__tests__/AbstractPackageTest.d.ts +7 -5
  7. package/build/__tests__/AbstractPackageTest.js +22 -15
  8. package/build/__tests__/AbstractPackageTest.js.map +1 -1
  9. package/build/__tests__/impl/BleDeviceController.test.d.ts +54 -0
  10. package/build/__tests__/impl/BleDeviceController.test.js +333 -0
  11. package/build/__tests__/impl/BleDeviceController.test.js.map +1 -0
  12. package/build/__tests__/impl/LslEventMarkerEmitter.test.d.ts +34 -0
  13. package/build/__tests__/impl/LslEventMarkerEmitter.test.js +243 -0
  14. package/build/__tests__/impl/LslEventMarkerEmitter.test.js.map +1 -0
  15. package/build/__tests__/impl/LslStreamInfo.test.d.ts +0 -3
  16. package/build/__tests__/impl/LslStreamInfo.test.js +2 -27
  17. package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
  18. package/build/__tests__/impl/LslStreamInlet.test.d.ts +20 -8
  19. package/build/__tests__/impl/LslStreamInlet.test.js +224 -69
  20. package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
  21. package/build/__tests__/impl/LslStreamOutlet.test.d.ts +3 -7
  22. package/build/__tests__/impl/LslStreamOutlet.test.js +40 -50
  23. package/build/__tests__/impl/LslStreamOutlet.test.js.map +1 -1
  24. package/build/__tests__/impl/LslWebSocketBridge.test.js +19 -20
  25. package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
  26. package/build/assertions.d.ts +1 -1
  27. package/build/assertions.js.map +1 -1
  28. package/build/impl/LslEventMarkerEmitter.d.ts +35 -0
  29. package/build/impl/LslEventMarkerEmitter.js +86 -0
  30. package/build/impl/LslEventMarkerEmitter.js.map +1 -0
  31. package/build/impl/LslStreamInfo.d.ts +4 -8
  32. package/build/impl/LslStreamInfo.js +8 -21
  33. package/build/impl/LslStreamInfo.js.map +1 -1
  34. package/build/impl/LslStreamInlet.d.ts +31 -50
  35. package/build/impl/LslStreamInlet.js +79 -149
  36. package/build/impl/LslStreamInlet.js.map +1 -1
  37. package/build/impl/LslStreamOutlet.d.ts +15 -18
  38. package/build/impl/LslStreamOutlet.js +39 -47
  39. package/build/impl/LslStreamOutlet.js.map +1 -1
  40. package/build/impl/LslWebSocketBridge.d.ts +4 -5
  41. package/build/impl/LslWebSocketBridge.js +10 -10
  42. package/build/impl/LslWebSocketBridge.js.map +1 -1
  43. package/build/impl/controllers/BleDeviceController.d.ts +58 -0
  44. package/build/impl/controllers/BleDeviceController.js +145 -0
  45. package/build/impl/controllers/BleDeviceController.js.map +1 -0
  46. package/build/impl/workers/inlet/LslStreamInlet.worker.d.ts +22 -0
  47. package/build/impl/workers/inlet/LslStreamInlet.worker.js +42 -0
  48. package/build/impl/workers/inlet/LslStreamInlet.worker.js.map +1 -0
  49. package/build/impl/workers/inlet/StreamInletWorker.d.ts +73 -0
  50. package/build/impl/workers/inlet/StreamInletWorker.js +253 -0
  51. package/build/impl/workers/inlet/StreamInletWorker.js.map +1 -0
  52. package/build/impl/workers/outlet/LslStreamOutlet.worker.d.ts +32 -0
  53. package/build/impl/workers/outlet/LslStreamOutlet.worker.js +82 -0
  54. package/build/impl/workers/outlet/LslStreamOutlet.worker.js.map +1 -0
  55. package/build/index.d.ts +14 -14
  56. package/build/index.js +16 -16
  57. package/build/index.js.map +1 -1
  58. package/build/scripts/discoverMuse.js +40 -0
  59. package/build/scripts/discoverMuse.js.map +1 -0
  60. package/build/scripts/finalizeHandles.d.ts +2 -0
  61. package/build/scripts/finalizeHandles.js +48 -0
  62. package/build/scripts/finalizeHandles.js.map +1 -0
  63. package/build/scripts/runLslEventMarkerEmitter.d.ts +1 -0
  64. package/build/scripts/runLslEventMarkerEmitter.js +11 -0
  65. package/build/scripts/runLslEventMarkerEmitter.js.map +1 -0
  66. package/build/scripts/runMuse.d.ts +1 -0
  67. package/build/scripts/runMuse.js +40 -0
  68. package/build/scripts/runMuse.js.map +1 -0
  69. package/build/scripts/runOutletToInlet.js +7 -6
  70. package/build/scripts/runOutletToInlet.js.map +1 -1
  71. package/build/scripts/testDestroyOutlet.d.ts +1 -0
  72. package/build/scripts/testDestroyOutlet.js +4 -0
  73. package/build/scripts/testDestroyOutlet.js.map +1 -0
  74. package/build/testDoubles/BleController/FakeBleController.d.ts +24 -0
  75. package/build/testDoubles/BleController/FakeBleController.js +42 -0
  76. package/build/testDoubles/BleController/FakeBleController.js.map +1 -0
  77. package/build/testDoubles/BleController/SpyBleController.d.ts +14 -0
  78. package/build/testDoubles/BleController/SpyBleController.js +48 -0
  79. package/build/testDoubles/BleController/SpyBleController.js.map +1 -0
  80. package/build/testDoubles/EventMarkerEmitter/FakeEventMarkerEmitter.d.ts +17 -0
  81. package/build/testDoubles/EventMarkerEmitter/FakeEventMarkerEmitter.js +30 -0
  82. package/build/testDoubles/EventMarkerEmitter/FakeEventMarkerEmitter.js.map +1 -0
  83. package/build/testDoubles/EventMarkerEmitter/SpyEventMarkerEmitter.d.ts +10 -0
  84. package/build/testDoubles/EventMarkerEmitter/SpyEventMarkerEmitter.js +23 -0
  85. package/build/testDoubles/EventMarkerEmitter/SpyEventMarkerEmitter.js.map +1 -0
  86. package/build/testDoubles/EventMarkerEmitter/ThrowingEventMarkerEmitter.d.ts +9 -0
  87. package/build/testDoubles/EventMarkerEmitter/ThrowingEventMarkerEmitter.js +19 -0
  88. package/build/testDoubles/EventMarkerEmitter/ThrowingEventMarkerEmitter.js.map +1 -0
  89. package/build/testDoubles/StreamInfo/FakeStreamInfo.d.ts +3 -3
  90. package/build/testDoubles/StreamInfo/FakeStreamInfo.js +3 -3
  91. package/build/testDoubles/StreamInfo/FakeStreamInfo.js.map +1 -1
  92. package/build/testDoubles/StreamInlet/FakeStreamInlet.d.ts +8 -10
  93. package/build/testDoubles/StreamInlet/FakeStreamInlet.js +6 -7
  94. package/build/testDoubles/StreamInlet/FakeStreamInlet.js.map +1 -1
  95. package/build/testDoubles/StreamInlet/SpyStreamInlet.d.ts +2 -5
  96. package/build/testDoubles/StreamInlet/SpyStreamInlet.js +2 -8
  97. package/build/testDoubles/StreamInlet/SpyStreamInlet.js.map +1 -1
  98. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.d.ts +7 -9
  99. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js +8 -8
  100. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js.map +1 -1
  101. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.d.ts +1 -1
  102. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.js +1 -1
  103. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.js.map +1 -1
  104. package/build/testDoubles/WorkerThreads/FakeWorker.d.ts +27 -0
  105. package/build/testDoubles/WorkerThreads/FakeWorker.js +67 -0
  106. package/build/testDoubles/WorkerThreads/FakeWorker.js.map +1 -0
  107. package/build/testDoubles/generateRandomOutletOptions.js +1 -1
  108. package/build/testDoubles/generateRandomOutletOptions.js.map +1 -1
  109. package/build/validations.js +0 -2
  110. package/build/validations.js.map +1 -1
  111. package/eslint.config.js +3 -0
  112. package/package.json +27 -49
  113. package/prettier.config.js +3 -0
  114. package/src/__tests__/AbstractPackageTest.ts +38 -21
  115. package/src/__tests__/impl/BleDeviceController.test.ts +492 -0
  116. package/src/__tests__/impl/LslEventMarkerEmitter.test.ts +323 -0
  117. package/src/__tests__/impl/LslStreamInfo.test.ts +3 -40
  118. package/src/__tests__/impl/LslStreamInlet.test.ts +344 -97
  119. package/src/__tests__/impl/LslStreamOutlet.test.ts +65 -73
  120. package/src/__tests__/impl/LslWebSocketBridge.test.ts +22 -21
  121. package/src/assertions.ts +2 -1
  122. package/src/impl/LslEventMarkerEmitter.ts +133 -0
  123. package/src/impl/LslStreamInfo.ts +17 -29
  124. package/src/impl/LslStreamInlet.ts +102 -215
  125. package/src/impl/LslStreamOutlet.ts +54 -78
  126. package/src/impl/LslWebSocketBridge.ts +14 -14
  127. package/src/impl/controllers/BleDeviceController.ts +223 -0
  128. package/src/impl/workers/inlet/LslStreamInlet.worker.ts +74 -0
  129. package/src/impl/workers/inlet/StreamInletWorker.ts +348 -0
  130. package/src/impl/workers/outlet/LslStreamOutlet.worker.ts +144 -0
  131. package/src/index.ts +16 -16
  132. package/src/scripts/discoverMuse.ts +50 -0
  133. package/src/scripts/finalizeHandles.ts +63 -0
  134. package/src/scripts/runLslEventMarkerEmitter.ts +15 -0
  135. package/src/scripts/runMuse.ts +50 -0
  136. package/src/scripts/runOutletToInlet.ts +10 -8
  137. package/src/scripts/testDestroyOutlet.ts +5 -0
  138. package/src/testDoubles/BleController/FakeBleController.ts +70 -0
  139. package/src/testDoubles/BleController/SpyBleController.ts +61 -0
  140. package/src/testDoubles/EventMarkerEmitter/FakeEventMarkerEmitter.ts +46 -0
  141. package/src/testDoubles/EventMarkerEmitter/SpyEventMarkerEmitter.ts +31 -0
  142. package/src/testDoubles/EventMarkerEmitter/ThrowingEventMarkerEmitter.ts +29 -0
  143. package/src/testDoubles/StreamInfo/FakeStreamInfo.ts +4 -4
  144. package/src/testDoubles/StreamInlet/FakeStreamInlet.ts +11 -17
  145. package/src/testDoubles/StreamInlet/SpyStreamInlet.ts +3 -16
  146. package/src/testDoubles/StreamOutlet/FakeStreamOutlet.ts +15 -15
  147. package/src/testDoubles/WebSocketBridge/FakeWebSocketBridge.ts +1 -1
  148. package/src/testDoubles/WorkerThreads/FakeWorker.ts +99 -0
  149. package/src/testDoubles/generateRandomOutletOptions.ts +2 -1
  150. package/src/validations.ts +0 -2
  151. package/tsconfig.json +23 -27
  152. package/build/.spruce/settings.json +0 -11
  153. package/build/__tests__/impl/LiblslAdapter.test.d.ts +0 -79
  154. package/build/__tests__/impl/LiblslAdapter.test.js +0 -688
  155. package/build/__tests__/impl/LiblslAdapter.test.js.map +0 -1
  156. package/build/__tests__/impl/LslEventMarkerOutlet.test.d.ts +0 -21
  157. package/build/__tests__/impl/LslEventMarkerOutlet.test.js +0 -160
  158. package/build/__tests__/impl/LslEventMarkerOutlet.test.js.map +0 -1
  159. package/build/handleError.d.ts +0 -8
  160. package/build/handleError.js +0 -25
  161. package/build/handleError.js.map +0 -1
  162. package/build/impl/LiblslAdapter.d.ts +0 -154
  163. package/build/impl/LiblslAdapter.js +0 -317
  164. package/build/impl/LiblslAdapter.js.map +0 -1
  165. package/build/impl/LslEventMarkerOutlet.d.ts +0 -28
  166. package/build/impl/LslEventMarkerOutlet.js +0 -63
  167. package/build/impl/LslEventMarkerOutlet.js.map +0 -1
  168. package/build/scripts/runLslEventMarkerOutlet.js +0 -18
  169. package/build/scripts/runLslEventMarkerOutlet.js.map +0 -1
  170. package/build/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.d.ts +0 -13
  171. package/build/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.js +0 -26
  172. package/build/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.js.map +0 -1
  173. package/build/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.d.ts +0 -17
  174. package/build/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.js +0 -46
  175. package/build/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.js.map +0 -1
  176. package/build/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.d.ts +0 -9
  177. package/build/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.js +0 -19
  178. package/build/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.js.map +0 -1
  179. package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.d.ts +0 -9
  180. package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.js +0 -19
  181. package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.js.map +0 -1
  182. package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +0 -50
  183. package/build/testDoubles/Liblsl/FakeLiblsl.js +0 -126
  184. package/build/testDoubles/Liblsl/FakeLiblsl.js.map +0 -1
  185. package/eslint.config.mjs +0 -3
  186. package/src/.spruce/settings.json +0 -11
  187. package/src/__tests__/impl/LiblslAdapter.test.ts +0 -817
  188. package/src/__tests__/impl/LslEventMarkerOutlet.test.ts +0 -195
  189. package/src/handleError.ts +0 -24
  190. package/src/impl/LiblslAdapter.ts +0 -543
  191. package/src/impl/LslEventMarkerOutlet.ts +0 -97
  192. package/src/scripts/runLslEventMarkerOutlet.ts +0 -23
  193. package/src/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.ts +0 -36
  194. package/src/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.ts +0 -75
  195. package/src/testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.ts +0 -24
  196. package/src/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.ts +0 -28
  197. package/src/testDoubles/Liblsl/FakeLiblsl.ts +0 -182
  198. /package/build/scripts/{runLslEventMarkerOutlet.d.ts → discoverMuse.d.ts} +0 -0
@@ -1,817 +0,0 @@
1
- import { randomInt } from 'crypto'
2
- import { test, assert } from '@neurodevs/node-tdd'
3
- import {
4
- createPointer,
5
- DataType,
6
- FieldType,
7
- FuncObj,
8
- OpenParams,
9
- unwrapPointer,
10
- } from 'ffi-rs'
11
-
12
- import {
13
- BoundChild,
14
- BoundDescription,
15
- BoundInlet,
16
- BoundOutlet,
17
- BoundStreamInfo,
18
- Liblsl,
19
- LiblslBindings,
20
- LslChannel,
21
- ResolveByPropOptions,
22
- } from 'impl/LiblslAdapter.js'
23
- import LiblslAdapter from '../../impl/LiblslAdapter.js'
24
- import FakeLiblsl from '../../testDoubles/Liblsl/FakeLiblsl.js'
25
- import AbstractPackageTest from '../AbstractPackageTest.js'
26
-
27
- export default class LiblslAdapterTest extends AbstractPackageTest {
28
- private static instance: Liblsl
29
- private static libraryPath?: string
30
- private static libraryOptions?: Record<string, any>
31
- private static fakeBindings: LiblslBindings
32
- private static fakeStreamInfo: BoundStreamInfo
33
- private static fakeOutlet: BoundOutlet
34
- private static fakeInlet: BoundInlet = {}
35
- private static fakeDesc: BoundDescription
36
- private static fakeChildNamedChannels: BoundChild
37
-
38
- private static createStreamInfoParams?: any[]
39
- private static destroyStreamInfoParams?: any[]
40
- private static appendChildParams: any[] = []
41
- private static createOutletParams?: any[]
42
- private static destroyOutletParams?: any[]
43
- private static createInletParams?: any[]
44
- private static flushInletParams?: any[]
45
- private static destroyInletParams?: any[]
46
- private static localClockParams?: any[]
47
- private static pushSampleFloatTimestampParams?: any[]
48
- private static pushSampleStringTimestampParams?: any[]
49
- private static appendChildValueParams: any[]
50
- private static shouldThrowWhenCreatingBindings: boolean
51
- private static getDescriptionParams?: [BoundStreamInfo]
52
- private static fakeChildNamedChannel: BoundChild
53
- private static appendChildHitCount: number
54
- private static ffiRsOpenOptions?: OpenParams
55
- private static ffiRsDefineOptions: FfiRsDefineOptions
56
- private static ffiRsLoadOptions?: Record<string, any>
57
-
58
- protected static async beforeEach() {
59
- await super.beforeEach()
60
-
61
- delete this.libraryPath
62
- delete this.libraryOptions
63
- delete this.createStreamInfoParams
64
- delete this.createOutletParams
65
- delete this.destroyOutletParams
66
- delete this.createInletParams
67
- delete this.destroyInletParams
68
- delete this.pushSampleFloatTimestampParams
69
- delete this.getDescriptionParams
70
- this.appendChildParams = []
71
- this.appendChildValueParams = []
72
-
73
- process.env.LIBLSL_PATH = this.generateId()
74
-
75
- this.fakeStreamInfo = {}
76
- this.fakeDesc = {}
77
- this.fakeOutlet = {}
78
- this.fakeChildNamedChannels = {}
79
- this.fakeChildNamedChannel = {}
80
- this.fakeBindings = this.FakeBindings()
81
-
82
- this.shouldThrowWhenCreatingBindings = false
83
-
84
- this.appendChildHitCount = 0
85
-
86
- delete this.ffiRsOpenOptions
87
- LiblslAdapter.open = (options) => {
88
- this.ffiRsOpenOptions = options
89
- }
90
-
91
- LiblslAdapter.define = (options) => {
92
- this.ffiRsDefineOptions = options as FfiRsDefineOptions
93
- if (this.shouldThrowWhenCreatingBindings) {
94
- throw new Error('Failed to create bindings!')
95
- }
96
- return this.fakeBindings as any
97
- }
98
-
99
- LiblslAdapter.load = (options) => {
100
- this.ffiRsLoadOptions = options
101
- return this.fakeNumResolveResults as any
102
- }
103
-
104
- LiblslAdapter.resetInstance()
105
- this.instance = LiblslAdapter.getInstance()
106
- }
107
-
108
- @test()
109
- protected static async createsInstance() {
110
- assert.isTruthy(this.instance, 'Failed to create instance!')
111
- }
112
-
113
- @test()
114
- protected static async throwsWhenBindingsFailToLoad() {
115
- this.shouldThrowWhenCreatingBindings = true
116
- LiblslAdapter.resetInstance()
117
-
118
- const err = assert.doesThrow(() => LiblslAdapter.getInstance())
119
-
120
- assert.isTrue(
121
- err.message.includes(this.generateFailedMessage()),
122
- 'Did not receive the expected error!'
123
- )
124
- }
125
-
126
- @test()
127
- protected static async callsOpenOnFfiRs() {
128
- assert.isEqualDeep(this.ffiRsOpenOptions, {
129
- library: 'lsl',
130
- path: process.env.LIBLSL_PATH,
131
- })
132
- }
133
-
134
- @test()
135
- protected static async worksAsASingleton() {
136
- const liblsl = LiblslAdapter.getInstance()
137
- //@ts-ignore
138
- assert.isInstanceOf(liblsl, LiblslAdapter)
139
- }
140
-
141
- @test()
142
- protected static async singletonIsTheSame() {
143
- assert.isEqual(LiblslAdapter.getInstance(), LiblslAdapter.getInstance())
144
- }
145
-
146
- @test()
147
- protected static canSetInstance() {
148
- const fake = new FakeLiblsl()
149
- LiblslAdapter.setInstance(fake)
150
- assert.isEqual(LiblslAdapter.getInstance(), fake)
151
- }
152
-
153
- @test()
154
- protected static async createsExpectedBindingsWithFfiRs() {
155
- assert.isEqualDeep(this.ffiRsDefineOptions, {
156
- lsl_create_streaminfo: {
157
- library: 'lsl',
158
- retType: DataType.External,
159
- paramsType: [
160
- DataType.String,
161
- DataType.String,
162
- DataType.I32,
163
- DataType.Double,
164
- DataType.I32,
165
- DataType.String,
166
- ],
167
- },
168
- lsl_destroy_streaminfo: {
169
- library: 'lsl',
170
- retType: DataType.Void,
171
- paramsType: [DataType.External],
172
- },
173
- lsl_create_outlet: {
174
- library: 'lsl',
175
- retType: DataType.External,
176
- paramsType: [DataType.External, DataType.I32, DataType.I32],
177
- },
178
- lsl_push_sample_ft: {
179
- library: 'lsl',
180
- retType: DataType.I32,
181
- paramsType: [
182
- DataType.External,
183
- DataType.FloatArray,
184
- DataType.Double,
185
- ],
186
- },
187
- lsl_push_sample_strt: {
188
- library: 'lsl',
189
- retType: DataType.I32,
190
- paramsType: [
191
- DataType.External,
192
- DataType.StringArray,
193
- DataType.Double,
194
- ],
195
- },
196
- lsl_destroy_outlet: {
197
- library: 'lsl',
198
- retType: DataType.Void,
199
- paramsType: [DataType.External],
200
- },
201
- lsl_create_inlet: {
202
- library: 'lsl',
203
- retType: DataType.External,
204
- paramsType: [
205
- DataType.External,
206
- DataType.I32,
207
- DataType.I32,
208
- DataType.I32,
209
- ],
210
- },
211
- lsl_flush_inlet: {
212
- library: 'lsl',
213
- retType: DataType.I32,
214
- paramsType: [DataType.External],
215
- },
216
- lsl_destroy_inlet: {
217
- library: 'lsl',
218
- retType: DataType.Void,
219
- paramsType: [DataType.External],
220
- },
221
- lsl_get_desc: {
222
- library: 'lsl',
223
- retType: DataType.External,
224
- paramsType: [DataType.External],
225
- },
226
- lsl_append_child: {
227
- library: 'lsl',
228
- retType: DataType.External,
229
- paramsType: [DataType.External, DataType.String],
230
- },
231
- lsl_append_child_value: {
232
- library: 'lsl',
233
- retType: DataType.External,
234
- paramsType: [
235
- DataType.External,
236
- DataType.String,
237
- DataType.String,
238
- ],
239
- },
240
- lsl_local_clock: {
241
- library: 'lsl',
242
- retType: DataType.Double,
243
- paramsType: [],
244
- },
245
- })
246
- }
247
-
248
- @test()
249
- protected static async createsStreamInfoWithRequiredParams() {
250
- const options = this.generateRandomCreateStreamInfoOptions()
251
- const actual = this.instance.createStreamInfo(options)
252
-
253
- assert.isEqual(actual, this.fakeStreamInfo)
254
- assert.isEqualDeep(this.createStreamInfoParams, Object.values(options))
255
- }
256
-
257
- @test()
258
- protected static async destroysStreamInfoWithBoundInfo() {
259
- const info = this.createRandomStreamInfo()
260
- this.instance.destroyStreamInfo({ info })
261
-
262
- assert.isEqualDeep(
263
- this.destroyStreamInfoParams,
264
- [info],
265
- 'Did not call destroyStreamInfo with expected params!'
266
- )
267
- }
268
-
269
- @test()
270
- protected static async resolvesStreamInfoByProp() {
271
- await this.resolveByProp()
272
-
273
- assert.isEqualDeep(
274
- this.ffiRsLoadOptions,
275
- {
276
- library: 'lsl',
277
- funcName: 'lsl_resolve_byprop',
278
- retType: DataType.I32,
279
- paramsType: [
280
- DataType.External,
281
- DataType.I32,
282
- DataType.String,
283
- DataType.String,
284
- DataType.I32,
285
- DataType.Double,
286
- ],
287
- paramsValue: [
288
- this.resultsBufferPtr,
289
- this.maxResults,
290
- this.prop,
291
- this.value,
292
- this.minResults,
293
- this.timeoutMs / 1000,
294
- ],
295
- runInNewThread: true,
296
- },
297
- 'Did not call resolveByProp with expected params!'
298
- )
299
- }
300
-
301
- @test()
302
- protected static async resolveByPropAcceptsOptionalArgs() {
303
- const minResults = randomInt(0, 10)
304
- const timeoutMs = Math.random() * 1000
305
-
306
- await this.resolveByProp({
307
- minResults,
308
- timeoutMs,
309
- })
310
-
311
- assert.isEqualDeep(
312
- {
313
- minResults: this.ffiRsLoadOptions?.['paramsValue']?.[4],
314
- timeoutMs: this.ffiRsLoadOptions?.['paramsValue']?.[5],
315
- },
316
- { minResults, timeoutMs: timeoutMs / 1000 },
317
- 'Did not call resolveByProp with expected params!'
318
- )
319
- }
320
-
321
- @test()
322
- protected static async returnsHandlesForResolvedStreamInfos() {
323
- LiblslAdapter.alloc = (size: number) => {
324
- const buffer = Buffer.alloc(size)
325
-
326
- for (let i = 0; i < this.fakeNumResolveResults; i++) {
327
- const offset = i * this.bytesPerPointer
328
- buffer.writeBigUInt64LE(BigInt(i + 1), offset)
329
- }
330
-
331
- return buffer
332
- }
333
-
334
- const expectedHandles: bigint[] = []
335
-
336
- for (let i = 0; i < this.fakeNumResolveResults; i++) {
337
- expectedHandles.push(BigInt(i + 1))
338
- }
339
-
340
- const actualHandles = await this.resolveByProp()
341
-
342
- const actual = actualHandles.map((h) => h.toString())
343
- const expected = expectedHandles.map((h) => h.toString())
344
-
345
- assert.isEqualDeep(
346
- actual,
347
- expected,
348
- 'Did not receive expected resolved stream info handles!'
349
- )
350
- }
351
-
352
- @test()
353
- protected static async createsOutletWithRequiredParams() {
354
- const { options, outlet } = this.createRandomOutlet()
355
-
356
- const expected = {
357
- ...options,
358
- maxBufferedMs: options.maxBufferedMs / 1000,
359
- }
360
-
361
- assert.isEqualDeep(this.createOutletParams, Object.values(expected))
362
- assert.isEqual(outlet, this.fakeOutlet)
363
- }
364
-
365
- @test()
366
- protected static async pushesFloatSample() {
367
- const expected = [1.0, 2.0, 3.0]
368
- const timestamp = randomInt(100)
369
- const options = {
370
- outlet: this.fakeOutlet,
371
- sample: expected,
372
- timestamp,
373
- }
374
- this.instance.pushSampleFloatTimestamp(options)
375
-
376
- assert.isEqualDeep(this.pushSampleFloatTimestampParams, [
377
- this.fakeOutlet,
378
- expected,
379
- timestamp,
380
- ])
381
- }
382
-
383
- @test()
384
- protected static async pushesStringSample() {
385
- const expected = [this.generateId()]
386
- const timestamp = randomInt(100)
387
- const options = {
388
- outlet: this.fakeOutlet,
389
- sample: expected,
390
- timestamp,
391
- }
392
- this.instance.pushSampleStringTimestamp(options)
393
- assert.isEqual(
394
- this.pushSampleStringTimestampParams?.[0],
395
- this.fakeOutlet
396
- )
397
- assert.isEqualDeep(this.pushSampleStringTimestampParams?.[1], expected)
398
- assert.isEqual(this.pushSampleStringTimestampParams?.[2], timestamp)
399
- }
400
-
401
- @test()
402
- protected static async addingSingleChannelGetsDescription() {
403
- const info = this.createRandomStreamInfo()
404
- const channel: LslChannel = this.generateRandomChannelValues()
405
-
406
- this.instance.appendChannelsToStreamInfo({
407
- info,
408
- channels: [channel],
409
- })
410
- assert.isEqualDeep(this.getDescriptionParams?.[0], [info])
411
-
412
- assert.isEqual(this.appendChildParams?.[0][0], this.fakeDesc)
413
- assert.isEqual(this.appendChildParams?.[0][1], 'channels')
414
-
415
- assert.isEqual(
416
- this.appendChildParams?.[1][0],
417
- this.fakeChildNamedChannels
418
- )
419
- assert.isEqual(this.appendChildParams?.[1][1], 'channel')
420
-
421
- assert.isLength(this.appendChildValueParams, 3)
422
-
423
- for (let i = 0; i < 3; i++) {
424
- const param = this.appendChildValueParams[i]
425
- assert.isEqual(param[0], this.fakeChildNamedChannel)
426
- }
427
-
428
- assert.isEqual(this.appendChildValueParams[0][1], 'label')
429
- assert.isEqual(this.appendChildValueParams[1][1], 'unit')
430
- assert.isEqual(this.appendChildValueParams[2][1], 'type')
431
-
432
- assert.isEqual(this.appendChildValueParams[0][2], channel.label)
433
- assert.isEqual(this.appendChildValueParams[1][2], channel.units)
434
- assert.isEqual(this.appendChildValueParams[2][2], channel.type)
435
- }
436
-
437
- @test()
438
- protected static async addingMultpleChannelsAddsChildrenToChannelsChild() {
439
- const info = this.createRandomStreamInfo()
440
- const channel1 = this.generateRandomChannelValues()
441
- const channel2 = this.generateRandomChannelValues()
442
-
443
- this.instance.appendChannelsToStreamInfo({
444
- info,
445
- channels: [channel1, channel2],
446
- })
447
-
448
- assert.isEqual(
449
- this.appendChildParams?.[2][0],
450
- this.fakeChildNamedChannels
451
- )
452
- assert.isEqual(this.appendChildParams?.[2][1], 'channel')
453
-
454
- assert.isEqual(this.appendChildValueParams[3][2], channel2.label)
455
- assert.isEqual(this.appendChildValueParams[4][2], channel2.units)
456
- assert.isEqual(this.appendChildValueParams[5][2], channel2.type)
457
- }
458
-
459
- @test()
460
- protected static async canDestroyOutlet() {
461
- const outlet = this.createRandomOutlet()
462
- const options = { outlet }
463
- this.instance.destroyOutlet(options)
464
-
465
- assert.isEqualDeep(this.destroyOutletParams, Object.values(options))
466
- }
467
-
468
- @test()
469
- protected static async callingLocalClockTwiceReturnsDifferentTimestamps() {
470
- const t1 = this.instance.localClock()
471
- await this.wait(10)
472
- const t2 = this.instance.localClock()
473
- assert.isNotEqual(t1, t2)
474
- }
475
-
476
- @test()
477
- protected static async localClockBindingReceivesEmptyArray() {
478
- delete this.localClockParams
479
- this.instance.localClock()
480
- assert.isEqualDeep(this.localClockParams, [])
481
- }
482
-
483
- @test()
484
- protected static async defaultsToMacOsPath() {
485
- delete process.env.LIBLSL_PATH
486
-
487
- LiblslAdapter.resetInstance()
488
- this.instance = LiblslAdapter.getInstance() as FakeLiblsl
489
-
490
- assert.isEqual(
491
- this.ffiRsOpenOptions?.path,
492
- '/opt/homebrew/Cellar/lsl/1.16.2/lib/liblsl.1.16.2.dylib'
493
- )
494
- }
495
-
496
- @test()
497
- protected static async createInletWithRequiredParams() {
498
- const { options, inlet } = this.createRandomInlet()
499
- const { maxBufferedMs } = options
500
-
501
- const expected = {
502
- ...options,
503
- maxBufferedMs: maxBufferedMs / 1000,
504
- }
505
-
506
- const maxChunkSize = 0
507
- const shouldRecover = 1
508
-
509
- assert.isEqualDeep(
510
- this.createInletParams,
511
- [...Object.values(expected), maxChunkSize, shouldRecover],
512
- 'Did not call createInlet with expected params!'
513
- )
514
-
515
- assert.isEqual(inlet, this.fakeInlet, 'Did not receive expected inlet!')
516
- }
517
-
518
- @test()
519
- protected static async pullSampleCallsBinding() {
520
- const { inlet } = this.createRandomInlet()
521
-
522
- const dataBuffer = Buffer.alloc(4 * this.channelCount)
523
- const dataBufferElements = this.channelCount
524
- const timeout = 0.0
525
-
526
- const dataBufferPtr = unwrapPointer(
527
- createPointer({
528
- paramsType: [DataType.U8Array],
529
- paramsValue: [dataBuffer],
530
- })
531
- )[0]
532
-
533
- const errcodePtr = unwrapPointer(
534
- createPointer({
535
- paramsType: [DataType.U8Array],
536
- paramsValue: [new Int32Array(1)],
537
- })
538
- )[0]
539
-
540
- this.instance.pullSample({
541
- inlet,
542
- dataBufferPtr,
543
- dataBufferElements,
544
- timeout,
545
- errcodePtr,
546
- })
547
-
548
- assert.isEqualDeep(
549
- this.ffiRsLoadOptions,
550
- {
551
- library: 'lsl',
552
- funcName: 'lsl_pull_sample_f',
553
- retType: DataType.Double,
554
- paramsType: [
555
- DataType.External,
556
- DataType.External,
557
- DataType.I32,
558
- DataType.Double,
559
- DataType.External,
560
- ],
561
- paramsValue: [
562
- inlet,
563
- dataBufferPtr,
564
- dataBufferElements,
565
- timeout,
566
- errcodePtr,
567
- ],
568
- },
569
- 'Did not call pullSample with expected options!'
570
- )
571
- }
572
-
573
- @test()
574
- protected static async pullChunkCallsBinding() {
575
- const { inlet } = this.createRandomInlet()
576
-
577
- const dataBuffer = Buffer.alloc(4 * this.chunkSize * this.channelCount)
578
- const timestampBuffer = Buffer.alloc(8 * this.chunkSize)
579
- const dataBufferElements = this.chunkSize * this.channelCount
580
- const timestampBufferElements = this.chunkSize
581
- const timeout = 0.0
582
-
583
- const dataBufferPtr = unwrapPointer(
584
- createPointer({
585
- paramsType: [DataType.U8Array],
586
- paramsValue: [dataBuffer],
587
- })
588
- )[0]
589
-
590
- const timestampBufferPtr = unwrapPointer(
591
- createPointer({
592
- paramsType: [DataType.U8Array],
593
- paramsValue: [timestampBuffer],
594
- })
595
- )[0]
596
-
597
- const errcodePtr = unwrapPointer(
598
- createPointer({
599
- paramsType: [DataType.U8Array],
600
- paramsValue: [new Int32Array(1)],
601
- })
602
- )[0]
603
-
604
- this.instance.pullChunk({
605
- inlet,
606
- dataBufferPtr,
607
- timestampBufferPtr,
608
- dataBufferElements,
609
- timestampBufferElements,
610
- timeout,
611
- errcodePtr,
612
- })
613
-
614
- assert.isEqualDeep(
615
- this.ffiRsLoadOptions,
616
- {
617
- library: 'lsl',
618
- funcName: 'lsl_pull_chunk_f',
619
- retType: DataType.Double,
620
- paramsType: [
621
- DataType.External,
622
- DataType.External,
623
- DataType.External,
624
- DataType.I32,
625
- DataType.I32,
626
- DataType.Double,
627
- DataType.External,
628
- ],
629
- paramsValue: [
630
- inlet,
631
- dataBufferPtr,
632
- timestampBufferPtr,
633
- dataBufferElements,
634
- timestampBufferElements,
635
- timeout,
636
- errcodePtr,
637
- ],
638
- },
639
- 'Did not call pullChunk with expected options!'
640
- )
641
- }
642
-
643
- @test()
644
- protected static async flushInletCallsBinding() {
645
- const { inlet } = this.createRandomInlet()
646
- this.instance.flushInlet({ inlet })
647
-
648
- assert.isEqualDeep(
649
- this.flushInletParams,
650
- [inlet],
651
- 'Should have called flushInlet with expected params!'
652
- )
653
- }
654
-
655
- @test()
656
- protected static async destroyInletCallsBinding() {
657
- const { inlet } = this.createRandomInlet()
658
- this.instance.destroyInlet({ inlet })
659
-
660
- assert.isEqualDeep(
661
- this.destroyInletParams,
662
- [inlet],
663
- 'Should have called destroyInlet with expected params!'
664
- )
665
- }
666
-
667
- private static createRandomStreamInfo() {
668
- return this.instance.createStreamInfo(
669
- this.generateRandomCreateStreamInfoOptions()
670
- )
671
- }
672
-
673
- private static async resolveByProp(
674
- options?: Partial<ResolveByPropOptions>
675
- ) {
676
- return this.instance.resolveByProp({
677
- prop: this.prop,
678
- value: this.value,
679
- minResults: this.minResults,
680
- timeoutMs: this.timeoutMs,
681
- ...options,
682
- })
683
- }
684
-
685
- private static createRandomOutlet() {
686
- const options = this.createRandomOutletOptions()
687
- const outlet = this.instance.createOutlet(options)
688
- return { options, outlet }
689
- }
690
-
691
- private static createRandomOutletOptions() {
692
- const info = this.createRandomStreamInfo()
693
- const options = {
694
- info,
695
- chunkSize: randomInt(10),
696
- maxBufferedMs: randomInt(10),
697
- }
698
- return options
699
- }
700
-
701
- private static createRandomInlet() {
702
- const options = this.createRandomInletOptions()
703
- const inlet = this.instance.createInlet(options)
704
- return { options, inlet }
705
- }
706
-
707
- private static createRandomInletOptions() {
708
- const info = this.createRandomStreamInfo()
709
- const options = {
710
- info,
711
- maxBufferedMs: randomInt(10),
712
- }
713
- return options
714
- }
715
-
716
- private static generateRandomChannelValues() {
717
- return {
718
- label: this.generateId(),
719
- type: this.generateId(),
720
- units: this.generateId(),
721
- }
722
- }
723
-
724
- private static generateRandomCreateStreamInfoOptions() {
725
- return {
726
- name: this.generateId(),
727
- type: this.generateId(),
728
- channelCount: randomInt(1, 10),
729
- sampleRateHz: randomInt(100),
730
- channelFormat: randomInt(7),
731
- sourceId: this.generateId(),
732
- }
733
- }
734
-
735
- // resolveByProp
736
- private static readonly maxResults = 1024
737
- private static readonly bytesPerPointer = 8
738
- private static readonly minResults = 1
739
- private static readonly timeoutMs = 1000
740
- private static readonly prop = this.generateId()
741
- private static readonly value = this.generateId()
742
- private static readonly fakeNumResolveResults = 2
743
-
744
- private static readonly resultsBuffer = Buffer.alloc(
745
- this.maxResults * this.bytesPerPointer
746
- )
747
-
748
- private static readonly resultsBufferPtr = unwrapPointer(
749
- createPointer({
750
- paramsType: [DataType.U8Array],
751
- paramsValue: [this.resultsBuffer],
752
- })
753
- )[0]
754
-
755
- private static generateFailedMessage() {
756
- return `Loading the liblsl dylib failed! I tried to load it from ${process.env.LIBLSL_PATH}.`
757
- }
758
-
759
- private static FakeBindings() {
760
- return {
761
- lsl_create_streaminfo: (params: any[]) => {
762
- this.createStreamInfoParams = params
763
- return this.fakeStreamInfo
764
- },
765
- lsl_destroy_streaminfo: (params: any[]) => {
766
- this.destroyStreamInfoParams = params
767
- },
768
- lsl_create_outlet: (params: any[]) => {
769
- this.createOutletParams = params
770
- return this.fakeOutlet
771
- },
772
- lsl_push_sample_ft: (params: any[]) => {
773
- this.pushSampleFloatTimestampParams = params
774
- return 0
775
- },
776
- lsl_push_sample_strt: (params: any[]) => {
777
- this.pushSampleStringTimestampParams = params
778
- return 0
779
- },
780
- lsl_destroy_outlet: (params: any[]) => {
781
- this.destroyOutletParams = params
782
- },
783
- lsl_create_inlet: (params: any[]) => {
784
- this.createInletParams = params
785
- return this.fakeInlet
786
- },
787
- lsl_flush_inlet: (params: any[]) => {
788
- this.flushInletParams = params
789
- return 0
790
- },
791
- lsl_destroy_inlet: (params: any[]) => {
792
- this.destroyInletParams = params
793
- },
794
- lsl_local_clock: (params: []) => {
795
- this.localClockParams = params
796
- return new Date().getTime()
797
- },
798
- lsl_get_desc: (info: BoundStreamInfo) => {
799
- this.getDescriptionParams = [info]
800
- return this.fakeDesc
801
- },
802
- lsl_append_child: (params: any) => {
803
- this.appendChildParams.push(params)
804
- if (this.appendChildHitCount === 0) {
805
- this.appendChildHitCount++
806
- return this.fakeChildNamedChannels
807
- }
808
- return this.fakeChildNamedChannel
809
- },
810
- lsl_append_child_value: (params: any[]) => {
811
- this.appendChildValueParams.push(params)
812
- },
813
- }
814
- }
815
- }
816
-
817
- export type FfiRsDefineOptions = FuncObj<FieldType, boolean | undefined>