@neurodevs/node-lsl 16.0.3 → 17.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.
- package/build/__tests__/AbstractPackageTest.d.ts +1 -1
- package/build/__tests__/AbstractPackageTest.js +1 -3
- package/build/__tests__/AbstractPackageTest.js.map +1 -1
- package/build/__tests__/impl/LiblslAdapter.test.d.ts +13 -0
- package/build/__tests__/impl/LiblslAdapter.test.js +87 -1
- package/build/__tests__/impl/LiblslAdapter.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamInfo.test.d.ts +3 -1
- package/build/__tests__/impl/LslStreamInfo.test.js +26 -9
- package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamInlet.test.d.ts +3 -2
- package/build/__tests__/impl/LslStreamInlet.test.js +27 -21
- package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
- package/build/__tests__/impl/LslWebSocketBridge.test.js +8 -16
- package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
- package/build/impl/LiblslAdapter.d.ts +14 -4
- package/build/impl/LiblslAdapter.js +49 -5
- package/build/impl/LiblslAdapter.js.map +1 -1
- package/build/impl/LslStreamInfo.d.ts +4 -1
- package/build/impl/LslStreamInfo.js +18 -19
- package/build/impl/LslStreamInfo.js.map +1 -1
- package/build/impl/LslStreamInlet.d.ts +3 -13
- package/build/impl/LslStreamInlet.js +12 -15
- package/build/impl/LslStreamInlet.js.map +1 -1
- package/build/impl/LslWebSocketBridge.d.ts +2 -8
- package/build/impl/LslWebSocketBridge.js +2 -2
- package/build/impl/LslWebSocketBridge.js.map +1 -1
- package/build/scripts/runOutletToInlet.js +1 -1
- package/build/scripts/runOutletToInlet.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/build/testDoubles/StreamInfo/FakeStreamInfo.js +1 -1
- package/build/testDoubles/StreamInfo/FakeStreamInfo.js.map +1 -1
- package/build/testDoubles/StreamInlet/SpyStreamInlet.d.ts +0 -1
- package/build/testDoubles/StreamInlet/SpyStreamInlet.js +0 -3
- package/build/testDoubles/StreamInlet/SpyStreamInlet.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/AbstractPackageTest.ts +1 -5
- package/src/__tests__/impl/LiblslAdapter.test.ts +118 -2
- package/src/__tests__/impl/LslStreamInfo.test.ts +34 -9
- package/src/__tests__/impl/LslStreamInlet.test.ts +36 -26
- package/src/__tests__/impl/LslWebSocketBridge.test.ts +9 -24
- package/src/impl/LiblslAdapter.ts +84 -11
- package/src/impl/LslStreamInfo.ts +21 -28
- package/src/impl/LslStreamInlet.ts +20 -37
- package/src/impl/LslWebSocketBridge.ts +3 -9
- package/src/scripts/runOutletToInlet.ts +6 -3
- package/src/testDoubles/Liblsl/FakeLiblsl.ts +18 -6
- package/src/testDoubles/StreamInfo/FakeStreamInfo.ts +1 -1
- package/src/testDoubles/StreamInlet/SpyStreamInlet.ts +0 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FakeLiblsl.js","sourceRoot":"","sources":["../../../src/testDoubles/Liblsl/FakeLiblsl.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"FakeLiblsl.js","sourceRoot":"","sources":["../../../src/testDoubles/Liblsl/FakeLiblsl.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAsB/C,MAAM,CAAC,OAAO,OAAO,UAAU;IACpB,MAAM,CAAC,qBAAqB,GAAsB,EAAE,CAAA;IAEpD,MAAM,CAAC,WAAW,GAAmB;QACxC,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3B,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KAC9B,CAAA;IAEM,MAAM,CAAC,UAAU,GAAmB;QACvC,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACpC,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KACvC,CAAA;IAEM,MAAM,CAAC,cAAc,GAAmB;QAC3C,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxB,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KAC3B,CAAA;IAEM,MAAM,CAAC,aAAa,GAAG,CAAC,CAAA;IAExB,UAAU,GAAW,UAAU,EAAE,CAAA;IAEjC,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC,KAAK,EAAE,CAAA;IAC5C,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;IAC1C,cAAc,GAAG,UAAU,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;IAElD,MAAM,GAAgB,EAAiB,CAAA;IACvC,UAAU,GAAoB,EAAqB,CAAA;IAEnD,2BAA2B,CAA0B;IACrD,qCAAqC,CAAoC;IACzE,4BAA4B,CAA2B;IACvD,wBAAwB,CAAuB;IAC/C,uBAAuB,CAAsB;IAC7C,mCAAmC,CAAkC;IACrE,oCAAoC,CAAmC;IACvE,sBAAsB,CAAqB;IAC3C,wBAAwB,CAAuB;IAC/C,qBAAqB,CAAoB;IACzC,oBAAoB,CAAmB;IACvC,qBAAqB,CAAoB;IACzC,uBAAuB,CAAsB;IAE7C,wBAAwB,GAAG,CAAC,CAAA;IAC5B,oBAAoB,GAAG,CAAC,CAAA;IACxB,qBAAqB,GAAG,CAAC,CAAA;IACzB,mBAAmB,GAAG,CAAC,CAAA;IACvB,kBAAkB,GAAG,CAAC,CAAA;IACtB,oBAAoB,GAAG,CAAC,CAAA;IACxB,kBAAkB,GAAG,CAAC,CAAA;IACtB,iCAAiC,GAAG,CAAC,CAAA;IAErC,gBAAgB,CAAC,OAAgC;QACpD,IAAI,CAAC,wBAAwB,EAAE,CAAA;QAC/B,IAAI,CAAC,2BAA2B,GAAG,OAAO,CAAA;QAC1C,OAAO,IAAI,CAAC,UAAU,CAAA;IAC1B,CAAC;IAEM,0BAA0B,CAC7B,OAA0C;QAE1C,IAAI,CAAC,qCAAqC,GAAG,OAAO,CAAA;IACxD,CAAC;IAEM,iBAAiB,CAAC,OAAiC;QACtD,IAAI,CAAC,4BAA4B,GAAG,OAAO,CAAA;IAC/C,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,OAA6B;QACpD,IAAI,CAAC,wBAAwB,GAAG,OAAO,CAAA;QACvC,OAAO,UAAU,CAAC,qBAAiC,CAAA;IACvD,CAAC;IAEM,wBAAwB,CAAC,OAAwC;QACpE,IAAI,CAAC,mCAAmC,GAAG,OAAO,CAAA;QAClD,OAAO,UAAU,CAAC,aAAa,CAAA;IACnC,CAAC;IAEM,yBAAyB,CAC5B,OAAyC;QAEzC,IAAI,CAAC,oCAAoC,GAAG,OAAO,CAAA;QACnD,IAAI,CAAC,iCAAiC,EAAE,CAAA;QACxC,OAAO,UAAU,CAAC,aAAa,CAAA;IACnC,CAAC;IAEM,YAAY,CAAC,OAA4B;QAC5C,IAAI,CAAC,oBAAoB,EAAE,CAAA;QAC3B,IAAI,CAAC,uBAAuB,GAAG,OAAO,CAAA;QACtC,OAAO,IAAI,CAAC,MAAM,CAAA;IACtB,CAAC;IAEM,aAAa,CAAC,OAA6B;QAC9C,IAAI,CAAC,qBAAqB,EAAE,CAAA;QAC5B,IAAI,CAAC,wBAAwB,GAAG,OAAO,CAAA;IAC3C,CAAC;IAEM,WAAW,CAAC,OAA2B;QAC1C,IAAI,CAAC,mBAAmB,EAAE,CAAA;QAC1B,IAAI,CAAC,sBAAsB,GAAG,OAAO,CAAA;QACrC,OAAO,EAAgB,CAAA;IAC3B,CAAC;IAEM,UAAU,CAAC,OAA0B;QACxC,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAA;QAEpC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAA;QAEvC,IAAI,MAAM,EAAE,CAAC;YACT,OAAO,CAAC,CAAA;QACZ,CAAC;QAED,OAAO,CAAC,CAAA;IACZ,CAAC;IAEM,SAAS,CAAC,OAAyB;QACtC,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAA;QAEnC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;QAE9C,IAAI,KAAK,IAAI,UAAU,EAAE,CAAC;YACtB,OAAO,CAAC,CAAA;QACZ,CAAC;QAED,OAAO,CAAC,CAAA;IACZ,CAAC;IAEM,UAAU,CAAC,OAA0B;QACxC,IAAI,CAAC,kBAAkB,EAAE,CAAA;QACzB,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAA;IACxC,CAAC;IAEM,YAAY,CAAC,OAA4B;QAC5C,IAAI,CAAC,oBAAoB,EAAE,CAAA;QAC3B,IAAI,CAAC,uBAAuB,GAAG,OAAO,CAAA;IAC1C,CAAC;IAEM,UAAU;QACb,IAAI,CAAC,kBAAkB,EAAE,CAAA;QACzB,OAAO,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAA;IAC/B,CAAC;IAEM,eAAe;QAClB,IAAI,CAAC,2BAA2B,GAAG,SAAS,CAAA;QAC5C,IAAI,CAAC,qCAAqC,GAAG,SAAS,CAAA;QACtD,IAAI,CAAC,uBAAuB,GAAG,SAAS,CAAA;QACxC,IAAI,CAAC,mCAAmC,GAAG,SAAS,CAAA;QACpD,IAAI,CAAC,oCAAoC,GAAG,SAAS,CAAA;QAErD,IAAI,CAAC,wBAAwB,GAAG,CAAC,CAAA;QACjC,IAAI,CAAC,qBAAqB,GAAG,CAAC,CAAA;QAC9B,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAA;QAC3B,IAAI,CAAC,iCAAiC,GAAG,CAAC,CAAA;QAE1C,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC,KAAK,EAAE,CAAA;QACjD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;QAC/C,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;IAC3D,CAAC"}
|
|
@@ -6,7 +6,7 @@ export default class FakeStreamInfo {
|
|
|
6
6
|
name = generateId();
|
|
7
7
|
type = generateId();
|
|
8
8
|
sourceId = generateId();
|
|
9
|
-
channelNames = [generateId(), generateId()];
|
|
9
|
+
channelNames = [generateId(), generateId(), generateId()];
|
|
10
10
|
channelFormat = 'float32';
|
|
11
11
|
sampleRateHz = 0;
|
|
12
12
|
units = 'N/A';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FakeStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/FakeStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAK/C,MAAM,CAAC,OAAO,OAAO,cAAc;IACxB,MAAM,CAAC,kBAAkB,GAAwB,EAAE,CAAA;IACnD,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAA;IAE5B,MAAM,CAAC,eAAe,GAAG,EAAqB,CAAA;IAE9C,IAAI,GAAG,UAAU,EAAE,CAAA;IACnB,IAAI,GAAG,UAAU,EAAE,CAAA;IACnB,QAAQ,GAAG,UAAU,EAAE,CAAA;IACvB,YAAY,GAAa,CAAC,UAAU,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"FakeStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/FakeStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAK/C,MAAM,CAAC,OAAO,OAAO,cAAc;IACxB,MAAM,CAAC,kBAAkB,GAAwB,EAAE,CAAA;IACnD,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAA;IAE5B,MAAM,CAAC,eAAe,GAAG,EAAqB,CAAA;IAE9C,IAAI,GAAG,UAAU,EAAE,CAAA;IACnB,IAAI,GAAG,UAAU,EAAE,CAAA;IACnB,QAAQ,GAAG,UAAU,EAAE,CAAA;IACvB,YAAY,GAAa,CAAC,UAAU,EAAE,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;IACnE,aAAa,GAAG,SAAkB,CAAA;IAClC,YAAY,GAAG,CAAC,CAAA;IAChB,KAAK,GAAG,KAAK,CAAA;IAEpB,YAAmB,OAA0B;QACzC,cAAc,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnD,CAAC;IAEM,OAAO;QACV,cAAc,CAAC,iBAAiB,EAAE,CAAA;IACtC,CAAC;IAED,IAAW,YAAY;QACnB,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAA;IACnC,CAAC;IAED,IAAW,eAAe;QACtB,OAAO,cAAc,CAAC,eAAe,CAAA;IACzC,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,cAAc,CAAC,kBAAkB,GAAG,EAAE,CAAA;QACtC,cAAc,CAAC,iBAAiB,GAAG,CAAC,CAAA;IACxC,CAAC"}
|
|
@@ -2,7 +2,6 @@ import { StreamInfo } from '../../impl/LslStreamInfo.js';
|
|
|
2
2
|
import LslStreamInlet, { OnDataCallback, StreamInletOptions } from '../../impl/LslStreamInlet.js';
|
|
3
3
|
export declare class SpyStreamInlet extends LslStreamInlet {
|
|
4
4
|
constructor(info: StreamInfo, options: StreamInletOptions, onData: OnDataCallback);
|
|
5
|
-
getName(): string;
|
|
6
5
|
getStreamInfo(): StreamInfo;
|
|
7
6
|
getBoundInlet(): import("../../index.js").BoundInlet;
|
|
8
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpyStreamInlet.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInlet/SpyStreamInlet.ts"],"names":[],"mappings":"AACA,OAAO,cAGN,MAAM,8BAA8B,CAAA;AAErC,MAAM,OAAO,cAAe,SAAQ,cAAc;IAC9C,YACI,IAAgB,EAChB,OAA2B,EAC3B,MAAsB;QAEtB,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IAChC,CAAC;IAEM,
|
|
1
|
+
{"version":3,"file":"SpyStreamInlet.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInlet/SpyStreamInlet.ts"],"names":[],"mappings":"AACA,OAAO,cAGN,MAAM,8BAA8B,CAAA;AAErC,MAAM,OAAO,cAAe,SAAQ,cAAc;IAC9C,YACI,IAAgB,EAChB,OAA2B,EAC3B,MAAsB;QAEtB,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IAChC,CAAC;IAEM,aAAa;QAChB,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,aAAa;QAChB,OAAO,IAAI,CAAC,KAAK,CAAA;IACrB,CAAC;CACJ"}
|
package/package.json
CHANGED
|
@@ -27,8 +27,6 @@ export default class AbstractPackageTest extends AbstractModuleTest {
|
|
|
27
27
|
|
|
28
28
|
protected static async beforeEach() {
|
|
29
29
|
await super.beforeEach()
|
|
30
|
-
|
|
31
|
-
this.setFakeLiblsl()
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
protected static setFakeLiblsl() {
|
|
@@ -46,8 +44,6 @@ export default class AbstractPackageTest extends AbstractModuleTest {
|
|
|
46
44
|
protected static setFakeStreamInfo() {
|
|
47
45
|
LslStreamInfo.Class = FakeStreamInfo
|
|
48
46
|
FakeStreamInfo.resetTestDouble()
|
|
49
|
-
|
|
50
|
-
LslStreamInfo['instanceCache'] = {}
|
|
51
47
|
}
|
|
52
48
|
|
|
53
49
|
protected static setSpyStreamInlet() {
|
|
@@ -101,7 +97,7 @@ export default class AbstractPackageTest extends AbstractModuleTest {
|
|
|
101
97
|
protected static readonly sampleRateHz = Math.floor(Math.random() * 100)
|
|
102
98
|
protected static readonly maxBufferedMs = Math.floor(Math.random() * 1000)
|
|
103
99
|
|
|
104
|
-
protected static LslStreamInlet(
|
|
100
|
+
protected static async LslStreamInlet(
|
|
105
101
|
options: Partial<StreamInletOptions>,
|
|
106
102
|
onData: OnDataCallback
|
|
107
103
|
) {
|
|
@@ -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()
|
|
@@ -265,6 +266,89 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
265
266
|
)
|
|
266
267
|
}
|
|
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
|
+
|
|
268
352
|
@test()
|
|
269
353
|
protected static async createsOutletWithRequiredParams() {
|
|
270
354
|
const { options, outlet } = this.createRandomOutlet()
|
|
@@ -401,7 +485,7 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
401
485
|
delete process.env.LIBLSL_PATH
|
|
402
486
|
|
|
403
487
|
LiblslAdapter.resetInstance()
|
|
404
|
-
this.instance = LiblslAdapter.getInstance()
|
|
488
|
+
this.instance = LiblslAdapter.getInstance() as FakeLiblsl
|
|
405
489
|
|
|
406
490
|
assert.isEqual(
|
|
407
491
|
this.ffiRsOpenOptions?.path,
|
|
@@ -586,6 +670,18 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
586
670
|
)
|
|
587
671
|
}
|
|
588
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
|
+
|
|
589
685
|
private static createRandomOutlet() {
|
|
590
686
|
const options = this.createRandomOutletOptions()
|
|
591
687
|
const outlet = this.instance.createOutlet(options)
|
|
@@ -636,6 +732,26 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
|
|
|
636
732
|
}
|
|
637
733
|
}
|
|
638
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
|
+
|
|
639
755
|
private static generateFailedMessage() {
|
|
640
756
|
return `Loading the liblsl dylib failed! I tried to load it from ${process.env.LIBLSL_PATH}.`
|
|
641
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,20 +219,46 @@ 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!'
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@test()
|
|
248
|
+
protected static async cachesInfoAttributesByBoundStreamInfo() {
|
|
249
|
+
const cached = LslStreamInfo.From(this.instance.getBoundInfo())
|
|
250
|
+
|
|
251
|
+
assert.isEqualDeep(
|
|
252
|
+
cached,
|
|
253
|
+
this.instance,
|
|
254
|
+
'Should have set bound stream info!'
|
|
230
255
|
)
|
|
231
256
|
}
|
|
232
257
|
|
|
233
258
|
private static readonly defaultOptions = {
|
|
234
|
-
name: this.
|
|
235
|
-
type: this.
|
|
236
|
-
sourceId: this.
|
|
259
|
+
name: this.name,
|
|
260
|
+
type: this.type,
|
|
261
|
+
sourceId: this.sourceId,
|
|
237
262
|
channelNames: this.channelNames,
|
|
238
263
|
channelFormat: 'float32',
|
|
239
264
|
sampleRateHz: 100 * Math.random(),
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { test, assert } from '@neurodevs/node-tdd'
|
|
2
|
+
import { BoundStreamInfo } from '../../impl/LiblslAdapter.js'
|
|
3
|
+
import LslStreamInfo, { StreamInfo } from '../../impl/LslStreamInfo.js'
|
|
2
4
|
import { StreamInletOptions } from '../../impl/LslStreamInlet.js'
|
|
5
|
+
import FakeLiblsl from '../../testDoubles/Liblsl/FakeLiblsl.js'
|
|
3
6
|
import FakeStreamInfo from '../../testDoubles/StreamInfo/FakeStreamInfo.js'
|
|
4
7
|
import { SpyStreamInlet } from '../../testDoubles/StreamInlet/SpyStreamInlet.js'
|
|
5
8
|
import AbstractPackageTest from '../AbstractPackageTest.js'
|
|
6
9
|
|
|
7
10
|
export default class LslStreamInletTest extends AbstractPackageTest {
|
|
8
11
|
private static instance: SpyStreamInlet
|
|
12
|
+
private static outletInfo: StreamInfo
|
|
13
|
+
private static passedHandle?: BoundStreamInfo
|
|
9
14
|
|
|
10
15
|
private static callsToOnData: {
|
|
11
16
|
samples: Float32Array
|
|
@@ -15,12 +20,33 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
15
20
|
protected static async beforeEach() {
|
|
16
21
|
await super.beforeEach()
|
|
17
22
|
|
|
18
|
-
this.
|
|
23
|
+
this.setFakeLiblsl()
|
|
19
24
|
this.setFakeStreamInfo()
|
|
25
|
+
this.setSpyStreamInlet()
|
|
20
26
|
|
|
21
27
|
this.callsToOnData = []
|
|
22
28
|
|
|
23
|
-
this.
|
|
29
|
+
this.outletInfo = LslStreamInfo.Create({
|
|
30
|
+
sourceId: this.sourceId,
|
|
31
|
+
channelNames: [],
|
|
32
|
+
channelFormat: 'float32',
|
|
33
|
+
sampleRateHz: 0,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
FakeStreamInfo.resetTestDouble()
|
|
37
|
+
|
|
38
|
+
FakeLiblsl.fakeStreamInfoHandles = [
|
|
39
|
+
this.outletInfo.boundStreamInfo as bigint,
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
const From = LslStreamInfo.From.bind(LslStreamInfo)
|
|
43
|
+
|
|
44
|
+
LslStreamInfo.From = (handle: BoundStreamInfo) => {
|
|
45
|
+
this.passedHandle = handle
|
|
46
|
+
return From(handle) as FakeStreamInfo
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this.instance = await this.LslStreamInlet()
|
|
24
50
|
}
|
|
25
51
|
|
|
26
52
|
@test()
|
|
@@ -31,30 +57,12 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
31
57
|
@test()
|
|
32
58
|
protected static async createsStreamInfoWithExpectedOptions() {
|
|
33
59
|
assert.isEqualDeep(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
channelNames: this.channelNames,
|
|
37
|
-
channelFormat: 'float32',
|
|
38
|
-
sampleRateHz: 0,
|
|
39
|
-
name: this.name_,
|
|
40
|
-
type: this.type,
|
|
41
|
-
sourceId: this.sourceId,
|
|
42
|
-
},
|
|
60
|
+
this.passedHandle,
|
|
61
|
+
this.outletInfo.boundStreamInfo,
|
|
43
62
|
'Stream info should have expected options!'
|
|
44
63
|
)
|
|
45
64
|
}
|
|
46
65
|
|
|
47
|
-
@test()
|
|
48
|
-
protected static async uniqueNameHasSetPrefix() {
|
|
49
|
-
const instance = this.LslStreamInlet({ name: undefined })
|
|
50
|
-
|
|
51
|
-
assert.doesInclude(
|
|
52
|
-
instance.getName(),
|
|
53
|
-
'lsl-inlet-',
|
|
54
|
-
'Name should have set prefix!'
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
66
|
@test()
|
|
59
67
|
protected static async callsBindingsToCreateStreamInlet() {
|
|
60
68
|
const fakeInfo = this.instance.getStreamInfo()
|
|
@@ -281,7 +289,7 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
281
289
|
private static async runInletWithOptions(
|
|
282
290
|
options?: Partial<StreamInletOptions>
|
|
283
291
|
) {
|
|
284
|
-
const inlet = this.LslStreamInlet(options)
|
|
292
|
+
const inlet = await this.LslStreamInlet(options)
|
|
285
293
|
await this.startThenStop(inlet)
|
|
286
294
|
return inlet
|
|
287
295
|
}
|
|
@@ -316,12 +324,14 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
316
324
|
this.callsToOnData.push({ samples, timestamps })
|
|
317
325
|
}
|
|
318
326
|
|
|
319
|
-
protected static LslStreamInlet(
|
|
320
|
-
|
|
327
|
+
protected static async LslStreamInlet(
|
|
328
|
+
options?: Partial<StreamInletOptions>
|
|
329
|
+
) {
|
|
330
|
+
return (await AbstractPackageTest.LslStreamInlet(
|
|
321
331
|
{
|
|
322
332
|
...options,
|
|
323
333
|
},
|
|
324
334
|
this.onData
|
|
325
|
-
) as SpyStreamInlet
|
|
335
|
+
)) as SpyStreamInlet
|
|
326
336
|
}
|
|
327
337
|
}
|
|
@@ -17,12 +17,14 @@ export default class LslWebSocketBridgeTest extends AbstractPackageTest {
|
|
|
17
17
|
protected static async beforeEach() {
|
|
18
18
|
await super.beforeEach()
|
|
19
19
|
|
|
20
|
+
this.setFakeLiblsl()
|
|
20
21
|
this.setFakeStreamInlet()
|
|
21
22
|
this.setFakeWebSocket()
|
|
22
23
|
this.setFakeWebSocketServer()
|
|
23
24
|
this.setSpyLslWebSocketBridge()
|
|
24
25
|
|
|
25
|
-
this.instance =
|
|
26
|
+
this.instance =
|
|
27
|
+
(await this.LslWebSocketBridge()) as SpyLslWebSocketBridge
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
@test()
|
|
@@ -32,25 +34,13 @@ export default class LslWebSocketBridgeTest extends AbstractPackageTest {
|
|
|
32
34
|
|
|
33
35
|
@test()
|
|
34
36
|
protected static async createsLslStreamInlet() {
|
|
35
|
-
const {
|
|
36
|
-
|
|
37
|
-
channelFormat,
|
|
38
|
-
sampleRateHz,
|
|
39
|
-
chunkSize,
|
|
40
|
-
name,
|
|
41
|
-
type,
|
|
42
|
-
sourceId,
|
|
43
|
-
} = FakeStreamInlet.callsToConstructor[0]?.options ?? {}
|
|
37
|
+
const { sourceId, chunkSize } =
|
|
38
|
+
FakeStreamInlet.callsToConstructor[0]?.options ?? {}
|
|
44
39
|
|
|
45
40
|
assert.isEqualDeep(
|
|
46
41
|
{
|
|
47
|
-
channelNames,
|
|
48
|
-
channelFormat,
|
|
49
|
-
sampleRateHz,
|
|
50
|
-
chunkSize,
|
|
51
|
-
name,
|
|
52
|
-
type,
|
|
53
42
|
sourceId,
|
|
43
|
+
chunkSize,
|
|
54
44
|
},
|
|
55
45
|
this.inletOptions
|
|
56
46
|
)
|
|
@@ -253,8 +243,8 @@ export default class LslWebSocketBridgeTest extends AbstractPackageTest {
|
|
|
253
243
|
|
|
254
244
|
@test()
|
|
255
245
|
protected static async throwsIfNeitherPortNorRemoteUrlsPassed() {
|
|
256
|
-
assert.
|
|
257
|
-
this.LslWebSocketBridge({
|
|
246
|
+
await assert.doesThrowAsync(async () => {
|
|
247
|
+
await this.LslWebSocketBridge({
|
|
258
248
|
listenPort: undefined,
|
|
259
249
|
connectUrls: undefined,
|
|
260
250
|
})
|
|
@@ -286,13 +276,8 @@ export default class LslWebSocketBridgeTest extends AbstractPackageTest {
|
|
|
286
276
|
private static readonly connectUrls = [this.generateId(), this.generateId()]
|
|
287
277
|
|
|
288
278
|
private static readonly inletOptions = {
|
|
289
|
-
channelNames: this.channelNames,
|
|
290
|
-
channelFormat: 'float32' as const,
|
|
291
|
-
sampleRateHz: 100 * Math.random(),
|
|
292
|
-
chunkSize: randomInt(1, 100),
|
|
293
|
-
name: this.generateId(),
|
|
294
|
-
type: this.generateId(),
|
|
295
279
|
sourceId: this.generateId(),
|
|
280
|
+
chunkSize: randomInt(1, 100),
|
|
296
281
|
}
|
|
297
282
|
|
|
298
283
|
private static readonly baseOptions = {
|
|
@@ -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
|
|
|
@@ -243,6 +303,10 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
243
303
|
return LiblslAdapter.load
|
|
244
304
|
}
|
|
245
305
|
|
|
306
|
+
private get alloc() {
|
|
307
|
+
return LiblslAdapter.alloc
|
|
308
|
+
}
|
|
309
|
+
|
|
246
310
|
private get liblslFuncs() {
|
|
247
311
|
return {
|
|
248
312
|
lsl_create_streaminfo: {
|
|
@@ -345,6 +409,8 @@ export interface Liblsl {
|
|
|
345
409
|
destroyStreamInfo(options: DestroyStreamInfoOptions): void
|
|
346
410
|
appendChannelsToStreamInfo(options: AppendChannelsToStreamInfoOptions): void
|
|
347
411
|
|
|
412
|
+
resolveByProp(options: ResolveByPropOptions): Promise<bigint[]>
|
|
413
|
+
|
|
348
414
|
createOutlet(options: CreateOutletOptions): BoundOutlet
|
|
349
415
|
|
|
350
416
|
pushSampleFloatTimestamp(
|
|
@@ -382,14 +448,21 @@ export interface AppendChannelsToStreamInfoOptions {
|
|
|
382
448
|
channels: LslChannel[]
|
|
383
449
|
}
|
|
384
450
|
|
|
385
|
-
export interface
|
|
451
|
+
export interface DestroyStreamInfoOptions {
|
|
386
452
|
info: BoundStreamInfo
|
|
387
|
-
chunkSize: number
|
|
388
|
-
maxBufferedMs: number
|
|
389
453
|
}
|
|
390
454
|
|
|
391
|
-
export interface
|
|
455
|
+
export interface ResolveByPropOptions {
|
|
456
|
+
prop: string
|
|
457
|
+
value: string
|
|
458
|
+
minResults?: number
|
|
459
|
+
timeoutMs?: number
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export interface CreateOutletOptions {
|
|
392
463
|
info: BoundStreamInfo
|
|
464
|
+
chunkSize: number
|
|
465
|
+
maxBufferedMs: number
|
|
393
466
|
}
|
|
394
467
|
|
|
395
468
|
export interface PushSampleFloatTimestampOptions {
|