@neurodevs/node-lsl 0.0.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/.eslintignore +3 -0
- package/.eslintrc.js +3 -0
- package/.nvmrc +1 -0
- package/.vscode/launch.json +58 -0
- package/.vscode/settings.json +70 -0
- package/.vscode/tasks.json +112 -0
- package/LICENSE +21 -0
- package/README.md +2 -0
- package/build/.spruce/errors/errors.types.d.ts +21 -0
- package/build/.spruce/errors/errors.types.js +5 -0
- package/build/.spruce/errors/errors.types.js.map +1 -0
- package/build/.spruce/errors/nodeLsl/failedToLoadLiblsl.schema.d.ts +3 -0
- package/build/.spruce/errors/nodeLsl/failedToLoadLiblsl.schema.js +19 -0
- package/build/.spruce/errors/nodeLsl/failedToLoadLiblsl.schema.js.map +1 -0
- package/build/.spruce/errors/options.types.d.ts +7 -0
- package/build/.spruce/errors/options.types.js +3 -0
- package/build/.spruce/errors/options.types.js.map +1 -0
- package/build/.spruce/schemas/fields/fieldClassMap.d.ts +2 -0
- package/build/.spruce/schemas/fields/fieldClassMap.js +5 -0
- package/build/.spruce/schemas/fields/fieldClassMap.js.map +1 -0
- package/build/.spruce/schemas/fields/fields.types.d.ts +1 -0
- package/build/.spruce/schemas/fields/fields.types.js +3 -0
- package/build/.spruce/schemas/fields/fields.types.js.map +1 -0
- package/build/.spruce/settings.json +13 -0
- package/build/Liblsl.d.ts +47 -0
- package/build/Liblsl.js +81 -0
- package/build/Liblsl.js.map +1 -0
- package/build/LslOutlet.d.ts +30 -0
- package/build/LslOutlet.js +122 -0
- package/build/LslOutlet.js.map +1 -0
- package/build/__tests__/behavioral/LslOutlet.test.d.ts +26 -0
- package/build/__tests__/behavioral/LslOutlet.test.js +232 -0
- package/build/__tests__/behavioral/LslOutlet.test.js.map +1 -0
- package/build/__tests__/implementation/Liblsl.test.d.ts +28 -0
- package/build/__tests__/implementation/Liblsl.test.js +236 -0
- package/build/__tests__/implementation/Liblsl.test.js.map +1 -0
- package/build/errors/SpruceError.d.ts +6 -0
- package/build/errors/SpruceError.js +26 -0
- package/build/errors/SpruceError.js.map +1 -0
- package/build/errors/failedToLoadLiblsl.builder.d.ts +11 -0
- package/build/errors/failedToLoadLiblsl.builder.js +14 -0
- package/build/errors/failedToLoadLiblsl.builder.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +27 -0
- package/build/index.js.map +1 -0
- package/package.json +80 -0
- package/src/.spruce/errors/errors.types.ts +40 -0
- package/src/.spruce/errors/nodeLsl/failedToLoadLiblsl.schema.ts +22 -0
- package/src/.spruce/errors/options.types.ts +10 -0
- package/src/.spruce/schemas/fields/fieldClassMap.ts +6 -0
- package/src/.spruce/schemas/fields/fields.types.ts +1 -0
- package/src/.spruce/settings.json +13 -0
- package/src/Liblsl.ts +151 -0
- package/src/LslOutlet.ts +143 -0
- package/src/__tests__/behavioral/LslOutlet.test.ts +217 -0
- package/src/__tests__/implementation/Liblsl.test.ts +231 -0
- package/src/errors/SpruceError.ts +23 -0
- package/src/errors/failedToLoadLiblsl.builder.ts +12 -0
- package/src/index.ts +5 -0
- package/tsconfig.json +40 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { randomInt } from 'crypto'
|
|
2
|
+
import AbstractSpruceTest, {
|
|
3
|
+
test,
|
|
4
|
+
assert,
|
|
5
|
+
errorAssert,
|
|
6
|
+
generateId,
|
|
7
|
+
} from '@sprucelabs/test-utils'
|
|
8
|
+
import LiblslImpl, {
|
|
9
|
+
CreateOutletOptions,
|
|
10
|
+
CreateStreamInfoOptions,
|
|
11
|
+
Liblsl,
|
|
12
|
+
LslBindingsOutlet,
|
|
13
|
+
LslBindingsStreamInfo,
|
|
14
|
+
LslSample,
|
|
15
|
+
} from '../../Liblsl'
|
|
16
|
+
import LslOutlet, { ChannelFormat, LslOutletOptions } from '../../LslOutlet'
|
|
17
|
+
|
|
18
|
+
export const CHANNEL_FORMATS = [
|
|
19
|
+
'undefined',
|
|
20
|
+
'float32',
|
|
21
|
+
'double64',
|
|
22
|
+
'string',
|
|
23
|
+
'int32',
|
|
24
|
+
'int16',
|
|
25
|
+
'int8',
|
|
26
|
+
'int64',
|
|
27
|
+
] as const
|
|
28
|
+
|
|
29
|
+
export default class LslOutletTest extends AbstractSpruceTest {
|
|
30
|
+
private static spyLsl: SpyLiblsl
|
|
31
|
+
private static randomOutletOptions: LslOutletOptions
|
|
32
|
+
private static channelIdx: number
|
|
33
|
+
|
|
34
|
+
protected static async beforeEach() {
|
|
35
|
+
await super.beforeEach()
|
|
36
|
+
this.channelIdx = randomInt(7)
|
|
37
|
+
this.randomOutletOptions = {
|
|
38
|
+
name: generateId(),
|
|
39
|
+
type: generateId(),
|
|
40
|
+
channelCount: randomInt(1, 10),
|
|
41
|
+
sampleRate: Math.random() * 10,
|
|
42
|
+
channelFormat: CHANNEL_FORMATS[this.channelIdx],
|
|
43
|
+
sourceId: generateId(),
|
|
44
|
+
manufacturer: generateId(),
|
|
45
|
+
unit: generateId(),
|
|
46
|
+
chunkSize: randomInt(0, 10),
|
|
47
|
+
maxBuffered: randomInt(0, 10),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.spyLsl = new SpyLiblsl()
|
|
51
|
+
LiblslImpl.setInstance(this.spyLsl)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@test()
|
|
55
|
+
protected static async throwsWhenMissingRequiredParameters() {
|
|
56
|
+
//@ts-ignore
|
|
57
|
+
const err = assert.doesThrow(() => new LslOutlet())
|
|
58
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
59
|
+
parameters: [
|
|
60
|
+
'name',
|
|
61
|
+
'type',
|
|
62
|
+
'channelCount',
|
|
63
|
+
'sampleRate',
|
|
64
|
+
'channelFormat',
|
|
65
|
+
'sourceId',
|
|
66
|
+
'manufacturer',
|
|
67
|
+
'unit',
|
|
68
|
+
'chunkSize',
|
|
69
|
+
'maxBuffered',
|
|
70
|
+
],
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@test()
|
|
75
|
+
protected static async canCreateWithRequiredParams() {
|
|
76
|
+
this.Outlet()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@test()
|
|
80
|
+
protected static async throwsWithInvalidChannelCount() {
|
|
81
|
+
this.assertThrowsInvalidChannelCount(0)
|
|
82
|
+
this.assertThrowsInvalidChannelCount(-1)
|
|
83
|
+
this.assertThrowsInvalidChannelCount(1.5)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@test()
|
|
87
|
+
protected static async throwsWithInvalidSampleRate() {
|
|
88
|
+
this.assertThrowsInvalidSampleRate(0)
|
|
89
|
+
this.assertThrowsInvalidSampleRate(-1)
|
|
90
|
+
this.assertThrowsInvalidSampleRate(-1.5)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@test()
|
|
94
|
+
protected static async throwsWithInvalidChannelFormat() {
|
|
95
|
+
//@ts-ignore
|
|
96
|
+
this.assertDoesThrowInvalidParameters({ channelFormat: generateId() }, [
|
|
97
|
+
'channelFormat',
|
|
98
|
+
])
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@test()
|
|
102
|
+
protected static async supportsAllKnownChannelFormats() {
|
|
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() {
|
|
111
|
+
this.Outlet({ chunkSize: 0 })
|
|
112
|
+
this.assertThrowsInvalidChunkSize(-1)
|
|
113
|
+
this.assertThrowsInvalidChunkSize(-1.5)
|
|
114
|
+
this.assertThrowsInvalidChunkSize(1.5)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@test()
|
|
118
|
+
protected static async throwsWithInvalidMaxBuffered() {
|
|
119
|
+
this.Outlet({ maxBuffered: 0 })
|
|
120
|
+
this.assertThrowsInvalidMaxBuffered(-1)
|
|
121
|
+
this.assertThrowsInvalidMaxBuffered(-1.5)
|
|
122
|
+
this.assertThrowsInvalidMaxBuffered(1.5)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@test('pushing sample sends to lsl 1', [1])
|
|
126
|
+
@test('pushing sample sends to lsl 2', [1, 2])
|
|
127
|
+
protected static async pushingSampleSendsToLsl(sample: LslSample) {
|
|
128
|
+
this.pushSample(sample)
|
|
129
|
+
assert.isEqual(this.spyLsl.lastPushedOutlet, this.spyLsl.outlet)
|
|
130
|
+
assert.isEqualDeep(this.spyLsl.lastPushedSample, sample)
|
|
131
|
+
assert.isEqualDeep(this.spyLsl.lastOutletOptions, {
|
|
132
|
+
info: this.spyLsl.streamInfo,
|
|
133
|
+
chunkSize: this.randomOutletOptions.chunkSize,
|
|
134
|
+
maxBuffered: this.randomOutletOptions.maxBuffered,
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@test()
|
|
139
|
+
protected static async pushingSamplePassesCorrectOptionsToCreateStreamInfo() {
|
|
140
|
+
this.pushSample([1])
|
|
141
|
+
const { ...options } = this.randomOutletOptions as any
|
|
142
|
+
|
|
143
|
+
delete options.manufacturer
|
|
144
|
+
delete options.unit
|
|
145
|
+
delete options.chunkSize
|
|
146
|
+
delete options.maxBuffered
|
|
147
|
+
|
|
148
|
+
assert.isEqualDeep(this.spyLsl.lastStreamInfoOptions, {
|
|
149
|
+
...options,
|
|
150
|
+
channelFormat: this.channelIdx,
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private static pushSample(sample: LslSample) {
|
|
155
|
+
const outlet = this.Outlet()
|
|
156
|
+
outlet.pushSample(sample)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private static assertThrowsInvalidMaxBuffered(maxBuffered: number) {
|
|
160
|
+
this.assertDoesThrowInvalidParameters({ maxBuffered }, ['maxBuffered'])
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private static assertThrowsInvalidChunkSize(chunkSize: number) {
|
|
164
|
+
this.assertDoesThrowInvalidParameters({ chunkSize }, ['chunkSize'])
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private static assertThrowsInvalidSampleRate(sampleRate: number) {
|
|
168
|
+
this.assertDoesThrowInvalidParameters({ sampleRate }, ['sampleRate'])
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private static assertThrowsInvalidChannelCount(count: number) {
|
|
172
|
+
this.assertDoesThrowInvalidParameters({ channelCount: count }, [
|
|
173
|
+
'channelCount',
|
|
174
|
+
])
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private static assertDoesThrowInvalidParameters(
|
|
178
|
+
options: Partial<LslOutletOptions>,
|
|
179
|
+
parameters: string[]
|
|
180
|
+
) {
|
|
181
|
+
const err = assert.doesThrow(() => this.Outlet(options))
|
|
182
|
+
errorAssert.assertError(err, 'INVALID_PARAMETERS', {
|
|
183
|
+
parameters,
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private static Outlet(options?: Partial<LslOutletOptions>) {
|
|
188
|
+
return new LslOutlet({
|
|
189
|
+
...this.randomOutletOptions,
|
|
190
|
+
...options,
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
class SpyLiblsl implements Liblsl {
|
|
196
|
+
public lastPushedOutlet?: LslBindingsOutlet
|
|
197
|
+
public lastPushedSample?: LslSample
|
|
198
|
+
public lastOutletOptions?: CreateOutletOptions
|
|
199
|
+
public lastStreamInfoOptions?: CreateStreamInfoOptions
|
|
200
|
+
public outlet: LslBindingsOutlet = {} as LslBindingsOutlet
|
|
201
|
+
public streamInfo: LslBindingsStreamInfo = {} as LslBindingsStreamInfo
|
|
202
|
+
|
|
203
|
+
public createStreamInfo(
|
|
204
|
+
options: CreateStreamInfoOptions
|
|
205
|
+
): LslBindingsStreamInfo {
|
|
206
|
+
this.lastStreamInfoOptions = options
|
|
207
|
+
return this.streamInfo
|
|
208
|
+
}
|
|
209
|
+
public createOutlet(options: CreateOutletOptions): LslBindingsOutlet {
|
|
210
|
+
this.lastOutletOptions = options
|
|
211
|
+
return this.outlet
|
|
212
|
+
}
|
|
213
|
+
public pushSample(outlet: LslBindingsOutlet, sample: LslSample): void {
|
|
214
|
+
this.lastPushedOutlet = outlet
|
|
215
|
+
this.lastPushedSample = sample
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { randomInt } from 'crypto'
|
|
2
|
+
import AbstractSpruceTest, {
|
|
3
|
+
test,
|
|
4
|
+
assert,
|
|
5
|
+
errorAssert,
|
|
6
|
+
generateId,
|
|
7
|
+
} from '@sprucelabs/test-utils'
|
|
8
|
+
import ArrayType from 'ref-array-napi'
|
|
9
|
+
import ref from 'ref-napi'
|
|
10
|
+
import LiblslImpl, {
|
|
11
|
+
CreateStreamInfoOptions,
|
|
12
|
+
LiblslBindings,
|
|
13
|
+
Liblsl,
|
|
14
|
+
LslSample,
|
|
15
|
+
StreamInfo,
|
|
16
|
+
CreateOutletOptions,
|
|
17
|
+
LslBindingsOutlet,
|
|
18
|
+
LslBindingsStreamInfo,
|
|
19
|
+
} from '../../Liblsl'
|
|
20
|
+
|
|
21
|
+
export default class LiblslTest extends AbstractSpruceTest {
|
|
22
|
+
private static lsl: Liblsl
|
|
23
|
+
private static libraryPath?: string
|
|
24
|
+
private static libraryOptions?: Record<string, any>
|
|
25
|
+
private static fakeBindings: LiblslBindings
|
|
26
|
+
private static fakeStreamInfo: StreamInfo
|
|
27
|
+
private static fakeOutlet: LslBindingsOutlet
|
|
28
|
+
private static createStreamInfoParams?: any[]
|
|
29
|
+
private static createOutletParams?: any[]
|
|
30
|
+
private static pushSampleParams?: any[]
|
|
31
|
+
private static localClock: number
|
|
32
|
+
private static shouldThrowWhenCreatingBindings: boolean
|
|
33
|
+
|
|
34
|
+
protected static async beforeEach(): Promise<void> {
|
|
35
|
+
await super.beforeEach()
|
|
36
|
+
|
|
37
|
+
delete this.libraryPath
|
|
38
|
+
delete this.libraryOptions
|
|
39
|
+
delete this.createStreamInfoParams
|
|
40
|
+
delete this.createOutletParams
|
|
41
|
+
delete this.pushSampleParams
|
|
42
|
+
|
|
43
|
+
process.env.LIBLSL_PATH = generateId()
|
|
44
|
+
|
|
45
|
+
this.fakeStreamInfo = {}
|
|
46
|
+
this.fakeOutlet = {}
|
|
47
|
+
this.localClock = new Date().getTime()
|
|
48
|
+
this.shouldThrowWhenCreatingBindings = false
|
|
49
|
+
|
|
50
|
+
this.fakeBindings = {
|
|
51
|
+
lsl_create_streaminfo: (...params: any[]) => {
|
|
52
|
+
this.createStreamInfoParams = params
|
|
53
|
+
return this.fakeStreamInfo
|
|
54
|
+
},
|
|
55
|
+
lsl_create_outlet: (...params: any[]) => {
|
|
56
|
+
this.createOutletParams = params
|
|
57
|
+
return this.fakeOutlet
|
|
58
|
+
},
|
|
59
|
+
lsl_push_sample_ft: (...params: any[]) => {
|
|
60
|
+
this.pushSampleParams = params
|
|
61
|
+
return 0
|
|
62
|
+
},
|
|
63
|
+
lsl_local_clock: () => this.localClock,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
LiblslImpl.ffi = {
|
|
67
|
+
//@ts-ignore
|
|
68
|
+
Library: (path: string, options: Record<string, any>) => {
|
|
69
|
+
this.libraryPath = path
|
|
70
|
+
this.libraryOptions = options
|
|
71
|
+
if (this.shouldThrowWhenCreatingBindings) {
|
|
72
|
+
throw new Error('Failed to create bindings')
|
|
73
|
+
}
|
|
74
|
+
return this.fakeBindings
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
LiblslImpl.reset()
|
|
79
|
+
this.lsl = LiblslImpl.getInstance()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@test()
|
|
83
|
+
protected static async throwsIfNoEnvSet() {
|
|
84
|
+
delete process.env.LIBLSL_PATH
|
|
85
|
+
const err = assert.doesThrow(() => new LiblslImpl())
|
|
86
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
87
|
+
parameters: ['env.LIBLSL_PATH'],
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@test()
|
|
92
|
+
protected static async throwsHelpfulErrorWhenBindingsFailToLoad() {
|
|
93
|
+
this.shouldThrowWhenCreatingBindings = true
|
|
94
|
+
const err = assert.doesThrow(() => new LiblslImpl())
|
|
95
|
+
errorAssert.assertError(err, 'FAILED_TO_LOAD_LIBLSL', {
|
|
96
|
+
liblslPath: process.env.LIBLSL_PATH,
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@test()
|
|
101
|
+
protected static async worksAsASingleton() {
|
|
102
|
+
const liblsl = LiblslImpl.getInstance()
|
|
103
|
+
assert.isInstanceOf(liblsl, LiblslImpl)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@test()
|
|
107
|
+
protected static async singletonIsTheSame() {
|
|
108
|
+
assert.isEqual(LiblslImpl.getInstance(), LiblslImpl.getInstance())
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@test()
|
|
112
|
+
protected static canSetInstance() {
|
|
113
|
+
const fake = new FakeLiblsl()
|
|
114
|
+
LiblslImpl.setInstance(fake)
|
|
115
|
+
assert.isEqual(LiblslImpl.getInstance(), fake)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@test()
|
|
119
|
+
protected static async createsExpectedBindingsToLiblsl() {
|
|
120
|
+
process.env.LIBLSL_PATH = generateId()
|
|
121
|
+
new LiblslImpl()
|
|
122
|
+
assert.isEqual(this.libraryPath, process.env.LIBLSL_PATH)
|
|
123
|
+
const expected = {
|
|
124
|
+
lsl_create_streaminfo: [
|
|
125
|
+
streamInfo,
|
|
126
|
+
['string', 'string', 'int', 'double', 'int', 'string'],
|
|
127
|
+
],
|
|
128
|
+
lsl_create_outlet: [outletType, [streamInfo, 'int', 'int']],
|
|
129
|
+
lsl_local_clock: ['double', []],
|
|
130
|
+
lsl_push_sample_ft: ['void', [outletType, FloatArray, 'double']],
|
|
131
|
+
}
|
|
132
|
+
assert.isEqual(
|
|
133
|
+
JSON.stringify(this.libraryOptions),
|
|
134
|
+
JSON.stringify(expected)
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@test()
|
|
139
|
+
protected static createStreamInfoThrowsWithMissingRequiredParams() {
|
|
140
|
+
//@ts-ignore
|
|
141
|
+
const err = assert.doesThrow(() => this.lsl.createStreamInfo())
|
|
142
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
143
|
+
parameters: [
|
|
144
|
+
'name',
|
|
145
|
+
'type',
|
|
146
|
+
'channelCount',
|
|
147
|
+
'sampleRate',
|
|
148
|
+
'channelFormat',
|
|
149
|
+
'sourceId',
|
|
150
|
+
],
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@test()
|
|
155
|
+
protected static async canGetStreamInfoWithRequiredParams() {
|
|
156
|
+
const options = this.generateRandomCreateStreamInfoOptions()
|
|
157
|
+
const actual = this.lsl.createStreamInfo(options)
|
|
158
|
+
|
|
159
|
+
assert.isEqual(actual, this.fakeStreamInfo)
|
|
160
|
+
assert.isEqualDeep(this.createStreamInfoParams, Object.values(options))
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@test()
|
|
164
|
+
protected static async createOutletThrowsWhenMissingRequiredParams() {
|
|
165
|
+
//@ts-ignore
|
|
166
|
+
const err = assert.doesThrow(() => this.lsl.createOutlet({}))
|
|
167
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
168
|
+
parameters: ['info', 'chunkSize', 'maxBuffered'],
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@test()
|
|
173
|
+
protected static async canCreateOutletWithRequiredParams() {
|
|
174
|
+
const info = this.lsl.createStreamInfo(
|
|
175
|
+
this.generateRandomCreateStreamInfoOptions()
|
|
176
|
+
)
|
|
177
|
+
const options = {
|
|
178
|
+
info,
|
|
179
|
+
chunkSize: randomInt(10),
|
|
180
|
+
maxBuffered: randomInt(10),
|
|
181
|
+
}
|
|
182
|
+
const actual = this.lsl.createOutlet(options)
|
|
183
|
+
assert.isEqualDeep(this.createOutletParams, Object.values(options))
|
|
184
|
+
assert.isEqual(actual, this.fakeOutlet)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@test()
|
|
188
|
+
protected static async pushSampleThrowsWhenMissingRequiredParams() {
|
|
189
|
+
//@ts-ignore
|
|
190
|
+
const err = assert.doesThrow(() => this.lsl.pushSample())
|
|
191
|
+
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
|
|
192
|
+
parameters: ['outlet', 'sample'],
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@test()
|
|
197
|
+
protected static async pushSampleCallsBindings() {
|
|
198
|
+
const expected = [1, 2, 3]
|
|
199
|
+
this.lsl.pushSample(this.fakeOutlet, expected)
|
|
200
|
+
assert.isEqual(this.pushSampleParams?.[0], this.fakeOutlet)
|
|
201
|
+
assert.isEqual(this.pushSampleParams?.[1], expected)
|
|
202
|
+
assert.isEqual(this.pushSampleParams?.[2], this.localClock)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private static generateRandomCreateStreamInfoOptions() {
|
|
206
|
+
return {
|
|
207
|
+
name: generateId(),
|
|
208
|
+
type: generateId(),
|
|
209
|
+
channelCount: randomInt(10),
|
|
210
|
+
sampleRate: randomInt(10),
|
|
211
|
+
channelFormat: randomInt(10),
|
|
212
|
+
sourceId: generateId(),
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
class FakeLiblsl implements Liblsl {
|
|
218
|
+
public createOutlet(_options: CreateOutletOptions): LslBindingsOutlet {
|
|
219
|
+
return {} as LslBindingsOutlet
|
|
220
|
+
}
|
|
221
|
+
public createStreamInfo(
|
|
222
|
+
_options: CreateStreamInfoOptions
|
|
223
|
+
): LslBindingsStreamInfo {
|
|
224
|
+
return {} as StreamInfo
|
|
225
|
+
}
|
|
226
|
+
public pushSample(_sample: LslSample): void {}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const streamInfo = ref.refType(ref.types.void)
|
|
230
|
+
const outletType = ref.refType(ref.types.void)
|
|
231
|
+
const FloatArray = ArrayType(ref.types.float)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import BaseSpruceError from '@sprucelabs/error'
|
|
2
|
+
import ErrorOptions from '#spruce/errors/options.types'
|
|
3
|
+
|
|
4
|
+
export default class SpruceError extends BaseSpruceError<ErrorOptions> {
|
|
5
|
+
/** an easy to understand version of the errors */
|
|
6
|
+
public friendlyMessage(): string {
|
|
7
|
+
const { options } = this
|
|
8
|
+
let message
|
|
9
|
+
switch (options?.code) {
|
|
10
|
+
case 'FAILED_TO_LOAD_LIBLSL':
|
|
11
|
+
message = `Well shoot! Loading the liblsl dylib failed. I tried to load it from ${options.liblslPath}.`
|
|
12
|
+
break
|
|
13
|
+
default:
|
|
14
|
+
message = super.friendlyMessage()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const fullMessage = options.friendlyMessage
|
|
18
|
+
? options.friendlyMessage
|
|
19
|
+
: message
|
|
20
|
+
|
|
21
|
+
return fullMessage
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/index.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"skipLibCheck": true,
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"target": "ES2017",
|
|
7
|
+
"lib": [
|
|
8
|
+
"DOM",
|
|
9
|
+
"es2017",
|
|
10
|
+
"ES2020"
|
|
11
|
+
],
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"noImplicitAny": true,
|
|
14
|
+
"allowJs": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"noImplicitReturns": true,
|
|
17
|
+
"strict": true,
|
|
18
|
+
"noUnusedLocals": true,
|
|
19
|
+
"resolveJsonModule": true,
|
|
20
|
+
"moduleResolution": "node",
|
|
21
|
+
"sourceMap": false,
|
|
22
|
+
"outDir": "build",
|
|
23
|
+
"baseUrl": "src",
|
|
24
|
+
"experimentalDecorators": true,
|
|
25
|
+
"paths": {
|
|
26
|
+
"#spruce/*": [
|
|
27
|
+
".spruce/*"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"include": [
|
|
32
|
+
"./src/*.ts",
|
|
33
|
+
"./src/**/*.ts",
|
|
34
|
+
"./src/.spruce/**/*"
|
|
35
|
+
],
|
|
36
|
+
"exclude": [
|
|
37
|
+
"build",
|
|
38
|
+
"esm"
|
|
39
|
+
]
|
|
40
|
+
}
|