@neurodevs/node-lsl 16.0.2 → 16.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.
- package/build/__tests__/AbstractPackageTest.js +0 -2
- package/build/__tests__/AbstractPackageTest.js.map +1 -1
- package/build/__tests__/impl/LiblslAdapter.test.d.ts +15 -1
- package/build/__tests__/impl/LiblslAdapter.test.js +111 -9
- package/build/__tests__/impl/LiblslAdapter.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamInfo.test.d.ts +2 -1
- package/build/__tests__/impl/LslStreamInfo.test.js +16 -6
- package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamInlet.test.js +5 -5
- package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
- package/build/__tests__/impl/LslWebSocketBridge.test.js +1 -0
- package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
- package/build/impl/LiblslAdapter.d.ts +16 -5
- package/build/impl/LiblslAdapter.js +60 -8
- package/build/impl/LiblslAdapter.js.map +1 -1
- package/build/impl/LslStreamInfo.d.ts +1 -1
- package/build/impl/LslStreamInfo.js +9 -20
- package/build/impl/LslStreamInfo.js.map +1 -1
- package/build/impl/LslStreamInlet.d.ts +3 -0
- package/build/impl/LslStreamInlet.js +7 -8
- package/build/impl/LslStreamInlet.js.map +1 -1
- package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +8 -4
- package/build/testDoubles/Liblsl/FakeLiblsl.js +12 -4
- package/build/testDoubles/Liblsl/FakeLiblsl.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/AbstractPackageTest.ts +0 -4
- package/src/__tests__/impl/LiblslAdapter.test.ts +149 -10
- package/src/__tests__/impl/LslStreamInfo.test.ts +20 -6
- package/src/__tests__/impl/LslStreamInlet.test.ts +5 -5
- package/src/__tests__/impl/LslWebSocketBridge.test.ts +1 -0
- package/src/impl/LiblslAdapter.ts +96 -15
- package/src/impl/LslStreamInfo.ts +9 -31
- package/src/impl/LslStreamInlet.ts +12 -9
- package/src/testDoubles/Liblsl/FakeLiblsl.ts +18 -6
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
Liblsl,
|
|
19
19
|
LiblslBindings,
|
|
20
20
|
LslChannel,
|
|
21
|
+
ResolveByPropOptions,
|
|
21
22
|
} from 'impl/LiblslAdapter.js'
|
|
22
23
|
import LiblslAdapter from '../../impl/LiblslAdapter.js'
|
|
23
24
|
import FakeLiblsl from '../../testDoubles/Liblsl/FakeLiblsl.js'
|
|
@@ -97,7 +98,7 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
97
98
|
|
|
98
99
|
LiblslAdapter.load = (options) => {
|
|
99
100
|
this.ffiRsLoadOptions = options
|
|
100
|
-
return
|
|
101
|
+
return this.fakeNumResolveResults as any
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
LiblslAdapter.resetInstance()
|
|
@@ -200,7 +201,12 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
200
201
|
lsl_create_inlet: {
|
|
201
202
|
library: 'lsl',
|
|
202
203
|
retType: DataType.External,
|
|
203
|
-
paramsType: [
|
|
204
|
+
paramsType: [
|
|
205
|
+
DataType.External,
|
|
206
|
+
DataType.I32,
|
|
207
|
+
DataType.I32,
|
|
208
|
+
DataType.I32,
|
|
209
|
+
],
|
|
204
210
|
},
|
|
205
211
|
lsl_flush_inlet: {
|
|
206
212
|
library: 'lsl',
|
|
@@ -260,6 +266,89 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
260
266
|
)
|
|
261
267
|
}
|
|
262
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
|
+
|
|
263
352
|
@test()
|
|
264
353
|
protected static async createsOutletWithRequiredParams() {
|
|
265
354
|
const { options, outlet } = this.createRandomOutlet()
|
|
@@ -396,7 +485,7 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
396
485
|
delete process.env.LIBLSL_PATH
|
|
397
486
|
|
|
398
487
|
LiblslAdapter.resetInstance()
|
|
399
|
-
this.instance = LiblslAdapter.getInstance()
|
|
488
|
+
this.instance = LiblslAdapter.getInstance() as FakeLiblsl
|
|
400
489
|
|
|
401
490
|
assert.isEqual(
|
|
402
491
|
this.ffiRsOpenOptions?.path,
|
|
@@ -407,14 +496,23 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
407
496
|
@test()
|
|
408
497
|
protected static async createInletWithRequiredParams() {
|
|
409
498
|
const { options, inlet } = this.createRandomInlet()
|
|
499
|
+
const { maxBufferedMs } = options
|
|
410
500
|
|
|
411
501
|
const expected = {
|
|
412
502
|
...options,
|
|
413
|
-
maxBufferedMs:
|
|
503
|
+
maxBufferedMs: maxBufferedMs / 1000,
|
|
414
504
|
}
|
|
415
505
|
|
|
416
|
-
|
|
417
|
-
|
|
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!')
|
|
418
516
|
}
|
|
419
517
|
|
|
420
518
|
@test()
|
|
@@ -572,23 +670,44 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
572
670
|
)
|
|
573
671
|
}
|
|
574
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
|
+
|
|
575
685
|
private static createRandomOutlet() {
|
|
576
|
-
const options = this.
|
|
686
|
+
const options = this.createRandomOutletOptions()
|
|
577
687
|
const outlet = this.instance.createOutlet(options)
|
|
578
688
|
return { options, outlet }
|
|
579
689
|
}
|
|
580
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
|
+
|
|
581
701
|
private static createRandomInlet() {
|
|
582
|
-
const options = this.
|
|
702
|
+
const options = this.createRandomInletOptions()
|
|
583
703
|
const inlet = this.instance.createInlet(options)
|
|
584
704
|
return { options, inlet }
|
|
585
705
|
}
|
|
586
706
|
|
|
587
|
-
private static
|
|
707
|
+
private static createRandomInletOptions() {
|
|
588
708
|
const info = this.createRandomStreamInfo()
|
|
589
709
|
const options = {
|
|
590
710
|
info,
|
|
591
|
-
chunkSize: randomInt(10),
|
|
592
711
|
maxBufferedMs: randomInt(10),
|
|
593
712
|
}
|
|
594
713
|
return options
|
|
@@ -613,6 +732,26 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
613
732
|
}
|
|
614
733
|
}
|
|
615
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
|
+
|
|
616
755
|
private static generateFailedMessage() {
|
|
617
756
|
return `Loading the liblsl dylib failed! I tried to load it from ${process.env.LIBLSL_PATH}.`
|
|
618
757
|
}
|
|
@@ -11,10 +11,9 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
11
11
|
protected static async beforeEach() {
|
|
12
12
|
await super.beforeEach()
|
|
13
13
|
|
|
14
|
+
this.setFakeLiblsl()
|
|
14
15
|
this.setSpyStreamInfo()
|
|
15
16
|
|
|
16
|
-
LslStreamInfo['instanceCache'] = {}
|
|
17
|
-
|
|
18
17
|
this.instance = this.LslStreamInfo()
|
|
19
18
|
}
|
|
20
19
|
|
|
@@ -220,13 +219,28 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
220
219
|
}
|
|
221
220
|
|
|
222
221
|
@test()
|
|
223
|
-
protected static async
|
|
224
|
-
this.LslStreamInfo(
|
|
222
|
+
protected static async doesNotCreateNewStreamInfoIfPassedBoundStreamInfo() {
|
|
223
|
+
this.LslStreamInfo({
|
|
224
|
+
boundStreamInfo: this.instance.getBoundInfo(),
|
|
225
|
+
})
|
|
225
226
|
|
|
226
227
|
assert.isEqual(
|
|
227
|
-
|
|
228
|
+
this.fakeLiblsl.createStreamInfoHitCount,
|
|
228
229
|
1,
|
|
229
|
-
'
|
|
230
|
+
'Should not have created new stream info!'
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
@test()
|
|
235
|
+
protected static async setsBoundStreamInfoWhenPassed() {
|
|
236
|
+
const instance = this.LslStreamInfo({
|
|
237
|
+
boundStreamInfo: this.instance.getBoundInfo(),
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
assert.isEqualDeep(
|
|
241
|
+
instance.getBoundInfo(),
|
|
242
|
+
this.instance.getBoundInfo(),
|
|
243
|
+
'Should have set bound stream info!'
|
|
230
244
|
)
|
|
231
245
|
}
|
|
232
246
|
|
|
@@ -15,8 +15,9 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
15
15
|
protected static async beforeEach() {
|
|
16
16
|
await super.beforeEach()
|
|
17
17
|
|
|
18
|
-
this.
|
|
18
|
+
this.setFakeLiblsl()
|
|
19
19
|
this.setFakeStreamInfo()
|
|
20
|
+
this.setSpyStreamInlet()
|
|
20
21
|
|
|
21
22
|
this.callsToOnData = []
|
|
22
23
|
|
|
@@ -65,8 +66,7 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
65
66
|
this.fakeLiblsl.lastCreateInletOptions,
|
|
66
67
|
{
|
|
67
68
|
info: fakeInfo.boundStreamInfo,
|
|
68
|
-
|
|
69
|
-
maxBufferedMs: this.maxBufferedMs / 1000,
|
|
69
|
+
maxBufferedMs: this.maxBufferedMs,
|
|
70
70
|
},
|
|
71
71
|
'Should have called createInlet!'
|
|
72
72
|
)
|
|
@@ -212,11 +212,11 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
212
212
|
maxBufferedMs: undefined,
|
|
213
213
|
})
|
|
214
214
|
|
|
215
|
-
const
|
|
215
|
+
const sixMinutesInMs = 360 * 1000
|
|
216
216
|
|
|
217
217
|
assert.isEqualDeep(
|
|
218
218
|
this.fakeLiblsl.lastCreateInletOptions?.maxBufferedMs,
|
|
219
|
-
|
|
219
|
+
sixMinutesInMs
|
|
220
220
|
)
|
|
221
221
|
}
|
|
222
222
|
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createPointer,
|
|
3
|
+
DataType,
|
|
4
|
+
define,
|
|
5
|
+
JsExternal,
|
|
6
|
+
load,
|
|
7
|
+
open,
|
|
8
|
+
unwrapPointer,
|
|
9
|
+
} from 'ffi-rs'
|
|
2
10
|
|
|
3
11
|
import { CHANNEL_FORMATS } from '../consts.js'
|
|
4
12
|
import { LslErrorCode } from '../handleError.js'
|
|
@@ -7,6 +15,7 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
7
15
|
public static open = open
|
|
8
16
|
public static define = define
|
|
9
17
|
public static load = load
|
|
18
|
+
public static alloc = Buffer.alloc
|
|
10
19
|
|
|
11
20
|
private static instance?: Liblsl
|
|
12
21
|
|
|
@@ -62,7 +71,7 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
private defineLiblslBindings() {
|
|
65
|
-
return this.define(this.liblslFuncs) as
|
|
74
|
+
return this.define(this.liblslFuncs) as LiblslBindings
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
public createStreamInfo(options: CreateStreamInfoOptions) {
|
|
@@ -85,11 +94,6 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
85
94
|
])
|
|
86
95
|
}
|
|
87
96
|
|
|
88
|
-
public destroyStreamInfo(options: DestroyStreamInfoOptions) {
|
|
89
|
-
const { info } = options
|
|
90
|
-
this.bindings.lsl_destroy_streaminfo([info])
|
|
91
|
-
}
|
|
92
|
-
|
|
93
97
|
public appendChannelsToStreamInfo(
|
|
94
98
|
options: AppendChannelsToStreamInfoOptions
|
|
95
99
|
) {
|
|
@@ -110,6 +114,62 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
110
114
|
}
|
|
111
115
|
}
|
|
112
116
|
|
|
117
|
+
public destroyStreamInfo(options: DestroyStreamInfoOptions) {
|
|
118
|
+
const { info } = options
|
|
119
|
+
this.bindings.lsl_destroy_streaminfo([info])
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async resolveByProp(options: ResolveByPropOptions) {
|
|
123
|
+
const { prop, value, minResults = 1, timeoutMs = 1000 } = options
|
|
124
|
+
|
|
125
|
+
const maxResults = 1024
|
|
126
|
+
const bytesPerPointer = 8
|
|
127
|
+
|
|
128
|
+
const resultsBuffer = this.alloc(maxResults * bytesPerPointer)
|
|
129
|
+
|
|
130
|
+
const resultsBufferPtr = unwrapPointer(
|
|
131
|
+
createPointer({
|
|
132
|
+
paramsType: [DataType.U8Array],
|
|
133
|
+
paramsValue: [resultsBuffer],
|
|
134
|
+
})
|
|
135
|
+
)[0]
|
|
136
|
+
|
|
137
|
+
const numResults = await this.load({
|
|
138
|
+
library: 'lsl',
|
|
139
|
+
funcName: 'lsl_resolve_byprop',
|
|
140
|
+
retType: DataType.I32,
|
|
141
|
+
paramsType: [
|
|
142
|
+
DataType.External,
|
|
143
|
+
DataType.I32,
|
|
144
|
+
DataType.String,
|
|
145
|
+
DataType.String,
|
|
146
|
+
DataType.I32,
|
|
147
|
+
DataType.Double,
|
|
148
|
+
],
|
|
149
|
+
paramsValue: [
|
|
150
|
+
resultsBufferPtr,
|
|
151
|
+
maxResults,
|
|
152
|
+
prop,
|
|
153
|
+
value,
|
|
154
|
+
minResults,
|
|
155
|
+
timeoutMs / 1000,
|
|
156
|
+
],
|
|
157
|
+
runInNewThread: true,
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
const handles: bigint[] = []
|
|
161
|
+
|
|
162
|
+
for (let i = 0; i < numResults; i++) {
|
|
163
|
+
const handle = resultsBuffer.readBigUInt64LE(i * bytesPerPointer)
|
|
164
|
+
|
|
165
|
+
if (handle !== 0n) {
|
|
166
|
+
handles.push(handle)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return handles
|
|
171
|
+
}
|
|
172
|
+
|
|
113
173
|
public createOutlet(options: CreateOutletOptions) {
|
|
114
174
|
const { info, chunkSize, maxBufferedMs } = options
|
|
115
175
|
|
|
@@ -138,15 +198,19 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
138
198
|
}
|
|
139
199
|
|
|
140
200
|
public createInlet(options: CreateInletOptions) {
|
|
141
|
-
const { info,
|
|
201
|
+
const { info, maxBufferedMs } = options
|
|
142
202
|
|
|
143
203
|
return this.bindings.lsl_create_inlet([
|
|
144
204
|
info,
|
|
145
|
-
chunkSize,
|
|
146
205
|
maxBufferedMs / 1000,
|
|
206
|
+
this.maxChunkSize,
|
|
207
|
+
this.shouldRecover,
|
|
147
208
|
])
|
|
148
209
|
}
|
|
149
210
|
|
|
211
|
+
private readonly maxChunkSize = 0
|
|
212
|
+
private readonly shouldRecover = 1
|
|
213
|
+
|
|
150
214
|
public pullSample(options: PullSampleOptions) {
|
|
151
215
|
const {
|
|
152
216
|
inlet,
|
|
@@ -239,6 +303,10 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
239
303
|
return LiblslAdapter.load
|
|
240
304
|
}
|
|
241
305
|
|
|
306
|
+
private get alloc() {
|
|
307
|
+
return LiblslAdapter.alloc
|
|
308
|
+
}
|
|
309
|
+
|
|
242
310
|
private get liblslFuncs() {
|
|
243
311
|
return {
|
|
244
312
|
lsl_create_streaminfo: {
|
|
@@ -289,7 +357,12 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
289
357
|
lsl_create_inlet: {
|
|
290
358
|
library: 'lsl',
|
|
291
359
|
retType: DataType.External,
|
|
292
|
-
paramsType: [
|
|
360
|
+
paramsType: [
|
|
361
|
+
DataType.External,
|
|
362
|
+
DataType.I32,
|
|
363
|
+
DataType.I32,
|
|
364
|
+
DataType.I32,
|
|
365
|
+
],
|
|
293
366
|
},
|
|
294
367
|
lsl_flush_inlet: {
|
|
295
368
|
library: 'lsl',
|
|
@@ -336,6 +409,8 @@ export interface Liblsl {
|
|
|
336
409
|
destroyStreamInfo(options: DestroyStreamInfoOptions): void
|
|
337
410
|
appendChannelsToStreamInfo(options: AppendChannelsToStreamInfoOptions): void
|
|
338
411
|
|
|
412
|
+
resolveByProp(options: ResolveByPropOptions): Promise<bigint[]>
|
|
413
|
+
|
|
339
414
|
createOutlet(options: CreateOutletOptions): BoundOutlet
|
|
340
415
|
|
|
341
416
|
pushSampleFloatTimestamp(
|
|
@@ -373,14 +448,21 @@ export interface AppendChannelsToStreamInfoOptions {
|
|
|
373
448
|
channels: LslChannel[]
|
|
374
449
|
}
|
|
375
450
|
|
|
376
|
-
export interface
|
|
451
|
+
export interface DestroyStreamInfoOptions {
|
|
377
452
|
info: BoundStreamInfo
|
|
378
|
-
chunkSize: number
|
|
379
|
-
maxBufferedMs: number
|
|
380
453
|
}
|
|
381
454
|
|
|
382
|
-
export interface
|
|
455
|
+
export interface ResolveByPropOptions {
|
|
456
|
+
prop: string
|
|
457
|
+
value: string
|
|
458
|
+
minResults?: number
|
|
459
|
+
timeoutMs?: number
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export interface CreateOutletOptions {
|
|
383
463
|
info: BoundStreamInfo
|
|
464
|
+
chunkSize: number
|
|
465
|
+
maxBufferedMs: number
|
|
384
466
|
}
|
|
385
467
|
|
|
386
468
|
export interface PushSampleFloatTimestampOptions {
|
|
@@ -401,7 +483,6 @@ export interface DestroyOutletOptions {
|
|
|
401
483
|
|
|
402
484
|
export interface CreateInletOptions {
|
|
403
485
|
info: BoundStreamInfo
|
|
404
|
-
chunkSize: number
|
|
405
486
|
maxBufferedMs: number
|
|
406
487
|
}
|
|
407
488
|
|
|
@@ -7,8 +7,6 @@ import LiblslAdapter from './LiblslAdapter.js'
|
|
|
7
7
|
export default class LslStreamInfo implements StreamInfo {
|
|
8
8
|
public static Class?: StreamInfoConstructor
|
|
9
9
|
|
|
10
|
-
private static instanceCache: Record<string, StreamInfo> = {}
|
|
11
|
-
|
|
12
10
|
public readonly name: string
|
|
13
11
|
public readonly type: string
|
|
14
12
|
public readonly sourceId: string
|
|
@@ -36,6 +34,7 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
36
34
|
channelFormat,
|
|
37
35
|
sampleRateHz,
|
|
38
36
|
units = this.defaultUnits,
|
|
37
|
+
boundStreamInfo,
|
|
39
38
|
} = options
|
|
40
39
|
|
|
41
40
|
this.name = name
|
|
@@ -47,38 +46,16 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
47
46
|
this.sampleRateHz = sampleRateHz
|
|
48
47
|
this.units = units
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
if (!boundStreamInfo) {
|
|
50
|
+
this.createStreamInfo()
|
|
51
|
+
this.appendChannelsToStreamInfo()
|
|
52
|
+
} else {
|
|
53
|
+
this.boundInfo = boundStreamInfo
|
|
54
|
+
}
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
public static Create(options: StreamInfoOptions) {
|
|
55
|
-
|
|
56
|
-
name,
|
|
57
|
-
type,
|
|
58
|
-
sourceId,
|
|
59
|
-
channelNames,
|
|
60
|
-
channelFormat,
|
|
61
|
-
sampleRateHz,
|
|
62
|
-
} = options
|
|
63
|
-
|
|
64
|
-
const channelCount = channelNames.length
|
|
65
|
-
|
|
66
|
-
const key = JSON.stringify({
|
|
67
|
-
name,
|
|
68
|
-
type,
|
|
69
|
-
sourceId,
|
|
70
|
-
channelCount,
|
|
71
|
-
channelFormat,
|
|
72
|
-
sampleRateHz,
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
let instance = this.instanceCache[key]
|
|
76
|
-
|
|
77
|
-
if (instance === undefined) {
|
|
78
|
-
instance = new (this.Class ?? this)(options)
|
|
79
|
-
this.instanceCache[key] = instance
|
|
80
|
-
}
|
|
81
|
-
return instance
|
|
58
|
+
return new (this.Class ?? this)(options)
|
|
82
59
|
}
|
|
83
60
|
|
|
84
61
|
private createStreamInfo() {
|
|
@@ -139,4 +116,5 @@ export interface StreamInfoOptions {
|
|
|
139
116
|
type?: string
|
|
140
117
|
sourceId?: string
|
|
141
118
|
units?: string
|
|
119
|
+
boundStreamInfo?: BoundStreamInfo
|
|
142
120
|
}
|
|
@@ -92,8 +92,7 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
92
92
|
private createBoundInlet() {
|
|
93
93
|
this.inlet = this.lsl.createInlet({
|
|
94
94
|
info: this.boundStreamInfo,
|
|
95
|
-
|
|
96
|
-
maxBufferedMs: this.maxBufferedMs / 1000,
|
|
95
|
+
maxBufferedMs: this.maxBufferedMs,
|
|
97
96
|
})
|
|
98
97
|
}
|
|
99
98
|
|
|
@@ -117,23 +116,27 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
117
116
|
}
|
|
118
117
|
|
|
119
118
|
private createDataBuffer() {
|
|
120
|
-
const bytesPerFloat = 4
|
|
121
|
-
|
|
122
119
|
this.dataBuffer = Buffer.alloc(
|
|
123
|
-
bytesPerFloat * this.chunkSize * this.channelCount
|
|
120
|
+
this.bytesPerFloat * this.chunkSize * this.channelCount
|
|
124
121
|
)
|
|
125
122
|
}
|
|
126
123
|
|
|
124
|
+
private readonly bytesPerFloat = 4
|
|
125
|
+
|
|
127
126
|
private createTimestampBuffer() {
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
this.timestampBuffer = Buffer.alloc(
|
|
128
|
+
this.bytesPerDouble * this.chunkSize
|
|
129
|
+
)
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
private readonly bytesPerDouble = 8
|
|
133
|
+
|
|
132
134
|
private createErrorCodeBuffer() {
|
|
133
|
-
|
|
134
|
-
this.errorCodeBuffer = Buffer.alloc(bytesPerInt)
|
|
135
|
+
this.errorCodeBuffer = Buffer.alloc(this.bytesPerInt)
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
private readonly bytesPerInt = 4
|
|
139
|
+
|
|
137
140
|
private createPointersToBuffers() {
|
|
138
141
|
this.createDataBufferPtr()
|
|
139
142
|
this.createTimestampBufferPtr()
|
|
@@ -16,9 +16,13 @@ import {
|
|
|
16
16
|
PullChunkOptions,
|
|
17
17
|
PullSampleOptions,
|
|
18
18
|
DestroyStreamInfoOptions,
|
|
19
|
+
ResolveByPropOptions,
|
|
20
|
+
DestroyOutletOptions,
|
|
19
21
|
} from 'impl/LiblslAdapter.js'
|
|
20
22
|
|
|
21
23
|
export default class FakeLiblsl implements Liblsl {
|
|
24
|
+
public static fakeResolveHandles: bigint[] = []
|
|
25
|
+
|
|
22
26
|
public static fakeSamples: Float32Array[] = [
|
|
23
27
|
new Float32Array([1, 2, 3]),
|
|
24
28
|
new Float32Array([4, 5, 6]),
|
|
@@ -46,12 +50,14 @@ export default class FakeLiblsl implements Liblsl {
|
|
|
46
50
|
public streamInfo: BoundStreamInfo = {} as BoundStreamInfo
|
|
47
51
|
|
|
48
52
|
public lastCreateStreamInfoOptions?: CreateStreamInfoOptions
|
|
49
|
-
public lastDestroyStreamInfoOptions?: DestroyStreamInfoOptions
|
|
50
53
|
public lastAppendChannelsToStreamInfoOptions?: AppendChannelsToStreamInfoOptions
|
|
54
|
+
public lastDestroyStreamInfoOptions?: DestroyStreamInfoOptions
|
|
55
|
+
public lastResolveByPropOptions?: ResolveByPropOptions
|
|
51
56
|
public lastCreateOutletOptions?: CreateOutletOptions
|
|
52
57
|
public lastPushSampleFloatTimestampOptions?: PushSampleFloatTimestampOptions
|
|
53
58
|
public lastPushSampleStringTimestampOptions?: PushSampleStringTimestampOptions
|
|
54
59
|
public lastCreateInletOptions?: CreateInletOptions
|
|
60
|
+
public lastDestroyOutletOptions?: DestroyOutletOptions
|
|
55
61
|
public lastPullSampleOptions?: PullSampleOptions
|
|
56
62
|
public lastPullChunkOptions?: PullChunkOptions
|
|
57
63
|
public lastFlushInletOptions?: FlushInletOptions
|
|
@@ -72,16 +78,21 @@ export default class FakeLiblsl implements Liblsl {
|
|
|
72
78
|
return this.streamInfo
|
|
73
79
|
}
|
|
74
80
|
|
|
75
|
-
public destroyStreamInfo(options: DestroyStreamInfoOptions) {
|
|
76
|
-
this.lastDestroyStreamInfoOptions = options
|
|
77
|
-
}
|
|
78
|
-
|
|
79
81
|
public appendChannelsToStreamInfo(
|
|
80
82
|
options: AppendChannelsToStreamInfoOptions
|
|
81
83
|
) {
|
|
82
84
|
this.lastAppendChannelsToStreamInfoOptions = options
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
public destroyStreamInfo(options: DestroyStreamInfoOptions) {
|
|
88
|
+
this.lastDestroyStreamInfoOptions = options
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public async resolveByProp(options: ResolveByPropOptions) {
|
|
92
|
+
this.lastResolveByPropOptions = options
|
|
93
|
+
return FakeLiblsl.fakeResolveHandles
|
|
94
|
+
}
|
|
95
|
+
|
|
85
96
|
public pushSampleFloatTimestamp(options: PushSampleFloatTimestampOptions) {
|
|
86
97
|
this.lastPushSampleFloatTimestampOptions = options
|
|
87
98
|
return FakeLiblsl.fakeErrorCode
|
|
@@ -101,8 +112,9 @@ export default class FakeLiblsl implements Liblsl {
|
|
|
101
112
|
return this.outlet
|
|
102
113
|
}
|
|
103
114
|
|
|
104
|
-
public destroyOutlet() {
|
|
115
|
+
public destroyOutlet(options: DestroyOutletOptions) {
|
|
105
116
|
this.destroyOutletHitCount++
|
|
117
|
+
this.lastDestroyOutletOptions = options
|
|
106
118
|
}
|
|
107
119
|
|
|
108
120
|
public createInlet(options: CreateInletOptions) {
|