@neurodevs/node-lsl 2.0.1 → 3.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/README.md +1 -1
- package/build/Liblsl.d.ts +33 -25
- package/build/Liblsl.js +29 -30
- package/build/Liblsl.js.map +1 -1
- package/build/LslOutlet.d.ts +7 -5
- package/build/LslOutlet.js +26 -18
- package/build/LslOutlet.js.map +1 -1
- package/build/__tests__/behavioral/LslOutlet.test.d.ts +10 -10
- package/build/__tests__/behavioral/LslOutlet.test.js +60 -57
- package/build/__tests__/behavioral/LslOutlet.test.js.map +1 -1
- package/build/__tests__/implementation/Liblsl.test.d.ts +9 -9
- package/build/__tests__/implementation/Liblsl.test.js +76 -66
- package/build/__tests__/implementation/Liblsl.test.js.map +1 -1
- package/package.json +1 -1
- package/src/Liblsl.ts +76 -73
- package/src/LslOutlet.ts +37 -30
- package/src/__tests__/behavioral/LslOutlet.test.ts +74 -71
- package/src/__tests__/implementation/Liblsl.test.ts +96 -84
package/src/LslOutlet.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { SchemaError, assertOptions } from '@sprucelabs/schema'
|
|
2
|
-
import LiblslImpl, {
|
|
2
|
+
import LiblslImpl, { BoundOutlet, BoundStreamInfo, LslSample } from './Liblsl'
|
|
3
3
|
|
|
4
4
|
export default class LslOutletImpl implements LslOutlet {
|
|
5
5
|
private outletOptions: LslOutletOptions
|
|
6
6
|
public static Class?: new (options: LslOutletOptions) => LslOutlet
|
|
7
|
-
private streamInfo:
|
|
7
|
+
private streamInfo: BoundStreamInfo
|
|
8
|
+
private outlet: BoundOutlet
|
|
8
9
|
|
|
9
10
|
protected constructor(options: LslOutletOptions) {
|
|
10
11
|
const { sampleRate, channelFormat } = assertOptions(options, [
|
|
11
12
|
'name',
|
|
12
13
|
'type',
|
|
13
|
-
'
|
|
14
|
+
'channelNames',
|
|
14
15
|
'sampleRate',
|
|
15
16
|
'channelFormat',
|
|
16
17
|
'sourceId',
|
|
@@ -22,10 +23,12 @@ export default class LslOutletImpl implements LslOutlet {
|
|
|
22
23
|
|
|
23
24
|
this.outletOptions = options
|
|
24
25
|
|
|
25
|
-
const { chunkSize, maxBuffered,
|
|
26
|
+
const { chunkSize, maxBuffered, channelNames, ...streamInfoOptions } = this
|
|
26
27
|
.outletOptions as any
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
const channelCount = channelNames.length
|
|
30
|
+
|
|
31
|
+
this.assertValidChannelCount(channelCount)
|
|
29
32
|
this.assertValidSampleRate(sampleRate)
|
|
30
33
|
this.assertValidChannelFormat(channelFormat)
|
|
31
34
|
this.assertValidChunkSize(chunkSize)
|
|
@@ -36,24 +39,38 @@ export default class LslOutletImpl implements LslOutlet {
|
|
|
36
39
|
|
|
37
40
|
this.streamInfo = this.lsl.createStreamInfo({
|
|
38
41
|
...streamInfoOptions,
|
|
39
|
-
channelCount
|
|
40
|
-
channelFormat:
|
|
42
|
+
channelCount,
|
|
43
|
+
channelFormat: this.lookupChannelFormat(channelFormat),
|
|
41
44
|
})
|
|
42
45
|
|
|
43
|
-
this.lsl.appendChannelsToStreamInfo(
|
|
44
|
-
this.streamInfo,
|
|
45
|
-
|
|
46
|
+
this.lsl.appendChannelsToStreamInfo({
|
|
47
|
+
info: this.streamInfo,
|
|
48
|
+
channels: channelNames.map((label: string) => ({
|
|
46
49
|
label,
|
|
47
50
|
unit: this.outletOptions.unit,
|
|
48
51
|
type: this.outletOptions.type,
|
|
49
|
-
}))
|
|
50
|
-
)
|
|
52
|
+
})),
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
this.outlet = this.lsl.createOutlet({
|
|
56
|
+
info: this.streamInfo,
|
|
57
|
+
chunkSize: this.outletOptions.chunkSize,
|
|
58
|
+
maxBuffered: this.outletOptions.maxBuffered,
|
|
59
|
+
})
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
public static Outlet(options: LslOutletOptions) {
|
|
54
63
|
return new (this.Class ?? this)(options)
|
|
55
64
|
}
|
|
56
65
|
|
|
66
|
+
public pushSample(sample: LslSample) {
|
|
67
|
+
this.lsl.pushSample({ outlet: this.outlet, sample })
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private lookupChannelFormat(channelFormat: ChannelFormat): number {
|
|
71
|
+
return CHANNEL_FORMATS.indexOf(channelFormat)
|
|
72
|
+
}
|
|
73
|
+
|
|
57
74
|
private assertValidMaxBufferred(maxBuffered: number) {
|
|
58
75
|
if (!this.isPositiveIntegerOrZero(maxBuffered)) {
|
|
59
76
|
throw new SchemaError({
|
|
@@ -100,8 +117,8 @@ export default class LslOutletImpl implements LslOutlet {
|
|
|
100
117
|
if (!this.isPositiveInteger(channelCount)) {
|
|
101
118
|
throw new SchemaError({
|
|
102
119
|
code: 'INVALID_PARAMETERS',
|
|
103
|
-
parameters: ['
|
|
104
|
-
friendlyMessage: '
|
|
120
|
+
parameters: ['channelNames'],
|
|
121
|
+
friendlyMessage: 'channelNames must have 1 or more labels.',
|
|
105
122
|
})
|
|
106
123
|
}
|
|
107
124
|
}
|
|
@@ -121,17 +138,6 @@ export default class LslOutletImpl implements LslOutlet {
|
|
|
121
138
|
private get lsl() {
|
|
122
139
|
return LiblslImpl.getInstance()
|
|
123
140
|
}
|
|
124
|
-
|
|
125
|
-
public pushSample(sample: LslSample) {
|
|
126
|
-
this.lsl.pushSample(
|
|
127
|
-
this.lsl.createOutlet({
|
|
128
|
-
info: this.streamInfo,
|
|
129
|
-
chunkSize: this.outletOptions.chunkSize,
|
|
130
|
-
maxBuffered: this.outletOptions.maxBuffered,
|
|
131
|
-
}),
|
|
132
|
-
sample
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
const CHANNEL_FORMATS = [
|
|
@@ -146,10 +152,15 @@ const CHANNEL_FORMATS = [
|
|
|
146
152
|
] as const
|
|
147
153
|
|
|
148
154
|
export type ChannelFormat = (typeof CHANNEL_FORMATS)[number]
|
|
155
|
+
|
|
156
|
+
export interface LslOutlet {
|
|
157
|
+
pushSample(sample: LslSample): void
|
|
158
|
+
}
|
|
159
|
+
|
|
149
160
|
export interface LslOutletOptions {
|
|
150
161
|
name: string
|
|
151
162
|
type: string
|
|
152
|
-
|
|
163
|
+
channelNames: string[]
|
|
153
164
|
sampleRate: number
|
|
154
165
|
channelFormat: ChannelFormat
|
|
155
166
|
sourceId: string
|
|
@@ -158,7 +169,3 @@ export interface LslOutletOptions {
|
|
|
158
169
|
chunkSize: number
|
|
159
170
|
maxBuffered: number
|
|
160
171
|
}
|
|
161
|
-
|
|
162
|
-
export interface LslOutlet {
|
|
163
|
-
pushSample(sample: LslSample): void
|
|
164
|
-
}
|
|
@@ -9,10 +9,11 @@ import LiblslImpl, {
|
|
|
9
9
|
CreateOutletOptions,
|
|
10
10
|
CreateStreamInfoOptions,
|
|
11
11
|
Liblsl,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
LslChannel,
|
|
12
|
+
BoundOutlet,
|
|
13
|
+
BoundStreamInfo,
|
|
15
14
|
LslSample,
|
|
15
|
+
AppendChannelsToStreamInfoOptions,
|
|
16
|
+
PushSampleOptions,
|
|
16
17
|
} from '../../Liblsl'
|
|
17
18
|
import LslOutlet, { ChannelFormat, LslOutletOptions } from '../../LslOutlet'
|
|
18
19
|
|
|
@@ -28,7 +29,7 @@ export const CHANNEL_FORMATS = [
|
|
|
28
29
|
] as const
|
|
29
30
|
|
|
30
31
|
export default class LslOutletTest extends AbstractSpruceTest {
|
|
31
|
-
private static
|
|
32
|
+
private static spyLiblsl: SpyLiblsl
|
|
32
33
|
private static randomOutletOptions: LslOutletOptions
|
|
33
34
|
private static channelIdx: number
|
|
34
35
|
|
|
@@ -39,7 +40,7 @@ export default class LslOutletTest extends AbstractSpruceTest {
|
|
|
39
40
|
this.randomOutletOptions = {
|
|
40
41
|
name: generateId(),
|
|
41
42
|
type: generateId(),
|
|
42
|
-
|
|
43
|
+
channelNames: new Array(randomInt(1, 10)).fill(generateId()),
|
|
43
44
|
sampleRate: Math.random() * 10,
|
|
44
45
|
channelFormat: CHANNEL_FORMATS[this.channelIdx],
|
|
45
46
|
sourceId: generateId(),
|
|
@@ -49,19 +50,19 @@ export default class LslOutletTest extends AbstractSpruceTest {
|
|
|
49
50
|
maxBuffered: randomInt(0, 10),
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
this.
|
|
53
|
-
LiblslImpl.setInstance(this.
|
|
53
|
+
this.spyLiblsl = new SpyLiblsl()
|
|
54
|
+
LiblslImpl.setInstance(this.spyLiblsl)
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
@test()
|
|
57
|
-
protected static async
|
|
58
|
+
protected static async throwsWhenMissingRequiredParams() {
|
|
58
59
|
//@ts-ignore
|
|
59
60
|
const err = assert.doesThrow(() => new LslOutlet())
|
|
60
61
|
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
61
62
|
parameters: [
|
|
62
63
|
'name',
|
|
63
64
|
'type',
|
|
64
|
-
'
|
|
65
|
+
'channelNames',
|
|
65
66
|
'sampleRate',
|
|
66
67
|
'channelFormat',
|
|
67
68
|
'sourceId',
|
|
@@ -74,13 +75,8 @@ export default class LslOutletTest extends AbstractSpruceTest {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
@test()
|
|
77
|
-
protected static async
|
|
78
|
-
this.
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
@test()
|
|
82
|
-
protected static async throwsWithInvalidChannelCount() {
|
|
83
|
-
this.assertThrowsInvalidChannelLabels(0)
|
|
78
|
+
protected static async throwsWithInvalidChannelNames() {
|
|
79
|
+
this.assertThrowsInvalidChannelNames(0)
|
|
84
80
|
}
|
|
85
81
|
|
|
86
82
|
@test()
|
|
@@ -99,15 +95,7 @@ export default class LslOutletTest extends AbstractSpruceTest {
|
|
|
99
95
|
}
|
|
100
96
|
|
|
101
97
|
@test()
|
|
102
|
-
protected static async
|
|
103
|
-
const valid = CHANNEL_FORMATS
|
|
104
|
-
for (const format of valid) {
|
|
105
|
-
this.Outlet({ channelFormat: format as ChannelFormat })
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
@test()
|
|
110
|
-
protected static async throwWithInvalidChunkSize() {
|
|
98
|
+
protected static async throwsWithInvalidChunkSize() {
|
|
111
99
|
this.Outlet({ chunkSize: 0 })
|
|
112
100
|
this.assertThrowsInvalidChunkSize(-1)
|
|
113
101
|
this.assertThrowsInvalidChunkSize(-1.5)
|
|
@@ -122,56 +110,67 @@ export default class LslOutletTest extends AbstractSpruceTest {
|
|
|
122
110
|
this.assertThrowsInvalidMaxBuffered(1.5)
|
|
123
111
|
}
|
|
124
112
|
|
|
125
|
-
@test(
|
|
126
|
-
|
|
127
|
-
|
|
113
|
+
@test()
|
|
114
|
+
protected static async supportsAllKnownChannelFormats() {
|
|
115
|
+
const valid = CHANNEL_FORMATS
|
|
116
|
+
for (const format of valid) {
|
|
117
|
+
this.Outlet({ channelFormat: format as ChannelFormat })
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@test('pushing [1, 2] sample sends to LSL', [1, 2])
|
|
122
|
+
@test('pushing [1] sample sends to LSL', [1])
|
|
123
|
+
protected static async canPushSampleToLsl(sample: LslSample) {
|
|
128
124
|
this.pushSample(sample)
|
|
129
|
-
assert.isEqual(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
125
|
+
assert.isEqual(
|
|
126
|
+
this.spyLiblsl.lastPushSampleOptions?.outlet,
|
|
127
|
+
this.spyLiblsl.outlet
|
|
128
|
+
)
|
|
129
|
+
assert.isEqualDeep(this.spyLiblsl.lastPushSampleOptions?.sample, sample)
|
|
130
|
+
assert.isEqualDeep(this.spyLiblsl.lastCreateOutletOptions, {
|
|
131
|
+
info: this.spyLiblsl.streamInfo,
|
|
133
132
|
chunkSize: this.randomOutletOptions.chunkSize,
|
|
134
133
|
maxBuffered: this.randomOutletOptions.maxBuffered,
|
|
135
134
|
})
|
|
136
135
|
}
|
|
137
136
|
|
|
138
137
|
@test()
|
|
139
|
-
protected static async
|
|
138
|
+
protected static async constructionCreatesStreamInfo() {
|
|
140
139
|
this.Outlet()
|
|
141
140
|
|
|
142
141
|
const { ...options } = this.randomOutletOptions as any
|
|
143
142
|
|
|
144
|
-
options.channelCount = options.
|
|
143
|
+
options.channelCount = options.channelNames.length
|
|
145
144
|
|
|
146
145
|
delete options.manufacturer
|
|
147
146
|
delete options.unit
|
|
148
147
|
delete options.chunkSize
|
|
149
148
|
delete options.maxBuffered
|
|
150
|
-
delete options.
|
|
149
|
+
delete options.channelNames
|
|
151
150
|
|
|
152
|
-
assert.isEqualDeep(this.
|
|
151
|
+
assert.isEqualDeep(this.spyLiblsl.lastCreateStreamInfoOptions, {
|
|
153
152
|
...options,
|
|
154
153
|
channelFormat: this.channelIdx,
|
|
155
154
|
})
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
@test()
|
|
159
|
-
protected static async
|
|
158
|
+
protected static async canOverrideClassInstantiatedInFactory() {
|
|
160
159
|
LslOutlet.Class = CheckingOutlet
|
|
161
160
|
const instance = this.Outlet()
|
|
162
161
|
assert.isInstanceOf(instance, CheckingOutlet)
|
|
163
162
|
}
|
|
164
163
|
|
|
165
|
-
@test('can add one label', [generateId()])
|
|
166
|
-
@test('can add two labels', [generateId(), generateId()])
|
|
164
|
+
@test('can add one label to channels', [generateId()])
|
|
165
|
+
@test('can add two labels to channels', [generateId(), generateId()])
|
|
167
166
|
protected static async appendsChannelsBasedOnCount(labels: string[]) {
|
|
168
167
|
const type = generateId()
|
|
169
168
|
const unit = generateId()
|
|
170
169
|
|
|
171
|
-
this.Outlet({
|
|
170
|
+
this.Outlet({ channelNames: labels, type, unit })
|
|
172
171
|
|
|
173
|
-
assert.isEqualDeep(this.
|
|
174
|
-
info: this.
|
|
172
|
+
assert.isEqualDeep(this.spyLiblsl.lastAppendChannelsToStreamInfoOptions, {
|
|
173
|
+
info: this.spyLiblsl.streamInfo,
|
|
175
174
|
channels: labels.map((label) => ({
|
|
176
175
|
label,
|
|
177
176
|
type,
|
|
@@ -180,6 +179,16 @@ export default class LslOutletTest extends AbstractSpruceTest {
|
|
|
180
179
|
})
|
|
181
180
|
}
|
|
182
181
|
|
|
182
|
+
@test()
|
|
183
|
+
protected static async pushSampleShouldNotCreateMultipleOutlets() {
|
|
184
|
+
const outlet = this.Outlet()
|
|
185
|
+
outlet.pushSample([1])
|
|
186
|
+
outlet.pushSample([2])
|
|
187
|
+
outlet.pushSample([3])
|
|
188
|
+
|
|
189
|
+
assert.isEqual(this.spyLiblsl.createStreamInfoHitCount, 1)
|
|
190
|
+
}
|
|
191
|
+
|
|
183
192
|
private static pushSample(sample: LslSample) {
|
|
184
193
|
const outlet = this.Outlet()
|
|
185
194
|
outlet.pushSample(sample)
|
|
@@ -197,10 +206,10 @@ export default class LslOutletTest extends AbstractSpruceTest {
|
|
|
197
206
|
this.assertDoesThrowInvalidParameters({ sampleRate }, ['sampleRate'])
|
|
198
207
|
}
|
|
199
208
|
|
|
200
|
-
private static
|
|
209
|
+
private static assertThrowsInvalidChannelNames(count: number) {
|
|
201
210
|
this.assertDoesThrowInvalidParameters(
|
|
202
|
-
{
|
|
203
|
-
['
|
|
211
|
+
{ channelNames: new Array(count).fill(generateId()) },
|
|
212
|
+
['channelNames']
|
|
204
213
|
)
|
|
205
214
|
}
|
|
206
215
|
|
|
@@ -223,40 +232,34 @@ export default class LslOutletTest extends AbstractSpruceTest {
|
|
|
223
232
|
}
|
|
224
233
|
|
|
225
234
|
class SpyLiblsl implements Liblsl {
|
|
226
|
-
public
|
|
227
|
-
public
|
|
228
|
-
public
|
|
229
|
-
public
|
|
230
|
-
|
|
231
|
-
public
|
|
232
|
-
public
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
options: CreateStreamInfoOptions
|
|
239
|
-
): LslBindingsStreamInfo {
|
|
240
|
-
this.lastStreamInfoOptions = options
|
|
235
|
+
public lastCreateStreamInfoOptions?: CreateStreamInfoOptions
|
|
236
|
+
public lastAppendChannelsToStreamInfoOptions?: AppendChannelsToStreamInfoOptions
|
|
237
|
+
public lastCreateOutletOptions?: CreateOutletOptions
|
|
238
|
+
public lastPushSampleOptions?: PushSampleOptions
|
|
239
|
+
|
|
240
|
+
public outlet: BoundOutlet = {} as BoundOutlet
|
|
241
|
+
public streamInfo: BoundStreamInfo = {} as BoundStreamInfo
|
|
242
|
+
public createStreamInfoHitCount = 0
|
|
243
|
+
|
|
244
|
+
public createStreamInfo(options: CreateStreamInfoOptions): BoundStreamInfo {
|
|
245
|
+
this.createStreamInfoHitCount++
|
|
246
|
+
this.lastCreateStreamInfoOptions = options
|
|
241
247
|
return this.streamInfo
|
|
242
248
|
}
|
|
249
|
+
|
|
243
250
|
public appendChannelsToStreamInfo(
|
|
244
|
-
|
|
245
|
-
channels: LslChannel[]
|
|
251
|
+
options: AppendChannelsToStreamInfoOptions
|
|
246
252
|
): void {
|
|
247
|
-
this.
|
|
248
|
-
info,
|
|
249
|
-
channels,
|
|
250
|
-
}
|
|
253
|
+
this.lastAppendChannelsToStreamInfoOptions = options
|
|
251
254
|
}
|
|
252
255
|
|
|
253
|
-
public createOutlet(options: CreateOutletOptions):
|
|
254
|
-
this.
|
|
256
|
+
public createOutlet(options: CreateOutletOptions): BoundOutlet {
|
|
257
|
+
this.lastCreateOutletOptions = options
|
|
255
258
|
return this.outlet
|
|
256
259
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
this.
|
|
260
|
+
|
|
261
|
+
public pushSample(options: PushSampleOptions): void {
|
|
262
|
+
this.lastPushSampleOptions = options
|
|
260
263
|
}
|
|
261
264
|
}
|
|
262
265
|
|
|
@@ -8,16 +8,17 @@ import AbstractSpruceTest, {
|
|
|
8
8
|
import ArrayType from 'ref-array-napi'
|
|
9
9
|
import ref from 'ref-napi'
|
|
10
10
|
import LiblslImpl, {
|
|
11
|
-
CreateStreamInfoOptions,
|
|
12
|
-
LiblslBindings,
|
|
13
11
|
Liblsl,
|
|
14
|
-
|
|
12
|
+
LiblslBindings,
|
|
13
|
+
CreateStreamInfoOptions,
|
|
14
|
+
AppendChannelsToStreamInfoOptions,
|
|
15
15
|
CreateOutletOptions,
|
|
16
|
-
|
|
17
|
-
LslBindingsStreamInfo,
|
|
16
|
+
PushSampleOptions,
|
|
18
17
|
LslChannel,
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
BoundOutlet,
|
|
19
|
+
BoundStreamInfo,
|
|
20
|
+
BoundDesc,
|
|
21
|
+
BoundChild,
|
|
21
22
|
} from '../../Liblsl'
|
|
22
23
|
|
|
23
24
|
export default class LiblslTest extends AbstractSpruceTest {
|
|
@@ -25,10 +26,10 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
25
26
|
private static libraryPath?: string
|
|
26
27
|
private static libraryOptions?: Record<string, any>
|
|
27
28
|
private static fakeBindings: LiblslBindings
|
|
28
|
-
private static fakeStreamInfo:
|
|
29
|
-
private static fakeOutlet:
|
|
30
|
-
private static fakeDesc:
|
|
31
|
-
private static fakeChildNamedChannels:
|
|
29
|
+
private static fakeStreamInfo: BoundStreamInfo
|
|
30
|
+
private static fakeOutlet: BoundOutlet
|
|
31
|
+
private static fakeDesc: BoundDesc
|
|
32
|
+
private static fakeChildNamedChannels: BoundChild
|
|
32
33
|
private static createStreamInfoParams?: any[]
|
|
33
34
|
private static appendChildParams: any[] = []
|
|
34
35
|
private static createOutletParams?: any[]
|
|
@@ -36,8 +37,8 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
36
37
|
private static appendChildValueParams: any[]
|
|
37
38
|
private static localClock: number
|
|
38
39
|
private static shouldThrowWhenCreatingBindings: boolean
|
|
39
|
-
private static getDescriptionParams?: [
|
|
40
|
-
private static fakeChildNamedChannel:
|
|
40
|
+
private static getDescriptionParams?: [BoundStreamInfo]
|
|
41
|
+
private static fakeChildNamedChannel: BoundChild
|
|
41
42
|
private static appendChildHitCount: number
|
|
42
43
|
|
|
43
44
|
protected static async beforeEach(): Promise<void> {
|
|
@@ -79,7 +80,7 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
79
80
|
return 0
|
|
80
81
|
},
|
|
81
82
|
lsl_local_clock: () => this.localClock,
|
|
82
|
-
lsl_get_desc: (info:
|
|
83
|
+
lsl_get_desc: (info: BoundStreamInfo) => {
|
|
83
84
|
this.getDescriptionParams = [info]
|
|
84
85
|
return this.fakeDesc
|
|
85
86
|
},
|
|
@@ -108,12 +109,12 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
108
109
|
},
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
LiblslImpl.
|
|
112
|
+
LiblslImpl.resetInstance()
|
|
112
113
|
this.lsl = LiblslImpl.getInstance()
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
@test()
|
|
116
|
-
protected static async
|
|
117
|
+
protected static async throwsWithMissingEnv() {
|
|
117
118
|
delete process.env.LIBLSL_PATH
|
|
118
119
|
const err = assert.doesThrow(() => new LiblslImpl())
|
|
119
120
|
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
@@ -122,7 +123,7 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
@test()
|
|
125
|
-
protected static async
|
|
126
|
+
protected static async throwsWhenBindingsFailToLoad() {
|
|
126
127
|
this.shouldThrowWhenCreatingBindings = true
|
|
127
128
|
const err = assert.doesThrow(() => new LiblslImpl())
|
|
128
129
|
errorAssert.assertError(err, 'FAILED_TO_LOAD_LIBLSL', {
|
|
@@ -130,6 +131,49 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
130
131
|
})
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
@test()
|
|
135
|
+
protected static throwsWhenCreateStreamInfoIsMissingRequiredParams() {
|
|
136
|
+
//@ts-ignore
|
|
137
|
+
const err = assert.doesThrow(() => this.lsl.createStreamInfo())
|
|
138
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
139
|
+
parameters: [
|
|
140
|
+
'name',
|
|
141
|
+
'type',
|
|
142
|
+
'channelCount',
|
|
143
|
+
'sampleRate',
|
|
144
|
+
'channelFormat',
|
|
145
|
+
'sourceId',
|
|
146
|
+
],
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@test()
|
|
151
|
+
protected static async throwsWhenAppendChannelsIsMissingRequiredParams() {
|
|
152
|
+
//@ts-ignore
|
|
153
|
+
const err = assert.doesThrow(() => this.lsl.appendChannelsToStreamInfo({}))
|
|
154
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
155
|
+
parameters: ['info', 'channels'],
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@test()
|
|
160
|
+
protected static async throwsWhenCreateOutletIsMissingRequiredParams() {
|
|
161
|
+
//@ts-ignore
|
|
162
|
+
const err = assert.doesThrow(() => this.lsl.createOutlet({}))
|
|
163
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
164
|
+
parameters: ['info', 'chunkSize', 'maxBuffered'],
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@test()
|
|
169
|
+
protected static async throwsWhenPushSampleIsMissingRequiredParams() {
|
|
170
|
+
//@ts-ignore
|
|
171
|
+
const err = assert.doesThrow(() => this.lsl.pushSample())
|
|
172
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
173
|
+
parameters: ['outlet', 'sample'],
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
133
177
|
@test()
|
|
134
178
|
protected static async worksAsASingleton() {
|
|
135
179
|
const liblsl = LiblslImpl.getInstance()
|
|
@@ -172,23 +216,7 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
172
216
|
}
|
|
173
217
|
|
|
174
218
|
@test()
|
|
175
|
-
protected static
|
|
176
|
-
//@ts-ignore
|
|
177
|
-
const err = assert.doesThrow(() => this.lsl.createStreamInfo())
|
|
178
|
-
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
179
|
-
parameters: [
|
|
180
|
-
'name',
|
|
181
|
-
'type',
|
|
182
|
-
'channelCount',
|
|
183
|
-
'sampleRate',
|
|
184
|
-
'channelFormat',
|
|
185
|
-
'sourceId',
|
|
186
|
-
],
|
|
187
|
-
})
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
@test()
|
|
191
|
-
protected static async canGetStreamInfoWithRequiredParams() {
|
|
219
|
+
protected static async canCreateStreamInfoWithRequiredParams() {
|
|
192
220
|
const options = this.generateRandomCreateStreamInfoOptions()
|
|
193
221
|
const actual = this.lsl.createStreamInfo(options)
|
|
194
222
|
|
|
@@ -196,15 +224,6 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
196
224
|
assert.isEqualDeep(this.createStreamInfoParams, Object.values(options))
|
|
197
225
|
}
|
|
198
226
|
|
|
199
|
-
@test()
|
|
200
|
-
protected static async createOutletThrowsWhenMissingRequiredParams() {
|
|
201
|
-
//@ts-ignore
|
|
202
|
-
const err = assert.doesThrow(() => this.lsl.createOutlet({}))
|
|
203
|
-
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
204
|
-
parameters: ['info', 'chunkSize', 'maxBuffered'],
|
|
205
|
-
})
|
|
206
|
-
}
|
|
207
|
-
|
|
208
227
|
@test()
|
|
209
228
|
protected static async canCreateOutletWithRequiredParams() {
|
|
210
229
|
const info = this.createRandomStreamInfo()
|
|
@@ -219,37 +238,27 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
219
238
|
}
|
|
220
239
|
|
|
221
240
|
@test()
|
|
222
|
-
protected static async
|
|
223
|
-
//@ts-ignore
|
|
224
|
-
const err = assert.doesThrow(() => this.lsl.pushSample())
|
|
225
|
-
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
226
|
-
parameters: ['outlet', 'sample'],
|
|
227
|
-
})
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
@test()
|
|
231
|
-
protected static async pushSampleCallsBindings() {
|
|
241
|
+
protected static async canPushSampleWithRequiredParams() {
|
|
232
242
|
const expected = [1, 2, 3]
|
|
233
|
-
|
|
243
|
+
const options = {
|
|
244
|
+
outlet: this.fakeOutlet,
|
|
245
|
+
sample: expected,
|
|
246
|
+
}
|
|
247
|
+
this.lsl.pushSample(options)
|
|
234
248
|
assert.isEqual(this.pushSampleParams?.[0], this.fakeOutlet)
|
|
235
249
|
assert.isEqual(this.pushSampleParams?.[1], expected)
|
|
236
250
|
assert.isEqual(this.pushSampleParams?.[2], this.localClock)
|
|
237
251
|
}
|
|
238
252
|
|
|
239
|
-
@test()
|
|
240
|
-
protected static async appendChannelsThrowsWithMissingParams() {
|
|
241
|
-
//@ts-ignore
|
|
242
|
-
const err = assert.doesThrow(() => this.lsl.appendChannelsToStreamInfo())
|
|
243
|
-
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
244
|
-
parameters: ['info', 'channels'],
|
|
245
|
-
})
|
|
246
|
-
}
|
|
247
|
-
|
|
248
253
|
@test()
|
|
249
254
|
protected static async addingSingleChannelGetsDescription() {
|
|
250
255
|
const info = this.createRandomStreamInfo()
|
|
251
256
|
const channel: LslChannel = this.generateRandomChannelValues()
|
|
252
|
-
|
|
257
|
+
|
|
258
|
+
this.lsl.appendChannelsToStreamInfo({
|
|
259
|
+
info,
|
|
260
|
+
channels: [channel],
|
|
261
|
+
})
|
|
253
262
|
assert.isEqual(this.getDescriptionParams?.[0], info)
|
|
254
263
|
|
|
255
264
|
assert.isEqual(this.appendChildParams?.[0][0], this.fakeDesc)
|
|
@@ -280,7 +289,10 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
280
289
|
const channel1 = this.generateRandomChannelValues()
|
|
281
290
|
const channel2 = this.generateRandomChannelValues()
|
|
282
291
|
|
|
283
|
-
this.lsl.appendChannelsToStreamInfo(
|
|
292
|
+
this.lsl.appendChannelsToStreamInfo({
|
|
293
|
+
info,
|
|
294
|
+
channels: [channel1, channel2],
|
|
295
|
+
})
|
|
284
296
|
|
|
285
297
|
assert.isEqual(this.appendChildParams?.[2][0], this.fakeChildNamedChannels)
|
|
286
298
|
assert.isEqual(this.appendChildParams?.[2][1], 'channel')
|
|
@@ -290,6 +302,12 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
290
302
|
assert.isEqual(this.appendChildValueParams[5][2], channel2.type)
|
|
291
303
|
}
|
|
292
304
|
|
|
305
|
+
private static createRandomStreamInfo() {
|
|
306
|
+
return this.lsl.createStreamInfo(
|
|
307
|
+
this.generateRandomCreateStreamInfoOptions()
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
|
|
293
311
|
private static generateRandomChannelValues(): LslChannel {
|
|
294
312
|
return {
|
|
295
313
|
label: generateId(),
|
|
@@ -298,38 +316,32 @@ export default class LiblslTest extends AbstractSpruceTest {
|
|
|
298
316
|
}
|
|
299
317
|
}
|
|
300
318
|
|
|
301
|
-
private static createRandomStreamInfo() {
|
|
302
|
-
return this.lsl.createStreamInfo(
|
|
303
|
-
this.generateRandomCreateStreamInfoOptions()
|
|
304
|
-
)
|
|
305
|
-
}
|
|
306
|
-
|
|
307
319
|
private static generateRandomCreateStreamInfoOptions() {
|
|
308
320
|
return {
|
|
309
321
|
name: generateId(),
|
|
310
322
|
type: generateId(),
|
|
311
|
-
channelCount: randomInt(10),
|
|
312
|
-
sampleRate: randomInt(
|
|
313
|
-
channelFormat: randomInt(
|
|
323
|
+
channelCount: randomInt(1, 10),
|
|
324
|
+
sampleRate: randomInt(100),
|
|
325
|
+
channelFormat: randomInt(7),
|
|
314
326
|
sourceId: generateId(),
|
|
315
327
|
}
|
|
316
328
|
}
|
|
317
329
|
}
|
|
318
330
|
|
|
319
331
|
class FakeLiblsl implements Liblsl {
|
|
332
|
+
public createStreamInfo(_options: CreateStreamInfoOptions): BoundStreamInfo {
|
|
333
|
+
return {} as BoundStreamInfo
|
|
334
|
+
}
|
|
335
|
+
|
|
320
336
|
public appendChannelsToStreamInfo(
|
|
321
|
-
|
|
322
|
-
_channels: LslChannel[]
|
|
337
|
+
_options: AppendChannelsToStreamInfoOptions
|
|
323
338
|
): void {}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
public createStreamInfo(
|
|
328
|
-
_options: CreateStreamInfoOptions
|
|
329
|
-
): LslBindingsStreamInfo {
|
|
330
|
-
return {} as LslBindingsStreamInfo
|
|
339
|
+
|
|
340
|
+
public createOutlet(_options: CreateOutletOptions): BoundOutlet {
|
|
341
|
+
return {} as BoundOutlet
|
|
331
342
|
}
|
|
332
|
-
|
|
343
|
+
|
|
344
|
+
public pushSample(_options: PushSampleOptions): void {}
|
|
333
345
|
}
|
|
334
346
|
|
|
335
347
|
const streamInfo = ref.refType(ref.types.void)
|