@neurodevs/node-lsl 17.0.0 → 17.1.1
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 +2 -0
- package/build/__tests__/AbstractPackageTest.js +2 -6
- package/build/__tests__/AbstractPackageTest.js.map +1 -1
- package/build/__tests__/impl/LslStreamInfo.test.d.ts +3 -3
- package/build/__tests__/impl/LslStreamInfo.test.js +12 -12
- package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamInlet.test.d.ts +2 -3
- package/build/__tests__/impl/LslStreamInlet.test.js +20 -27
- package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
- package/build/__tests__/impl/LslWebSocketBridge.test.js +6 -3
- package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
- package/build/impl/LiblslAdapter.d.ts +1 -6
- package/build/impl/LiblslAdapter.js +3 -3
- package/build/impl/LiblslAdapter.js.map +1 -1
- package/build/impl/LslStreamInfo.d.ts +3 -9
- package/build/impl/LslStreamInfo.js +6 -16
- package/build/impl/LslStreamInfo.js.map +1 -1
- package/build/impl/LslStreamInlet.d.ts +7 -5
- package/build/impl/LslStreamInlet.js +20 -24
- package/build/impl/LslStreamInlet.js.map +1 -1
- package/build/impl/LslStreamOutlet.d.ts +3 -3
- package/build/impl/LslStreamOutlet.js +5 -8
- package/build/impl/LslStreamOutlet.js.map +1 -1
- package/build/impl/LslWebSocketBridge.d.ts +2 -1
- package/build/impl/LslWebSocketBridge.js +1 -1
- package/build/impl/LslWebSocketBridge.js.map +1 -1
- package/build/scripts/runLslStreamOutlet.js +15 -10
- package/build/scripts/runLslStreamOutlet.js.map +1 -1
- package/build/scripts/runOutletToInlet.js +1 -6
- package/build/scripts/runOutletToInlet.js.map +1 -1
- package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +1 -1
- package/build/testDoubles/Liblsl/FakeLiblsl.js +1 -1
- package/build/testDoubles/Liblsl/FakeLiblsl.js.map +1 -1
- package/build/testDoubles/StreamInfo/FakeStreamInfo.d.ts +4 -4
- package/build/testDoubles/StreamInfo/FakeStreamInfo.js +3 -3
- package/build/testDoubles/StreamInfo/FakeStreamInfo.js.map +1 -1
- package/build/testDoubles/StreamInfo/SpyStreamInfo.d.ts +0 -1
- package/build/testDoubles/StreamInfo/SpyStreamInfo.js +0 -3
- package/build/testDoubles/StreamInfo/SpyStreamInfo.js.map +1 -1
- package/build/testDoubles/StreamInlet/FakeStreamInlet.d.ts +3 -3
- package/build/testDoubles/StreamInlet/FakeStreamInlet.js.map +1 -1
- package/build/testDoubles/StreamInlet/SpyStreamInlet.d.ts +2 -2
- package/build/testDoubles/StreamInlet/SpyStreamInlet.js.map +1 -1
- package/build/testDoubles/StreamOutlet/FakeStreamOutlet.d.ts +1 -0
- package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js +3 -0
- package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js.map +1 -1
- package/package.json +12 -12
- package/src/__tests__/AbstractPackageTest.ts +4 -8
- package/src/__tests__/impl/LslStreamInfo.test.ts +10 -10
- package/src/__tests__/impl/LslStreamInlet.test.ts +26 -36
- package/src/__tests__/impl/LslWebSocketBridge.test.ts +7 -5
- package/src/impl/LiblslAdapter.ts +4 -9
- package/src/impl/LslStreamInfo.ts +13 -27
- package/src/impl/LslStreamInlet.ts +35 -39
- package/src/impl/LslStreamOutlet.ts +6 -9
- package/src/impl/LslWebSocketBridge.ts +4 -4
- package/src/scripts/runLslStreamOutlet.ts +16 -10
- package/src/scripts/runOutletToInlet.ts +1 -6
- package/src/testDoubles/Liblsl/FakeLiblsl.ts +1 -1
- package/src/testDoubles/StreamInfo/FakeStreamInfo.ts +5 -5
- package/src/testDoubles/StreamInfo/SpyStreamInfo.ts +0 -4
- package/src/testDoubles/StreamInlet/FakeStreamInlet.ts +6 -3
- package/src/testDoubles/StreamInlet/SpyStreamInlet.ts +2 -2
- package/src/testDoubles/StreamOutlet/FakeStreamOutlet.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neurodevs/node-lsl",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.1.1",
|
|
4
4
|
"description": "Lab Streaming Layer (LSL) bindings for Node",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -45,27 +45,27 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@neurodevs/generate-id": "^1.0.9",
|
|
48
|
-
"ffi-rs": "^1.3.
|
|
49
|
-
"node-gyp": "^
|
|
48
|
+
"ffi-rs": "^1.3.1",
|
|
49
|
+
"node-gyp": "^12.1.0",
|
|
50
50
|
"ref-array-napi": "^1.2.2",
|
|
51
51
|
"ref-napi": "^3.0.3",
|
|
52
52
|
"ws": "^8.18.3"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@neurodevs/node-tdd": "^0.2.
|
|
55
|
+
"@neurodevs/node-tdd": "^0.2.3",
|
|
56
56
|
"@types/ffi-napi": "^4.0.10",
|
|
57
|
-
"@types/node": "^
|
|
57
|
+
"@types/node": "^25.0.2",
|
|
58
58
|
"@types/ws": "^8.18.1",
|
|
59
59
|
"chokidar-cli": "^3.0.0",
|
|
60
|
-
"concurrently": "^9.1
|
|
61
|
-
"eslint": "^9.
|
|
60
|
+
"concurrently": "^9.2.1",
|
|
61
|
+
"eslint": "^9.39.2",
|
|
62
62
|
"eslint-config-spruce": "^11.2.26",
|
|
63
|
-
"jest": "^
|
|
64
|
-
"jest-circus": "^
|
|
65
|
-
"prettier": "^3.
|
|
63
|
+
"jest": "^30.2.0",
|
|
64
|
+
"jest-circus": "^30.2.0",
|
|
65
|
+
"prettier": "^3.7.4",
|
|
66
66
|
"ts-node": "^10.9.2",
|
|
67
|
-
"tsc-watch": "^
|
|
68
|
-
"typescript": "^5.
|
|
67
|
+
"tsc-watch": "^7.2.0",
|
|
68
|
+
"typescript": "^5.9.3"
|
|
69
69
|
},
|
|
70
70
|
"jest": {
|
|
71
71
|
"testRunner": "jest-circus/runner",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import AbstractModuleTest from '@neurodevs/node-tdd'
|
|
2
|
-
import WebSocket from 'ws'
|
|
2
|
+
import WebSocket, { Server } from 'ws'
|
|
3
3
|
|
|
4
|
-
import { Server } from 'ws'
|
|
5
4
|
import LiblslAdapter from '../impl/LiblslAdapter.js'
|
|
6
5
|
import LslEventMarkerOutlet from '../impl/LslEventMarkerOutlet.js'
|
|
7
6
|
import LslStreamInfo from '../impl/LslStreamInfo.js'
|
|
@@ -11,6 +10,7 @@ import LslStreamInlet, {
|
|
|
11
10
|
} from '../impl/LslStreamInlet.js'
|
|
12
11
|
import LslStreamOutlet from '../impl/LslStreamOutlet.js'
|
|
13
12
|
import LslWebSocketBridge from '../impl/LslWebSocketBridge.js'
|
|
13
|
+
|
|
14
14
|
import SpyEventMarkerOutlet from '../testDoubles/EventMarkerOutlet/SpyEventMarkerOutlet.js'
|
|
15
15
|
import FakeLiblsl from '../testDoubles/Liblsl/FakeLiblsl.js'
|
|
16
16
|
import FakeStreamInfo from '../testDoubles/StreamInfo/FakeStreamInfo.js'
|
|
@@ -78,6 +78,7 @@ export default class AbstractPackageTest extends AbstractModuleTest {
|
|
|
78
78
|
FakeWebSocketServer.resetTestDouble()
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
protected static readonly info = new FakeStreamInfo()
|
|
81
82
|
protected static readonly name_ = this.generateId()
|
|
82
83
|
protected static readonly type = this.generateId()
|
|
83
84
|
protected static readonly sourceId = this.generateId()
|
|
@@ -102,14 +103,9 @@ export default class AbstractPackageTest extends AbstractModuleTest {
|
|
|
102
103
|
onData: OnDataCallback
|
|
103
104
|
) {
|
|
104
105
|
const defaultOptions = {
|
|
105
|
-
|
|
106
|
-
channelNames: this.channelNames,
|
|
107
|
-
channelFormat: 'float32',
|
|
106
|
+
info: this.info,
|
|
108
107
|
chunkSize: this.chunkSize,
|
|
109
108
|
maxBufferedMs: this.maxBufferedMs,
|
|
110
|
-
name: this.name_,
|
|
111
|
-
type: this.type,
|
|
112
|
-
sourceId: this.sourceId,
|
|
113
109
|
...options,
|
|
114
110
|
} as StreamInletOptions
|
|
115
111
|
|
|
@@ -196,7 +196,7 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
196
196
|
assert.isEqualDeep(
|
|
197
197
|
this.fakeLiblsl.lastAppendChannelsToStreamInfoOptions,
|
|
198
198
|
{
|
|
199
|
-
info: this.instance.
|
|
199
|
+
info: this.instance.boundInfo,
|
|
200
200
|
channels: this.channelNames.map((label: string) => ({
|
|
201
201
|
label,
|
|
202
202
|
units: this.units,
|
|
@@ -213,15 +213,15 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
213
213
|
|
|
214
214
|
assert.isEqualDeep(
|
|
215
215
|
this.fakeLiblsl.lastDestroyStreamInfoOptions?.info,
|
|
216
|
-
this.instance.
|
|
216
|
+
this.instance.boundInfo,
|
|
217
217
|
'Should have called destroyStreamInfo!'
|
|
218
218
|
)
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
@test()
|
|
222
|
-
protected static async
|
|
222
|
+
protected static async doesNotCreateNewStreamInfoIfPassedBoundInfo() {
|
|
223
223
|
this.LslStreamInfo({
|
|
224
|
-
|
|
224
|
+
boundInfo: this.instance.boundInfo,
|
|
225
225
|
})
|
|
226
226
|
|
|
227
227
|
assert.isEqual(
|
|
@@ -232,21 +232,21 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
@test()
|
|
235
|
-
protected static async
|
|
235
|
+
protected static async setsBoundInfoWhenPassed() {
|
|
236
236
|
const instance = this.LslStreamInfo({
|
|
237
|
-
|
|
237
|
+
boundInfo: this.instance.boundInfo,
|
|
238
238
|
})
|
|
239
239
|
|
|
240
240
|
assert.isEqualDeep(
|
|
241
|
-
instance.
|
|
242
|
-
this.instance.
|
|
241
|
+
instance.boundInfo,
|
|
242
|
+
this.instance.boundInfo,
|
|
243
243
|
'Should have set bound stream info!'
|
|
244
244
|
)
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
@test()
|
|
248
|
-
protected static async
|
|
249
|
-
const cached = LslStreamInfo.From(this.instance.
|
|
248
|
+
protected static async cachesInfoAttributesByBoundInfo() {
|
|
249
|
+
const cached = LslStreamInfo.From(this.instance.boundInfo)
|
|
250
250
|
|
|
251
251
|
assert.isEqualDeep(
|
|
252
252
|
cached,
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { test, assert } from '@neurodevs/node-tdd'
|
|
2
|
-
|
|
3
|
-
import LslStreamInfo, { StreamInfo } from '../../impl/LslStreamInfo.js'
|
|
2
|
+
|
|
4
3
|
import { StreamInletOptions } from '../../impl/LslStreamInlet.js'
|
|
5
|
-
import FakeLiblsl from '../../testDoubles/Liblsl/FakeLiblsl.js'
|
|
6
|
-
import FakeStreamInfo from '../../testDoubles/StreamInfo/FakeStreamInfo.js'
|
|
7
4
|
import { SpyStreamInlet } from '../../testDoubles/StreamInlet/SpyStreamInlet.js'
|
|
8
5
|
import AbstractPackageTest from '../AbstractPackageTest.js'
|
|
9
6
|
|
|
10
7
|
export default class LslStreamInletTest extends AbstractPackageTest {
|
|
11
8
|
private static instance: SpyStreamInlet
|
|
12
|
-
private static outletInfo: StreamInfo
|
|
13
|
-
private static passedHandle?: BoundStreamInfo
|
|
14
9
|
|
|
15
10
|
private static callsToOnData: {
|
|
16
11
|
samples: Float32Array
|
|
@@ -26,26 +21,6 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
26
21
|
|
|
27
22
|
this.callsToOnData = []
|
|
28
23
|
|
|
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
24
|
this.instance = await this.LslStreamInlet()
|
|
50
25
|
}
|
|
51
26
|
|
|
@@ -54,15 +29,6 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
54
29
|
assert.isTruthy(this.instance, 'Failed to create instance!')
|
|
55
30
|
}
|
|
56
31
|
|
|
57
|
-
@test()
|
|
58
|
-
protected static async createsStreamInfoWithExpectedOptions() {
|
|
59
|
-
assert.isEqualDeep(
|
|
60
|
-
this.passedHandle,
|
|
61
|
-
this.outletInfo.boundStreamInfo,
|
|
62
|
-
'Stream info should have expected options!'
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
32
|
@test()
|
|
67
33
|
protected static async callsBindingsToCreateStreamInlet() {
|
|
68
34
|
const fakeInfo = this.instance.getStreamInfo()
|
|
@@ -72,7 +38,7 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
72
38
|
assert.isEqualDeep(
|
|
73
39
|
this.fakeLiblsl.lastCreateInletOptions,
|
|
74
40
|
{
|
|
75
|
-
info: fakeInfo.
|
|
41
|
+
info: fakeInfo.boundInfo,
|
|
76
42
|
maxBufferedMs: this.maxBufferedMs,
|
|
77
43
|
},
|
|
78
44
|
'Should have called createInlet!'
|
|
@@ -101,6 +67,30 @@ export default class LslStreamInletTest extends AbstractPackageTest {
|
|
|
101
67
|
)
|
|
102
68
|
}
|
|
103
69
|
|
|
70
|
+
@test()
|
|
71
|
+
protected static async destroyCallsStopIfIsRunning() {
|
|
72
|
+
this.instance.startPulling()
|
|
73
|
+
this.instance.destroy()
|
|
74
|
+
|
|
75
|
+
assert.isFalse(
|
|
76
|
+
this.instance.isRunning,
|
|
77
|
+
'Did not stop inlet before destroying!'
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@test()
|
|
82
|
+
protected static async destroyDoesNotCallStopIfNotRunning() {
|
|
83
|
+
let wasHit = false
|
|
84
|
+
|
|
85
|
+
this.instance.stopPulling = () => {
|
|
86
|
+
wasHit = true
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.instance.destroy()
|
|
90
|
+
|
|
91
|
+
assert.isFalse(wasHit, 'Stop should not have been called!')
|
|
92
|
+
}
|
|
93
|
+
|
|
104
94
|
@test()
|
|
105
95
|
protected static async exposesIsRunningFieldThatIsFalseAtFirst() {
|
|
106
96
|
assert.isFalse(this.isRunning, 'isRunning should be false at first!')
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { randomInt } from 'crypto'
|
|
2
|
-
|
|
3
2
|
import { test, assert } from '@neurodevs/node-tdd'
|
|
4
3
|
|
|
5
4
|
import LslWebSocketBridge, {
|
|
6
5
|
WebSocketBridgeOptions,
|
|
7
6
|
} from '../../impl/LslWebSocketBridge.js'
|
|
7
|
+
import FakeStreamInfo from '../../testDoubles/StreamInfo/FakeStreamInfo.js'
|
|
8
8
|
import FakeStreamInlet from '../../testDoubles/StreamInlet/FakeStreamInlet.js'
|
|
9
9
|
import SpyLslWebSocketBridge from '../../testDoubles/WebSocketBridge/SpyLslWebSocketBridge.js'
|
|
10
10
|
import FakeWebSocket from '../../testDoubles/WebSockets/FakeWebSocket.js'
|
|
@@ -34,12 +34,14 @@ export default class LslWebSocketBridgeTest extends AbstractPackageTest {
|
|
|
34
34
|
|
|
35
35
|
@test()
|
|
36
36
|
protected static async createsLslStreamInlet() {
|
|
37
|
-
const
|
|
38
|
-
|
|
37
|
+
const call = FakeStreamInlet.callsToConstructor[0]
|
|
38
|
+
|
|
39
|
+
const info = call?.info
|
|
40
|
+
const chunkSize = call?.options?.chunkSize
|
|
39
41
|
|
|
40
42
|
assert.isEqualDeep(
|
|
41
43
|
{
|
|
42
|
-
|
|
44
|
+
info,
|
|
43
45
|
chunkSize,
|
|
44
46
|
},
|
|
45
47
|
this.inletOptions
|
|
@@ -276,7 +278,7 @@ export default class LslWebSocketBridgeTest extends AbstractPackageTest {
|
|
|
276
278
|
private static readonly connectUrls = [this.generateId(), this.generateId()]
|
|
277
279
|
|
|
278
280
|
private static readonly inletOptions = {
|
|
279
|
-
|
|
281
|
+
info: new FakeStreamInfo(),
|
|
280
282
|
chunkSize: randomInt(1, 100),
|
|
281
283
|
}
|
|
282
284
|
|
|
@@ -267,12 +267,12 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
267
267
|
],
|
|
268
268
|
paramsValue: [
|
|
269
269
|
inlet,
|
|
270
|
-
|
|
271
|
-
|
|
270
|
+
dataBufferPtr,
|
|
271
|
+
timestampBufferPtr,
|
|
272
272
|
dataBufferElements,
|
|
273
273
|
timestampBufferElements,
|
|
274
274
|
timeout,
|
|
275
|
-
|
|
275
|
+
errcodePtr,
|
|
276
276
|
],
|
|
277
277
|
})
|
|
278
278
|
}
|
|
@@ -494,14 +494,9 @@ export interface PullSampleOptions {
|
|
|
494
494
|
errcodePtr: JsExternal
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
-
export interface PullChunkOptions {
|
|
498
|
-
inlet: BoundInlet
|
|
499
|
-
dataBufferPtr: JsExternal
|
|
497
|
+
export interface PullChunkOptions extends PullSampleOptions {
|
|
500
498
|
timestampBufferPtr: JsExternal
|
|
501
|
-
dataBufferElements: number
|
|
502
499
|
timestampBufferElements: number
|
|
503
|
-
timeout: number
|
|
504
|
-
errcodePtr: JsExternal
|
|
505
500
|
}
|
|
506
501
|
|
|
507
502
|
export interface FlushInletOptions {
|
|
@@ -17,26 +17,20 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
17
17
|
public readonly channelFormat: ChannelFormat
|
|
18
18
|
public readonly sampleRateHz: number
|
|
19
19
|
public readonly units: string
|
|
20
|
-
|
|
21
|
-
protected boundInfo!: BoundStreamInfo
|
|
22
|
-
|
|
23
|
-
private readonly defaultName = `lsl-stream-info-${generateId()}`
|
|
24
|
-
private readonly defaultType = generateId()
|
|
25
|
-
private readonly defaultSourceId = generateId()
|
|
26
|
-
private readonly defaultUnits = 'N/A'
|
|
20
|
+
public readonly boundInfo: BoundStreamInfo
|
|
27
21
|
|
|
28
22
|
private lsl = LiblslAdapter.getInstance()
|
|
29
23
|
|
|
30
24
|
protected constructor(options: StreamInfoOptions) {
|
|
31
25
|
const {
|
|
32
|
-
name =
|
|
33
|
-
type =
|
|
34
|
-
sourceId =
|
|
26
|
+
name = `lsl-stream-info-${generateId()}`,
|
|
27
|
+
type = generateId(),
|
|
28
|
+
sourceId = generateId(),
|
|
35
29
|
channelNames,
|
|
36
30
|
channelFormat,
|
|
37
31
|
sampleRateHz,
|
|
38
|
-
units =
|
|
39
|
-
|
|
32
|
+
units = 'N/A',
|
|
33
|
+
boundInfo,
|
|
40
34
|
} = options
|
|
41
35
|
|
|
42
36
|
this.name = name
|
|
@@ -48,18 +42,18 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
48
42
|
this.sampleRateHz = sampleRateHz
|
|
49
43
|
this.units = units
|
|
50
44
|
|
|
51
|
-
if (!
|
|
52
|
-
this.createStreamInfo()
|
|
45
|
+
if (!boundInfo) {
|
|
46
|
+
this.boundInfo = this.createStreamInfo()
|
|
53
47
|
this.appendChannelsToStreamInfo()
|
|
54
48
|
} else {
|
|
55
|
-
this.boundInfo =
|
|
49
|
+
this.boundInfo = boundInfo
|
|
56
50
|
}
|
|
57
51
|
}
|
|
58
52
|
|
|
59
53
|
public static Create(options: StreamInfoOptions) {
|
|
60
54
|
const instance = new (this.Class ?? this)(options)
|
|
61
55
|
|
|
62
|
-
const {
|
|
56
|
+
const { boundInfo: handle } = instance
|
|
63
57
|
this.instanceCache.set(handle, instance)
|
|
64
58
|
|
|
65
59
|
return instance
|
|
@@ -70,7 +64,7 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
70
64
|
}
|
|
71
65
|
|
|
72
66
|
private createStreamInfo() {
|
|
73
|
-
|
|
67
|
+
return this.lsl.createStreamInfo({
|
|
74
68
|
name: this.name,
|
|
75
69
|
type: this.type,
|
|
76
70
|
sourceId: this.sourceId,
|
|
@@ -98,14 +92,6 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
98
92
|
public destroy() {
|
|
99
93
|
this.lsl.destroyStreamInfo({ info: this.boundInfo })
|
|
100
94
|
}
|
|
101
|
-
|
|
102
|
-
public get boundStreamInfo() {
|
|
103
|
-
return this.boundInfo
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public set boundStreamInfo(boundInfo: BoundStreamInfo) {
|
|
107
|
-
this.boundInfo = boundInfo
|
|
108
|
-
}
|
|
109
95
|
}
|
|
110
96
|
|
|
111
97
|
export interface StreamInfo {
|
|
@@ -118,7 +104,7 @@ export interface StreamInfo {
|
|
|
118
104
|
readonly channelCount: number
|
|
119
105
|
readonly channelFormat: ChannelFormat
|
|
120
106
|
readonly sampleRateHz: number
|
|
121
|
-
|
|
107
|
+
readonly boundInfo: BoundStreamInfo
|
|
122
108
|
}
|
|
123
109
|
|
|
124
110
|
type StreamInfoConstructor = new (options: StreamInfoOptions) => StreamInfo
|
|
@@ -131,5 +117,5 @@ export interface StreamInfoOptions {
|
|
|
131
117
|
type?: string
|
|
132
118
|
sourceId?: string
|
|
133
119
|
units?: string
|
|
134
|
-
|
|
120
|
+
boundInfo?: BoundStreamInfo
|
|
135
121
|
}
|
|
@@ -3,7 +3,7 @@ import { createPointer, DataType, JsExternal, unwrapPointer } from 'ffi-rs'
|
|
|
3
3
|
import handleError from '../handleError.js'
|
|
4
4
|
import { BoundInlet } from './LiblslAdapter.js'
|
|
5
5
|
import LiblslAdapter from './LiblslAdapter.js'
|
|
6
|
-
import
|
|
6
|
+
import { StreamInfo } from './LslStreamInfo.js'
|
|
7
7
|
|
|
8
8
|
export default class LslStreamInlet implements StreamInlet {
|
|
9
9
|
public static Class?: StreamInletConstructor
|
|
@@ -25,12 +25,15 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
private dataBuffer!: Buffer<ArrayBuffer>
|
|
28
|
+
private wrappedDataBufferPtr!: JsExternal[]
|
|
28
29
|
private dataBufferPtr!: JsExternal
|
|
29
30
|
|
|
30
31
|
private timestampBuffer!: Buffer<ArrayBuffer>
|
|
32
|
+
private wrappedTimestampBufferPtr!: JsExternal[]
|
|
31
33
|
private timestampBufferPtr!: JsExternal
|
|
32
34
|
|
|
33
35
|
private errorCodeBuffer!: Buffer<ArrayBuffer>
|
|
36
|
+
private wrappedErrorCodeBufferPtr!: JsExternal[]
|
|
34
37
|
private errorCodeBufferPtr!: JsExternal
|
|
35
38
|
|
|
36
39
|
private readonly sixMinutesInMs = 360 * 1000
|
|
@@ -39,7 +42,7 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
39
42
|
|
|
40
43
|
protected constructor(
|
|
41
44
|
info: StreamInfo,
|
|
42
|
-
options:
|
|
45
|
+
options: StreamInletConstructorOptions,
|
|
43
46
|
onData: OnDataCallback
|
|
44
47
|
) {
|
|
45
48
|
const { chunkSize, maxBufferedMs, timeoutMs } = options ?? {}
|
|
@@ -59,8 +62,7 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
59
62
|
options: StreamInletOptions,
|
|
60
63
|
onData: OnDataCallback
|
|
61
64
|
) {
|
|
62
|
-
const {
|
|
63
|
-
const info = await this.LslStreamInfo(sourceId)
|
|
65
|
+
const { info } = options
|
|
64
66
|
return new (this.Class ?? this)(info, options, onData)
|
|
65
67
|
}
|
|
66
68
|
|
|
@@ -74,15 +76,11 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
74
76
|
|
|
75
77
|
private createBoundInlet() {
|
|
76
78
|
this.inlet = this.lsl.createInlet({
|
|
77
|
-
info: this.
|
|
79
|
+
info: this.info.boundInfo,
|
|
78
80
|
maxBufferedMs: this.maxBufferedMs,
|
|
79
81
|
})
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
private get boundStreamInfo() {
|
|
83
|
-
return this.info.boundStreamInfo
|
|
84
|
-
}
|
|
85
|
-
|
|
86
84
|
public startPulling() {
|
|
87
85
|
this.isRunning = true
|
|
88
86
|
|
|
@@ -127,29 +125,33 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
127
125
|
}
|
|
128
126
|
|
|
129
127
|
private createDataBufferPtr() {
|
|
130
|
-
this.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
)[0]
|
|
128
|
+
this.wrappedDataBufferPtr = createPointer({
|
|
129
|
+
paramsType: [DataType.U8Array],
|
|
130
|
+
paramsValue: [this.dataBuffer],
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
this.dataBufferPtr = unwrapPointer(this.wrappedDataBufferPtr)[0]
|
|
136
134
|
}
|
|
137
135
|
|
|
138
136
|
private createTimestampBufferPtr() {
|
|
137
|
+
this.wrappedTimestampBufferPtr = createPointer({
|
|
138
|
+
paramsType: [DataType.U8Array],
|
|
139
|
+
paramsValue: [this.timestampBuffer],
|
|
140
|
+
})
|
|
141
|
+
|
|
139
142
|
this.timestampBufferPtr = unwrapPointer(
|
|
140
|
-
|
|
141
|
-
paramsType: [DataType.U8Array],
|
|
142
|
-
paramsValue: [this.timestampBuffer],
|
|
143
|
-
})
|
|
143
|
+
this.wrappedTimestampBufferPtr
|
|
144
144
|
)[0]
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
private createErrorCodeBufferPtr() {
|
|
148
|
+
this.wrappedErrorCodeBufferPtr = createPointer({
|
|
149
|
+
paramsType: [DataType.U8Array],
|
|
150
|
+
paramsValue: [this.errorCodeBuffer],
|
|
151
|
+
})
|
|
152
|
+
|
|
148
153
|
this.errorCodeBufferPtr = unwrapPointer(
|
|
149
|
-
|
|
150
|
-
paramsType: [DataType.U8Array],
|
|
151
|
-
paramsValue: [this.errorCodeBuffer],
|
|
152
|
-
})
|
|
154
|
+
this.wrappedErrorCodeBufferPtr
|
|
153
155
|
)[0]
|
|
154
156
|
}
|
|
155
157
|
|
|
@@ -171,7 +173,7 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
171
173
|
private pullSample() {
|
|
172
174
|
const timestamp = this.callPullSampleBinding()
|
|
173
175
|
|
|
174
|
-
if (timestamp) {
|
|
176
|
+
if (timestamp > 0) {
|
|
175
177
|
return {
|
|
176
178
|
samples: this.createFloatArrayFromDataBuffer(),
|
|
177
179
|
timestamps: new Float64Array([timestamp]),
|
|
@@ -201,7 +203,7 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
201
203
|
private pullChunk() {
|
|
202
204
|
const firstTimestamp = this.callPullChunkBinding()
|
|
203
205
|
|
|
204
|
-
if (firstTimestamp) {
|
|
206
|
+
if (firstTimestamp > 0) {
|
|
205
207
|
return {
|
|
206
208
|
samples: this.createFloatArrayFromDataBuffer(),
|
|
207
209
|
timestamps: this.createDoubleArrayFromTimestampBuffer(),
|
|
@@ -214,8 +216,8 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
214
216
|
return this.lsl.pullChunk({
|
|
215
217
|
inlet: this.inlet,
|
|
216
218
|
dataBufferPtr: this.dataBufferPtr,
|
|
217
|
-
timestampBufferPtr: this.timestampBufferPtr,
|
|
218
219
|
dataBufferElements: this.chunkSize * this.channelCount,
|
|
220
|
+
timestampBufferPtr: this.timestampBufferPtr,
|
|
219
221
|
timestampBufferElements: this.chunkSize,
|
|
220
222
|
timeout: this.timeoutMs / 1000,
|
|
221
223
|
errcodePtr: this.errorCodeBufferPtr,
|
|
@@ -243,23 +245,15 @@ export default class LslStreamInlet implements StreamInlet {
|
|
|
243
245
|
}
|
|
244
246
|
|
|
245
247
|
public destroy() {
|
|
248
|
+
if (this.isRunning) {
|
|
249
|
+
this.stopPulling()
|
|
250
|
+
}
|
|
246
251
|
this.destroyBoundInlet()
|
|
247
252
|
}
|
|
248
253
|
|
|
249
254
|
private destroyBoundInlet() {
|
|
250
255
|
this.lsl.destroyInlet({ inlet: this.inlet })
|
|
251
256
|
}
|
|
252
|
-
|
|
253
|
-
private static async LslStreamInfo(sourceId: string) {
|
|
254
|
-
const lsl = LiblslAdapter.getInstance()
|
|
255
|
-
|
|
256
|
-
const handles = await lsl.resolveByProp({
|
|
257
|
-
prop: 'source_id',
|
|
258
|
-
value: sourceId,
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
return LslStreamInfo.From(handles[0])
|
|
262
|
-
}
|
|
263
257
|
}
|
|
264
258
|
|
|
265
259
|
export interface StreamInlet {
|
|
@@ -272,17 +266,19 @@ export interface StreamInlet {
|
|
|
272
266
|
|
|
273
267
|
export type StreamInletConstructor = new (
|
|
274
268
|
info: StreamInfo,
|
|
275
|
-
options:
|
|
269
|
+
options: StreamInletConstructorOptions,
|
|
276
270
|
onData: OnDataCallback
|
|
277
271
|
) => StreamInlet
|
|
278
272
|
|
|
279
273
|
export interface StreamInletOptions {
|
|
280
|
-
|
|
274
|
+
info: StreamInfo
|
|
281
275
|
chunkSize: number
|
|
282
276
|
maxBufferedMs?: number
|
|
283
277
|
timeoutMs?: number
|
|
284
278
|
}
|
|
285
279
|
|
|
280
|
+
export type StreamInletConstructorOptions = Omit<StreamInletOptions, 'info'>
|
|
281
|
+
|
|
286
282
|
export type OnDataCallback = (
|
|
287
283
|
samples: Float32Array,
|
|
288
284
|
timestamps: Float64Array
|
|
@@ -21,6 +21,7 @@ import LslStreamInfo, {
|
|
|
21
21
|
export default class LslStreamOutlet implements StreamOutlet {
|
|
22
22
|
public static Class?: StreamOutletConstructor
|
|
23
23
|
|
|
24
|
+
public readonly info: StreamInfo
|
|
24
25
|
public readonly name: string
|
|
25
26
|
public readonly type: string
|
|
26
27
|
public readonly sourceId: string
|
|
@@ -33,7 +34,6 @@ export default class LslStreamOutlet implements StreamOutlet {
|
|
|
33
34
|
public readonly manufacturer: string = 'N/A'
|
|
34
35
|
public readonly units: string = 'N/A'
|
|
35
36
|
|
|
36
|
-
private info: StreamInfo
|
|
37
37
|
private boundOutlet!: BoundOutlet
|
|
38
38
|
private pushSampleMethod!: (options: unknown) => LslErrorCode
|
|
39
39
|
|
|
@@ -109,16 +109,12 @@ export default class LslStreamOutlet implements StreamOutlet {
|
|
|
109
109
|
|
|
110
110
|
private createStreamOutlet() {
|
|
111
111
|
this.boundOutlet = this.lsl.createOutlet({
|
|
112
|
-
info: this.
|
|
112
|
+
info: this.info.boundInfo,
|
|
113
113
|
chunkSize: this.chunkSize,
|
|
114
114
|
maxBufferedMs: this.maxBufferedMs,
|
|
115
115
|
})
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
private get boundStreamInfo() {
|
|
119
|
-
return this.info.boundStreamInfo
|
|
120
|
-
}
|
|
121
|
-
|
|
122
118
|
private setPushSampleMethod() {
|
|
123
119
|
this.pushSampleMethod = (
|
|
124
120
|
this.lsl[this.pushMethod] as (options: unknown) => LslErrorCode
|
|
@@ -146,12 +142,12 @@ export default class LslStreamOutlet implements StreamOutlet {
|
|
|
146
142
|
}
|
|
147
143
|
|
|
148
144
|
public destroy() {
|
|
149
|
-
this.
|
|
145
|
+
this.destroyBoundInfo()
|
|
150
146
|
this.destroyBoundOutlet()
|
|
151
147
|
}
|
|
152
148
|
|
|
153
|
-
private
|
|
154
|
-
this.lsl.destroyStreamInfo({ info: this.
|
|
149
|
+
private destroyBoundInfo() {
|
|
150
|
+
this.lsl.destroyStreamInfo({ info: this.info.boundInfo })
|
|
155
151
|
}
|
|
156
152
|
|
|
157
153
|
private destroyBoundOutlet() {
|
|
@@ -190,6 +186,7 @@ export default class LslStreamOutlet implements StreamOutlet {
|
|
|
190
186
|
export interface StreamOutlet {
|
|
191
187
|
pushSample(sample: LslSample): void
|
|
192
188
|
destroy(): void
|
|
189
|
+
readonly info: StreamInfo
|
|
193
190
|
readonly name: string
|
|
194
191
|
readonly type: string
|
|
195
192
|
readonly sourceId: string
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import WebSocket, { WebSocketServer } from 'ws'
|
|
2
|
+
import { StreamInfo } from './LslStreamInfo.js'
|
|
2
3
|
import LslStreamInlet, {
|
|
3
4
|
StreamInlet,
|
|
4
5
|
StreamInletOptions,
|
|
@@ -153,7 +154,7 @@ export default class LslWebSocketBridge implements WebSocketBridge {
|
|
|
153
154
|
return listenPort ? new this.WSS({ port: listenPort }) : undefined
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
private static LslStreamInlet(
|
|
157
|
+
private static async LslStreamInlet(
|
|
157
158
|
options: StreamInletOptions,
|
|
158
159
|
localServer?: WebSocketServer,
|
|
159
160
|
remoteSockets?: WebSocket[]
|
|
@@ -174,14 +175,13 @@ export type WebSocketBridgeConstructor = new (
|
|
|
174
175
|
) => WebSocketBridge
|
|
175
176
|
|
|
176
177
|
export interface WebSocketBridgeOptions {
|
|
177
|
-
|
|
178
|
+
info: StreamInfo
|
|
178
179
|
chunkSize: number
|
|
179
180
|
listenPort?: number
|
|
180
181
|
connectUrls?: string | string[]
|
|
181
182
|
}
|
|
182
183
|
|
|
183
|
-
export interface WebSocketBridgeConstructorOptions
|
|
184
|
-
extends WebSocketBridgeOptions {
|
|
184
|
+
export interface WebSocketBridgeConstructorOptions extends WebSocketBridgeOptions {
|
|
185
185
|
inlet: StreamInlet
|
|
186
186
|
localServer?: WebSocketServer
|
|
187
187
|
remoteSockets?: WebSocket[]
|