@neurodevs/node-lsl 10.1.4 → 10.2.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__/AbstractNodeLslTest.d.ts +18 -0
- package/build/__tests__/AbstractNodeLslTest.js +80 -0
- package/build/__tests__/AbstractNodeLslTest.js.map +1 -0
- package/build/__tests__/{implementation/Liblsl.test.d.ts → Liblsl.test.d.ts} +6 -0
- package/build/__tests__/{implementation/Liblsl.test.js → Liblsl.test.js} +60 -14
- package/build/__tests__/Liblsl.test.js.map +1 -0
- package/build/__tests__/LslInlet.test.d.ts +11 -0
- package/build/__tests__/LslInlet.test.js +94 -0
- package/build/__tests__/LslInlet.test.js.map +1 -0
- package/build/__tests__/{behavioral/LslOutlet.test.d.ts → LslOutlet.test.d.ts} +3 -6
- package/build/__tests__/{behavioral/LslOutlet.test.js → LslOutlet.test.js} +24 -68
- package/build/__tests__/LslOutlet.test.js.map +1 -0
- package/build/__tests__/LslStreamInfo.test.d.ts +21 -0
- package/build/__tests__/LslStreamInfo.test.js +166 -0
- package/build/__tests__/LslStreamInfo.test.js.map +1 -0
- package/build/__tests__/SpyLslStreamInfo.d.ts +5 -0
- package/build/__tests__/SpyLslStreamInfo.js +17 -0
- package/build/__tests__/SpyLslStreamInfo.js.map +1 -0
- package/build/__tests__/{behavioral/TimeMarkerOutlet.test.d.ts → TimeMarkerOutlet.test.d.ts} +2 -3
- package/build/__tests__/{behavioral/TimeMarkerOutlet.test.js → TimeMarkerOutlet.test.js} +7 -33
- package/build/__tests__/TimeMarkerOutlet.test.js.map +1 -0
- package/build/{implementations → components}/Liblsl.d.ts +4 -2
- package/build/{implementations → components}/Liblsl.js +23 -4
- package/build/components/Liblsl.js.map +1 -0
- package/build/components/LslInlet.d.ts +31 -0
- package/build/components/LslInlet.js +51 -0
- package/build/components/LslInlet.js.map +1 -0
- package/build/{implementations → components}/LslOutlet.d.ts +20 -9
- package/build/components/LslOutlet.js +118 -0
- package/build/components/LslOutlet.js.map +1 -0
- package/build/components/LslStreamInfo.d.ts +38 -0
- package/build/components/LslStreamInfo.js +65 -0
- package/build/components/LslStreamInfo.js.map +1 -0
- package/build/{implementations → components}/TimeMarkerOutlet.d.ts +2 -1
- package/build/{implementations → components}/TimeMarkerOutlet.js +1 -1
- package/build/components/TimeMarkerOutlet.js.map +1 -0
- package/build/demo.d.ts +1 -0
- package/build/demo.js +42 -0
- package/build/demo.js.map +1 -0
- package/build/index.d.ts +12 -7
- package/build/index.js +16 -8
- package/build/index.js.map +1 -1
- package/build/nodeLsl.types.d.ts +34 -18
- package/build/testDoubles/FakeLiblsl.d.ts +11 -3
- package/build/testDoubles/FakeLiblsl.js +29 -5
- package/build/testDoubles/FakeLiblsl.js.map +1 -1
- package/build/testDoubles/FakeLslOutlet.d.ts +4 -2
- package/build/testDoubles/FakeLslOutlet.js +2 -1
- package/build/testDoubles/FakeLslOutlet.js.map +1 -1
- package/build/testDoubles/FakeLslStreamInfo.d.ts +5 -0
- package/build/testDoubles/FakeLslStreamInfo.js +10 -0
- package/build/testDoubles/FakeLslStreamInfo.js.map +1 -0
- package/build/testDoubles/FakeStreamInfo.d.ts +9 -0
- package/build/testDoubles/FakeStreamInfo.js +17 -0
- package/build/testDoubles/FakeStreamInfo.js.map +1 -0
- package/build/testDoubles/FakeTimeMarkerOutlet.d.ts +1 -1
- package/build/testDoubles/SpyLslInlet.d.ts +7 -0
- package/build/testDoubles/SpyLslInlet.js +20 -0
- package/build/testDoubles/SpyLslInlet.js.map +1 -0
- package/build/testDoubles/SpyLslStreamInfo.d.ts +9 -0
- package/build/testDoubles/SpyLslStreamInfo.js +28 -0
- package/build/testDoubles/SpyLslStreamInfo.js.map +1 -0
- package/build/testDoubles/SpyTimeMarkerOutlet.d.ts +4 -3
- package/build/testDoubles/SpyTimeMarkerOutlet.js +3 -3
- package/build/testDoubles/SpyTimeMarkerOutlet.js.map +1 -1
- package/build/testDoubles/consts.js.map +1 -0
- package/build/{__tests__/support → testDoubles}/generateRandomOutletOptions.d.ts +1 -1
- package/build/testDoubles/generateRandomOutletOptions.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/AbstractNodeLslTest.ts +50 -0
- package/src/__tests__/{implementation/Liblsl.test.ts → Liblsl.test.ts} +49 -8
- package/src/__tests__/LslInlet.test.ts +99 -0
- package/src/__tests__/{behavioral/LslOutlet.test.ts → LslOutlet.test.ts} +29 -64
- package/src/__tests__/LslStreamInfo.test.ts +209 -0
- package/src/__tests__/{behavioral/TimeMarkerOutlet.test.ts → TimeMarkerOutlet.test.ts} +12 -17
- package/src/{implementations → components}/Liblsl.ts +29 -5
- package/src/components/LslInlet.ts +85 -0
- package/src/{implementations → components}/LslOutlet.ts +91 -64
- package/src/components/LslStreamInfo.ts +105 -0
- package/src/{implementations → components}/TimeMarkerOutlet.ts +3 -1
- package/src/demo.ts +43 -0
- package/src/index.ts +15 -7
- package/src/nodeLsl.types.ts +36 -23
- package/src/testDoubles/FakeLiblsl.ts +40 -7
- package/src/testDoubles/FakeLslOutlet.ts +5 -2
- package/src/testDoubles/FakeStreamInfo.ts +19 -0
- package/src/testDoubles/FakeTimeMarkerOutlet.ts +1 -1
- package/src/testDoubles/SpyLslInlet.ts +16 -0
- package/src/testDoubles/SpyLslStreamInfo.ts +27 -0
- package/src/testDoubles/SpyTimeMarkerOutlet.ts +5 -4
- package/src/{__tests__/support → testDoubles}/generateRandomOutletOptions.ts +1 -1
- package/build/__tests__/behavioral/LslOutlet.test.js.map +0 -1
- package/build/__tests__/behavioral/TimeMarkerOutlet.test.js.map +0 -1
- package/build/__tests__/implementation/Liblsl.test.js.map +0 -1
- package/build/__tests__/support/consts.js.map +0 -1
- package/build/__tests__/support/generateRandomOutletOptions.js.map +0 -1
- package/build/implementations/Liblsl.js.map +0 -1
- package/build/implementations/LslOutlet.js +0 -94
- package/build/implementations/LslOutlet.js.map +0 -1
- package/build/implementations/TimeMarkerOutlet.js.map +0 -1
- /package/build/{__tests__/support → testDoubles}/consts.d.ts +0 -0
- /package/build/{__tests__/support → testDoubles}/consts.js +0 -0
- /package/build/{__tests__/support → testDoubles}/generateRandomOutletOptions.js +0 -0
- /package/src/{__tests__/support → testDoubles}/consts.ts +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { test, assert, generateId, errorAssert } from '@sprucelabs/test-utils'
|
|
2
|
+
import LslStreamInfo, { StreamInfoOptions } from '../components/LslStreamInfo'
|
|
3
|
+
import { CHANNEL_FORMATS } from '../consts'
|
|
4
|
+
import SpyLslStreamInfo from '../testDoubles/SpyLslStreamInfo'
|
|
5
|
+
import AbstractNodeLslTest from './AbstractNodeLslTest'
|
|
6
|
+
|
|
7
|
+
export default class LslStreamInfoTest extends AbstractNodeLslTest {
|
|
8
|
+
private static instance: SpyLslStreamInfo
|
|
9
|
+
|
|
10
|
+
protected static async beforeEach() {
|
|
11
|
+
await super.beforeEach()
|
|
12
|
+
|
|
13
|
+
this.setSpyLslStreamInfo()
|
|
14
|
+
|
|
15
|
+
this.instance = this.LslStreamInfo()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@test()
|
|
19
|
+
protected static async canCreateLslStreamInfo() {
|
|
20
|
+
assert.isTruthy(this.instance, 'Instance should be created!')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@test()
|
|
24
|
+
protected static async throwsWithMissingRequiredOptions() {
|
|
25
|
+
const err = assert.doesThrow(
|
|
26
|
+
// @ts-ignore
|
|
27
|
+
() => LslStreamInfo.Create()
|
|
28
|
+
)
|
|
29
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
30
|
+
parameters: ['channelNames', 'channelFormat', 'sampleRate'],
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@test()
|
|
35
|
+
protected static async generatesUniqueNameIfNotProvided() {
|
|
36
|
+
const instance1 = this.LslStreamInfo({ name: undefined })
|
|
37
|
+
const instance2 = this.LslStreamInfo({ name: undefined })
|
|
38
|
+
|
|
39
|
+
assert.isNotEqual(
|
|
40
|
+
instance1.getName(),
|
|
41
|
+
instance2.getName(),
|
|
42
|
+
'Inlet names should be unique!'
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@test()
|
|
47
|
+
protected static async uniqueNameHasSetPrefix() {
|
|
48
|
+
const instance = this.LslStreamInfo({ name: undefined })
|
|
49
|
+
|
|
50
|
+
assert.doesInclude(
|
|
51
|
+
instance.getName(),
|
|
52
|
+
'lsl-stream-info-',
|
|
53
|
+
'Name should have set prefix!'
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@test()
|
|
58
|
+
protected static async canManuallySetName() {
|
|
59
|
+
const name = generateId()
|
|
60
|
+
const instance = this.LslStreamInfo({ name })
|
|
61
|
+
|
|
62
|
+
assert.isEqual(
|
|
63
|
+
instance.getName(),
|
|
64
|
+
name,
|
|
65
|
+
'Name should be set to provided value!'
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@test()
|
|
70
|
+
protected static async generatesUniqueTypeIfNotProvided() {
|
|
71
|
+
const instance1 = this.LslStreamInfo({ type: undefined })
|
|
72
|
+
const instance2 = this.LslStreamInfo({ type: undefined })
|
|
73
|
+
|
|
74
|
+
assert.isNotEqual(
|
|
75
|
+
instance1.getType(),
|
|
76
|
+
instance2.getType(),
|
|
77
|
+
'Inlet types should be unique!'
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@test()
|
|
82
|
+
protected static async canManuallySetType() {
|
|
83
|
+
const type = generateId()
|
|
84
|
+
const instance = this.LslStreamInfo({ type })
|
|
85
|
+
|
|
86
|
+
assert.isEqual(
|
|
87
|
+
instance.getType(),
|
|
88
|
+
type,
|
|
89
|
+
'Type should be set to provided value!'
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@test()
|
|
94
|
+
protected static async generatesUniqueSourceIdIfNotProvided() {
|
|
95
|
+
const instance1 = this.LslStreamInfo({ sourceId: undefined })
|
|
96
|
+
const instance2 = this.LslStreamInfo({ sourceId: undefined })
|
|
97
|
+
|
|
98
|
+
assert.isNotEqual(
|
|
99
|
+
instance1.getSourceId(),
|
|
100
|
+
instance2.getSourceId(),
|
|
101
|
+
'Inlet sourceIds should be unique!'
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@test()
|
|
106
|
+
protected static async canManuallySetSourceId() {
|
|
107
|
+
const sourceId = generateId()
|
|
108
|
+
const instance = this.LslStreamInfo({ sourceId })
|
|
109
|
+
|
|
110
|
+
assert.isEqual(
|
|
111
|
+
instance.getSourceId(),
|
|
112
|
+
sourceId,
|
|
113
|
+
'SourceId should be set to provided value!'
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@test()
|
|
118
|
+
protected static async setsUnitsToNAIfNotProvided() {
|
|
119
|
+
assert.isEqual(
|
|
120
|
+
this.instance.getUnits(),
|
|
121
|
+
'N/A',
|
|
122
|
+
'Units should be set to "N/A"!'
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@test()
|
|
127
|
+
protected static async canManuallySetUnits() {
|
|
128
|
+
const units = generateId()
|
|
129
|
+
const instance = this.LslStreamInfo({ units })
|
|
130
|
+
|
|
131
|
+
assert.isEqual(
|
|
132
|
+
instance.getUnits(),
|
|
133
|
+
units,
|
|
134
|
+
'Units should be set to provided value!'
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@test()
|
|
139
|
+
protected static async callsBindingsToCreateStreamInfo() {
|
|
140
|
+
assert.isEqual(
|
|
141
|
+
this.fakeLiblsl.createStreamInfoHitCount,
|
|
142
|
+
1,
|
|
143
|
+
'Should have called createStreamInfo!'
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@test()
|
|
148
|
+
protected static async passesOptionsToStreamInfo() {
|
|
149
|
+
const randomChannelIdx = Math.floor(
|
|
150
|
+
Math.random() * CHANNEL_FORMATS.length
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
const options = {
|
|
154
|
+
name: generateId(),
|
|
155
|
+
type: generateId(),
|
|
156
|
+
sourceId: generateId(),
|
|
157
|
+
channelCount: this.channelNames.length,
|
|
158
|
+
channelFormat: CHANNEL_FORMATS[randomChannelIdx],
|
|
159
|
+
sampleRate: 100 * Math.random(),
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this.LslStreamInfo(options)
|
|
163
|
+
|
|
164
|
+
const expected = {
|
|
165
|
+
...options,
|
|
166
|
+
channelFormat: randomChannelIdx,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
assert.isEqualDeep(
|
|
170
|
+
this.fakeLiblsl.lastCreateStreamInfoOptions,
|
|
171
|
+
expected,
|
|
172
|
+
'Should have passed options to createStreamInfo!'
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@test()
|
|
177
|
+
protected static async appendsChannelsToStreamInfo() {
|
|
178
|
+
this.LslStreamInfo({ units: this.units, type: this.type })
|
|
179
|
+
|
|
180
|
+
assert.isEqualDeep(
|
|
181
|
+
this.fakeLiblsl.lastAppendChannelsToStreamInfoOptions,
|
|
182
|
+
{
|
|
183
|
+
info: this.instance.getStreamInfo(),
|
|
184
|
+
channels: this.channelNames.map((label: string) => ({
|
|
185
|
+
label,
|
|
186
|
+
unit: this.units,
|
|
187
|
+
type: this.type,
|
|
188
|
+
})),
|
|
189
|
+
},
|
|
190
|
+
'Should have called appendChannelsToStreamInfo!'
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private static LslStreamInfo(options?: Partial<StreamInfoOptions>) {
|
|
195
|
+
return LslStreamInfo.Create({
|
|
196
|
+
...this.defaultOptions,
|
|
197
|
+
...options,
|
|
198
|
+
}) as SpyLslStreamInfo
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private static readonly defaultOptions = {
|
|
202
|
+
name: generateId(),
|
|
203
|
+
type: generateId(),
|
|
204
|
+
sourceId: generateId(),
|
|
205
|
+
channelNames: this.channelNames,
|
|
206
|
+
channelFormat: 'float32',
|
|
207
|
+
sampleRate: 100 * Math.random(),
|
|
208
|
+
} as StreamInfoOptions
|
|
209
|
+
}
|
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
import { randomInt } from 'crypto'
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import FakeLiblsl from '../../testDoubles/FakeLiblsl'
|
|
11
|
-
import SpyTimeMarkerOutlet from '../../testDoubles/SpyTimeMarkerOutlet'
|
|
12
|
-
import generateRandomOutletOptions from '../support/generateRandomOutletOptions'
|
|
13
|
-
|
|
14
|
-
export default class TimeMarkerOutletTest extends AbstractSpruceTest {
|
|
15
|
-
private static fakeLiblsl: FakeLiblsl
|
|
2
|
+
import { assert, generateId, test } from '@sprucelabs/test-utils'
|
|
3
|
+
import { LslOutletOptions } from '../components/LslOutlet'
|
|
4
|
+
import TimeMarkerOutletImpl from '../components/TimeMarkerOutlet'
|
|
5
|
+
import generateRandomOutletOptions from '../testDoubles/generateRandomOutletOptions'
|
|
6
|
+
import SpyTimeMarkerOutlet from '../testDoubles/SpyTimeMarkerOutlet'
|
|
7
|
+
import AbstractNodeLslTest from './AbstractNodeLslTest'
|
|
8
|
+
|
|
9
|
+
export default class TimeMarkerOutletTest extends AbstractNodeLslTest {
|
|
16
10
|
private static outlet: SpyTimeMarkerOutlet
|
|
17
11
|
|
|
18
12
|
protected static async beforeEach() {
|
|
19
13
|
await super.beforeEach()
|
|
20
|
-
|
|
21
|
-
this.
|
|
22
|
-
|
|
14
|
+
|
|
15
|
+
this.setSpyTimeMarkerOutlet()
|
|
16
|
+
this.setFakeLiblsl()
|
|
17
|
+
|
|
23
18
|
this.outlet = await this.Outlet()
|
|
24
19
|
}
|
|
25
20
|
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
DestroyOutletOptions,
|
|
11
11
|
PushSampleFloatTimestampOptions,
|
|
12
12
|
PushSampleStringTimestampOptions,
|
|
13
|
+
CreateInletOptions,
|
|
14
|
+
DestroyInletOptions,
|
|
13
15
|
} from '../nodeLsl.types'
|
|
14
16
|
|
|
15
17
|
export default class LiblslImpl implements Liblsl {
|
|
@@ -80,6 +82,16 @@ export default class LiblslImpl implements Liblsl {
|
|
|
80
82
|
retType: DataType.Void,
|
|
81
83
|
paramsType: [DataType.External],
|
|
82
84
|
},
|
|
85
|
+
lsl_create_inlet: {
|
|
86
|
+
library: 'lsl',
|
|
87
|
+
retType: DataType.External,
|
|
88
|
+
paramsType: [DataType.External, DataType.I32, DataType.I32],
|
|
89
|
+
},
|
|
90
|
+
lsl_destroy_inlet: {
|
|
91
|
+
library: 'lsl',
|
|
92
|
+
retType: DataType.Void,
|
|
93
|
+
paramsType: [DataType.External],
|
|
94
|
+
},
|
|
83
95
|
lsl_local_clock: {
|
|
84
96
|
library: 'lsl',
|
|
85
97
|
retType: DataType.Double,
|
|
@@ -182,11 +194,6 @@ export default class LiblslImpl implements Liblsl {
|
|
|
182
194
|
return this.bindings.lsl_create_outlet([info, chunkSize, maxBuffered])
|
|
183
195
|
}
|
|
184
196
|
|
|
185
|
-
public destroyOutlet(options: DestroyOutletOptions) {
|
|
186
|
-
const { outlet } = assertOptions(options, ['outlet'])
|
|
187
|
-
this.bindings.lsl_destroy_outlet([outlet])
|
|
188
|
-
}
|
|
189
|
-
|
|
190
197
|
public pushSampleFloatTimestamp(options: PushSampleFloatTimestampOptions) {
|
|
191
198
|
const { outlet, sample, timestamp } = assertOptions(options, [
|
|
192
199
|
'outlet',
|
|
@@ -207,6 +214,23 @@ export default class LiblslImpl implements Liblsl {
|
|
|
207
214
|
this.bindings.lsl_push_sample_strt([outlet, sample, timestamp])
|
|
208
215
|
}
|
|
209
216
|
|
|
217
|
+
public destroyOutlet(options: DestroyOutletOptions) {
|
|
218
|
+
const { outlet } = assertOptions(options, ['outlet'])
|
|
219
|
+
this.bindings.lsl_destroy_outlet([outlet])
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
public createInlet(options: CreateInletOptions) {
|
|
223
|
+
const { info, chunkSize, maxBuffered } = assertOptions(options, [
|
|
224
|
+
'info',
|
|
225
|
+
'chunkSize',
|
|
226
|
+
'maxBuffered',
|
|
227
|
+
])
|
|
228
|
+
|
|
229
|
+
return this.bindings.lsl_create_inlet([info, chunkSize, maxBuffered])
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public destroyInlet(_options: DestroyInletOptions) {}
|
|
233
|
+
|
|
210
234
|
public localClock() {
|
|
211
235
|
return this.bindings.lsl_local_clock([])
|
|
212
236
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { assertOptions } from '@sprucelabs/schema'
|
|
2
|
+
import { generateId } from '@sprucelabs/test-utils'
|
|
3
|
+
import { ChannelFormat } from '../nodeLsl.types'
|
|
4
|
+
import LiblslImpl from './Liblsl'
|
|
5
|
+
import LslStreamInfo, { StreamInfo, StreamInfoOptions } from './LslStreamInfo'
|
|
6
|
+
|
|
7
|
+
export default class LslInlet implements StreamInlet {
|
|
8
|
+
public static Class?: LslInletConstructor
|
|
9
|
+
|
|
10
|
+
protected name: string
|
|
11
|
+
protected info: StreamInfo
|
|
12
|
+
private chunkSize: number
|
|
13
|
+
private maxBuffered: number
|
|
14
|
+
|
|
15
|
+
protected constructor(info: StreamInfo, options: LslInletOptions) {
|
|
16
|
+
const {
|
|
17
|
+
name = this.defaultName,
|
|
18
|
+
chunkSize,
|
|
19
|
+
maxBuffered,
|
|
20
|
+
} = options ?? {}
|
|
21
|
+
|
|
22
|
+
this.info = info
|
|
23
|
+
this.chunkSize = chunkSize
|
|
24
|
+
this.maxBuffered = maxBuffered
|
|
25
|
+
this.name = name
|
|
26
|
+
|
|
27
|
+
this.createLslInlet()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static Create(options: LslInletOptions) {
|
|
31
|
+
assertOptions(options, [
|
|
32
|
+
'channelNames',
|
|
33
|
+
'channelFormat',
|
|
34
|
+
'sampleRate',
|
|
35
|
+
'chunkSize',
|
|
36
|
+
'maxBuffered',
|
|
37
|
+
])
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
39
|
+
const { maxBuffered, chunkSize, ...streamInfoOptions } = options
|
|
40
|
+
const info = this.LslStreamInfo(streamInfoOptions)
|
|
41
|
+
return new (this.Class ?? this)(info, options)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private createLslInlet() {
|
|
45
|
+
this.lsl.createInlet({
|
|
46
|
+
info: this.boundStreamInfo,
|
|
47
|
+
chunkSize: this.chunkSize,
|
|
48
|
+
maxBuffered: this.maxBuffered,
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private get boundStreamInfo() {
|
|
53
|
+
return this.info.boundStreamInfo
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private get lsl() {
|
|
57
|
+
return LiblslImpl.getInstance()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private readonly defaultName = `lsl-inlet-${generateId()}`
|
|
61
|
+
|
|
62
|
+
private static LslStreamInfo(options: StreamInfoOptions) {
|
|
63
|
+
return LslStreamInfo.Create(options)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface StreamInlet {}
|
|
68
|
+
|
|
69
|
+
export type LslInletConstructor = new (
|
|
70
|
+
info: StreamInfo,
|
|
71
|
+
options: LslInletOptions
|
|
72
|
+
) => StreamInlet
|
|
73
|
+
|
|
74
|
+
export interface LslInletOptions {
|
|
75
|
+
sampleRate: number
|
|
76
|
+
channelNames: string[]
|
|
77
|
+
channelFormat: ChannelFormat
|
|
78
|
+
chunkSize: number
|
|
79
|
+
maxBuffered: number
|
|
80
|
+
name?: string
|
|
81
|
+
type?: string
|
|
82
|
+
sourceId?: string
|
|
83
|
+
manufacturer?: string
|
|
84
|
+
units?: string
|
|
85
|
+
}
|
|
@@ -6,90 +6,82 @@ import {
|
|
|
6
6
|
assertValidMaxBuffered,
|
|
7
7
|
assertValidSampleRate,
|
|
8
8
|
} from '../assertions'
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
ChannelFormat,
|
|
12
|
-
BoundOutlet,
|
|
13
|
-
BoundStreamInfo,
|
|
14
|
-
Liblsl,
|
|
15
|
-
LslSample,
|
|
16
|
-
} from '../nodeLsl.types'
|
|
9
|
+
import { ChannelFormat, BoundOutlet, Liblsl, LslSample } from '../nodeLsl.types'
|
|
17
10
|
import LiblslImpl from './Liblsl'
|
|
11
|
+
import LslStreamInfo, { StreamInfo, StreamInfoOptions } from './LslStreamInfo'
|
|
18
12
|
|
|
19
13
|
export default class LslOutletImpl implements LslOutlet {
|
|
20
14
|
public static Class?: LslOutletConstructor
|
|
21
15
|
|
|
16
|
+
private info: StreamInfo
|
|
22
17
|
private options: LslOutletOptions
|
|
23
|
-
private
|
|
24
|
-
private
|
|
25
|
-
|
|
18
|
+
private outlet!: BoundOutlet
|
|
19
|
+
private pushSampleByType!: (options: any) => void
|
|
20
|
+
|
|
21
|
+
protected constructor(info: StreamInfo, options: LslOutletOptions) {
|
|
22
|
+
this.info = info
|
|
23
|
+
this.options = options
|
|
24
|
+
|
|
25
|
+
this.validateOptions()
|
|
26
|
+
this.createLslOutlet()
|
|
27
|
+
this.setPushSampleType()
|
|
28
|
+
}
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
public static async Create(options: LslOutletOptions) {
|
|
31
|
+
assertOptions(options, [
|
|
29
32
|
'name',
|
|
30
33
|
'type',
|
|
34
|
+
'sourceId',
|
|
31
35
|
'channelNames',
|
|
32
|
-
'sampleRate',
|
|
33
36
|
'channelFormat',
|
|
34
|
-
'
|
|
35
|
-
'manufacturer',
|
|
36
|
-
'unit',
|
|
37
|
+
'sampleRate',
|
|
37
38
|
'chunkSize',
|
|
38
39
|
'maxBuffered',
|
|
40
|
+
'manufacturer',
|
|
41
|
+
'unit',
|
|
39
42
|
])
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const { chunkSize, maxBuffered, channelNames, ...streamInfoOptions } =
|
|
44
|
-
this.options as any
|
|
44
|
+
const { waitAfterConstructionMs = 10 } = options ?? {}
|
|
45
45
|
|
|
46
|
-
const
|
|
46
|
+
const streamInfoOptions = {
|
|
47
|
+
channelNames: options.channelNames,
|
|
48
|
+
channelFormat: options.channelFormat,
|
|
49
|
+
sampleRate: options.sampleRate,
|
|
50
|
+
name: options.name,
|
|
51
|
+
type: options.type,
|
|
52
|
+
sourceId: options.sourceId,
|
|
53
|
+
units: options.unit,
|
|
54
|
+
}
|
|
47
55
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
assertValidChannelFormat(channelFormat)
|
|
51
|
-
assertValidChunkSize(chunkSize)
|
|
52
|
-
assertValidMaxBuffered(maxBuffered)
|
|
56
|
+
const info = this.LslStreamInfo(streamInfoOptions)
|
|
57
|
+
const instance = new (this.Class ?? this)(info, options)
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
delete streamInfoOptions.unit
|
|
59
|
+
await this.wait(waitAfterConstructionMs)
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
channelCount,
|
|
60
|
-
channelFormat: this.lookupChannelFormat(channelFormat),
|
|
61
|
-
})
|
|
61
|
+
return instance
|
|
62
|
+
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
})
|
|
64
|
+
private validateOptions() {
|
|
65
|
+
assertValidChannelCount(this.channelCount)
|
|
66
|
+
assertValidSampleRate(this.sampleRate)
|
|
67
|
+
assertValidChannelFormat(this.channelFormat)
|
|
68
|
+
assertValidChunkSize(this.chunkSize)
|
|
69
|
+
assertValidMaxBuffered(this.maxBuffered)
|
|
70
|
+
}
|
|
71
71
|
|
|
72
|
+
private createLslOutlet() {
|
|
72
73
|
this.outlet = this.lsl.createOutlet({
|
|
73
|
-
info: this.
|
|
74
|
-
chunkSize: this.
|
|
75
|
-
maxBuffered: this.
|
|
74
|
+
info: this.boundStreamInfo,
|
|
75
|
+
chunkSize: this.chunkSize,
|
|
76
|
+
maxBuffered: this.maxBuffered,
|
|
76
77
|
})
|
|
78
|
+
}
|
|
77
79
|
|
|
80
|
+
private setPushSampleType() {
|
|
78
81
|
const pushMethod = this.getPushMethod()
|
|
79
82
|
this.pushSampleByType = this.lsl[pushMethod].bind(this.lsl)
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
public static async Create(options: LslOutletOptions) {
|
|
83
|
-
const { waitAfterConstructionMs = 10 } = options ?? {}
|
|
84
|
-
const instance = new (this.Class ?? this)(options)
|
|
85
|
-
await this.wait(waitAfterConstructionMs)
|
|
86
|
-
return instance
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private static async wait(waitMs: number) {
|
|
90
|
-
return new Promise((resolve) => setTimeout(resolve, waitMs))
|
|
91
|
-
}
|
|
92
|
-
|
|
93
85
|
public destroy() {
|
|
94
86
|
this.lsl.destroyOutlet({ outlet: this.outlet })
|
|
95
87
|
}
|
|
@@ -105,7 +97,7 @@ export default class LslOutletImpl implements LslOutlet {
|
|
|
105
97
|
}
|
|
106
98
|
|
|
107
99
|
private getPushMethod() {
|
|
108
|
-
const channelFormat = this.
|
|
100
|
+
const channelFormat = this.channelFormat
|
|
109
101
|
|
|
110
102
|
const methodMap: Record<string, keyof Liblsl> = {
|
|
111
103
|
float32: 'pushSampleFloatTimestamp',
|
|
@@ -120,13 +112,45 @@ export default class LslOutletImpl implements LslOutlet {
|
|
|
120
112
|
return methodMap[channelFormat]
|
|
121
113
|
}
|
|
122
114
|
|
|
123
|
-
private
|
|
124
|
-
return
|
|
115
|
+
private get channelNames() {
|
|
116
|
+
return this.options.channelNames
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private get channelCount() {
|
|
120
|
+
return this.channelNames.length
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private get channelFormat() {
|
|
124
|
+
return this.options.channelFormat
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private get sampleRate() {
|
|
128
|
+
return this.options.sampleRate
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private get chunkSize() {
|
|
132
|
+
return this.options.chunkSize
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private get maxBuffered() {
|
|
136
|
+
return this.options.maxBuffered
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private get boundStreamInfo() {
|
|
140
|
+
return this.info.boundStreamInfo
|
|
125
141
|
}
|
|
126
142
|
|
|
127
143
|
private get lsl() {
|
|
128
144
|
return LiblslImpl.getInstance()
|
|
129
145
|
}
|
|
146
|
+
|
|
147
|
+
private static async wait(waitMs: number) {
|
|
148
|
+
return new Promise((resolve) => setTimeout(resolve, waitMs))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private static LslStreamInfo(options: StreamInfoOptions) {
|
|
152
|
+
return LslStreamInfo.Create(options)
|
|
153
|
+
}
|
|
130
154
|
}
|
|
131
155
|
|
|
132
156
|
export interface LslOutlet {
|
|
@@ -134,18 +158,21 @@ export interface LslOutlet {
|
|
|
134
158
|
pushSample(sample: LslSample): void
|
|
135
159
|
}
|
|
136
160
|
|
|
137
|
-
export type LslOutletConstructor = new (
|
|
161
|
+
export type LslOutletConstructor = new (
|
|
162
|
+
info: StreamInfo,
|
|
163
|
+
options: LslOutletOptions
|
|
164
|
+
) => LslOutlet
|
|
138
165
|
|
|
139
166
|
export interface LslOutletOptions {
|
|
140
167
|
name: string
|
|
141
168
|
type: string
|
|
169
|
+
sourceId: string
|
|
142
170
|
channelNames: string[]
|
|
143
|
-
sampleRate: number
|
|
144
171
|
channelFormat: ChannelFormat
|
|
145
|
-
|
|
146
|
-
manufacturer: string
|
|
147
|
-
unit: string
|
|
172
|
+
sampleRate: number
|
|
148
173
|
chunkSize: number
|
|
149
174
|
maxBuffered: number
|
|
175
|
+
manufacturer: string
|
|
176
|
+
unit: string
|
|
150
177
|
waitAfterConstructionMs?: number
|
|
151
178
|
}
|