@neurodevs/node-lsl 12.0.6 → 13.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/README.md +2 -5
- package/build/__tests__/AbstractPackageTest.d.ts +9 -3
- package/build/__tests__/AbstractPackageTest.js +37 -3
- package/build/__tests__/AbstractPackageTest.js.map +1 -1
- package/build/__tests__/impl/LiblslAdapter.test.d.ts +6 -0
- package/build/__tests__/impl/LiblslAdapter.test.js +133 -12
- package/build/__tests__/impl/LiblslAdapter.test.js.map +1 -1
- package/build/__tests__/impl/LslEventMarkerOutlet.test.js +5 -5
- package/build/__tests__/impl/LslEventMarkerOutlet.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamInfo.test.js +3 -3
- package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamInlet.test.d.ts +30 -2
- package/build/__tests__/impl/LslStreamInlet.test.js +181 -18
- package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
- package/build/__tests__/impl/LslStreamOutlet.test.d.ts +16 -7
- package/build/__tests__/impl/LslStreamOutlet.test.js +84 -23
- package/build/__tests__/impl/LslStreamOutlet.test.js.map +1 -1
- package/build/__tests__/impl/LslWebSocketBridge.test.d.ts +15 -0
- package/build/__tests__/impl/LslWebSocketBridge.test.js +112 -2
- package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
- package/build/assertions.d.ts +3 -3
- package/build/assertions.js +6 -6
- package/build/assertions.js.map +1 -1
- package/build/handleError.d.ts +8 -0
- package/build/handleError.js +25 -0
- package/build/handleError.js.map +1 -0
- package/build/impl/LiblslAdapter.d.ts +128 -13
- package/build/impl/LiblslAdapter.js +149 -71
- package/build/impl/LiblslAdapter.js.map +1 -1
- package/build/impl/LslEventMarkerOutlet.d.ts +4 -1
- package/build/impl/LslEventMarkerOutlet.js +3 -3
- package/build/impl/LslEventMarkerOutlet.js.map +1 -1
- package/build/impl/LslStreamInfo.d.ts +3 -3
- package/build/impl/LslStreamInfo.js +5 -5
- package/build/impl/LslStreamInfo.js.map +1 -1
- package/build/impl/LslStreamInlet.d.ts +52 -14
- package/build/impl/LslStreamInlet.js +157 -20
- package/build/impl/LslStreamInlet.js.map +1 -1
- package/build/impl/LslStreamOutlet.d.ts +13 -13
- package/build/impl/LslStreamOutlet.js +22 -21
- package/build/impl/LslStreamOutlet.js.map +1 -1
- package/build/impl/LslWebSocketBridge.d.ts +35 -3
- package/build/impl/LslWebSocketBridge.js +66 -3
- package/build/impl/LslWebSocketBridge.js.map +1 -1
- package/build/index.d.ts +4 -1
- package/build/index.js +5 -1
- package/build/index.js.map +1 -1
- package/build/scripts/runLslStreamOutlet.js +2 -3
- package/build/scripts/runLslStreamOutlet.js.map +1 -1
- package/build/scripts/runOutletToInlet.d.ts +1 -0
- package/build/scripts/runOutletToInlet.js +45 -0
- package/build/scripts/runOutletToInlet.js.map +1 -0
- package/build/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.d.ts +1 -2
- package/build/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.js.map +1 -1
- package/build/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.d.ts +2 -2
- package/build/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.js.map +1 -1
- package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.d.ts +1 -2
- package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.js.map +1 -1
- package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +15 -3
- package/build/testDoubles/Liblsl/FakeLiblsl.js +42 -0
- package/build/testDoubles/Liblsl/FakeLiblsl.js.map +1 -1
- package/build/testDoubles/StreamInfo/FakeStreamInfo.d.ts +1 -1
- package/build/testDoubles/StreamInfo/SpyStreamInfo.d.ts +1 -1
- package/build/testDoubles/StreamInlet/FakeStreamInlet.d.ts +12 -3
- package/build/testDoubles/StreamInlet/FakeStreamInlet.js +25 -5
- package/build/testDoubles/StreamInlet/FakeStreamInlet.js.map +1 -1
- package/build/testDoubles/StreamInlet/SpyStreamInlet.d.ts +3 -3
- package/build/testDoubles/StreamInlet/SpyStreamInlet.js +2 -2
- package/build/testDoubles/StreamInlet/SpyStreamInlet.js.map +1 -1
- package/build/testDoubles/StreamOutlet/FakeStreamOutlet.d.ts +4 -4
- package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js +6 -6
- package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js.map +1 -1
- package/build/testDoubles/StreamTransportBridge/FakeStreamTransportBridge.d.ts +6 -0
- package/build/testDoubles/StreamTransportBridge/FakeStreamTransportBridge.js +15 -0
- package/build/testDoubles/StreamTransportBridge/FakeStreamTransportBridge.js.map +1 -1
- package/build/testDoubles/StreamTransportBridge/SpyLslWebSocketBridge.d.ts +4 -0
- package/build/testDoubles/StreamTransportBridge/SpyLslWebSocketBridge.js +7 -0
- package/build/testDoubles/StreamTransportBridge/SpyLslWebSocketBridge.js.map +1 -0
- package/build/testDoubles/WebSockets/FakeWebSocket.d.ts +10 -0
- package/build/testDoubles/WebSockets/FakeWebSocket.js +14 -0
- package/build/testDoubles/WebSockets/FakeWebSocket.js.map +1 -0
- package/build/testDoubles/WebSockets/FakeWebSocketServer.d.ts +13 -0
- package/build/testDoubles/WebSockets/FakeWebSocketServer.js +22 -0
- package/build/testDoubles/WebSockets/FakeWebSocketServer.js.map +1 -0
- package/build/testDoubles/generateRandomOutletOptions.js +3 -3
- package/build/testDoubles/generateRandomOutletOptions.js.map +1 -1
- package/package.json +5 -3
- package/src/__tests__/AbstractPackageTest.ts +52 -4
- package/src/__tests__/impl/LiblslAdapter.test.ts +181 -16
- package/src/__tests__/impl/LslEventMarkerOutlet.test.ts +5 -5
- package/src/__tests__/impl/LslStreamInfo.test.ts +3 -3
- package/src/__tests__/impl/LslStreamInlet.test.ts +253 -20
- package/src/__tests__/impl/LslStreamOutlet.test.ts +111 -24
- package/src/__tests__/impl/LslWebSocketBridge.test.ts +163 -5
- package/src/assertions.ts +7 -7
- package/src/handleError.ts +24 -0
- package/src/impl/LiblslAdapter.ts +322 -97
- package/src/impl/LslEventMarkerOutlet.ts +8 -4
- package/src/impl/LslStreamInfo.ts +9 -9
- package/src/impl/LslStreamInlet.ts +233 -25
- package/src/impl/LslStreamOutlet.ts +43 -33
- package/src/impl/LslWebSocketBridge.ts +115 -5
- package/src/index.ts +8 -2
- package/src/scripts/runLslStreamOutlet.ts +2 -3
- package/src/scripts/runOutletToInlet.ts +53 -0
- package/src/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.ts +4 -2
- package/src/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.ts +5 -2
- package/src/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.ts +4 -2
- package/src/testDoubles/Liblsl/FakeLiblsl.ts +61 -1
- package/src/testDoubles/StreamInfo/FakeStreamInfo.ts +1 -1
- package/src/testDoubles/StreamInlet/FakeStreamInlet.ts +36 -5
- package/src/testDoubles/StreamInlet/SpyStreamInlet.ts +7 -2
- package/src/testDoubles/StreamOutlet/FakeStreamOutlet.ts +7 -7
- package/src/testDoubles/StreamTransportBridge/FakeStreamTransportBridge.ts +18 -0
- package/src/testDoubles/StreamTransportBridge/SpyLslWebSocketBridge.ts +9 -0
- package/src/testDoubles/WebSockets/FakeWebSocket.ts +17 -0
- package/src/testDoubles/WebSockets/FakeWebSocketServer.ts +32 -0
- package/src/testDoubles/generateRandomOutletOptions.ts +3 -3
- package/build/types.d.ts +0 -95
- package/build/types.js +0 -2
- package/build/types.js.map +0 -1
- package/src/types.ts +0 -111
package/src/assertions.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { ChannelFormat } from 'impl/LiblslAdapter.js'
|
|
1
2
|
import { CHANNEL_FORMATS } from './consts.js'
|
|
2
|
-
import { ChannelFormat } from './types.js'
|
|
3
3
|
import {
|
|
4
4
|
isGreaterThanOrEqualToZero,
|
|
5
5
|
isPositiveInteger,
|
|
@@ -15,10 +15,10 @@ export function assertValidChunkSize(chunkSize: number) {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export function
|
|
19
|
-
if (!isPositiveIntegerOrZero(
|
|
18
|
+
export function assertValidMaxBufferedMs(maxBufferedMs: number) {
|
|
19
|
+
if (!isPositiveIntegerOrZero(maxBufferedMs)) {
|
|
20
20
|
throw new Error(
|
|
21
|
-
`Invalid max buffered! Must be a positive integer or zero, not: ${
|
|
21
|
+
`Invalid max buffered! Must be a positive integer or zero, not: ${maxBufferedMs}.`
|
|
22
22
|
)
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -31,10 +31,10 @@ export function assertValidChannelFormat(channelFormat: ChannelFormat) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export function
|
|
35
|
-
if (!isGreaterThanOrEqualToZero(
|
|
34
|
+
export function assertValidSampleRateHz(sampleRateHz: number) {
|
|
35
|
+
if (!isGreaterThanOrEqualToZero(sampleRateHz)) {
|
|
36
36
|
throw new Error(
|
|
37
|
-
`Invalid sample rate! Must be a positive number or zero, not: ${
|
|
37
|
+
`Invalid sample rate! Must be a positive number or zero, not: ${sampleRateHz}.`
|
|
38
38
|
)
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export default function handleError(errorCode: number) {
|
|
2
|
+
switch (errorCode) {
|
|
3
|
+
case 0:
|
|
4
|
+
return
|
|
5
|
+
case -1:
|
|
6
|
+
throw new Error(`The liblsl operation failed due to a timeout!`)
|
|
7
|
+
case -2:
|
|
8
|
+
throw new Error(`The liblsl stream has been lost!`)
|
|
9
|
+
case -3:
|
|
10
|
+
throw new Error(`A liblsl argument was incorrectly specified!`)
|
|
11
|
+
case -4:
|
|
12
|
+
throw new Error(`An internal liblsl error has occurred!`)
|
|
13
|
+
default:
|
|
14
|
+
throw new Error(`An unknown liblsl error has occurred!`)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export enum LslErrorCode {
|
|
19
|
+
Ok = 0,
|
|
20
|
+
Timeout = -1,
|
|
21
|
+
Lost = -2,
|
|
22
|
+
BadArgument = -3,
|
|
23
|
+
InternalError = -4,
|
|
24
|
+
}
|
|
@@ -1,42 +1,37 @@
|
|
|
1
|
-
import { DataType, define, open } from 'ffi-rs'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
LiblslBindings,
|
|
6
|
-
CreateStreamInfoOptions,
|
|
7
|
-
AppendChannelsToStreamInfoOptions,
|
|
8
|
-
CreateOutletOptions,
|
|
9
|
-
DestroyOutletOptions,
|
|
10
|
-
PushSampleFloatTimestampOptions,
|
|
11
|
-
PushSampleStringTimestampOptions,
|
|
12
|
-
CreateInletOptions,
|
|
13
|
-
DestroyInletOptions,
|
|
14
|
-
FlushInletOptions,
|
|
15
|
-
} from '../types.js'
|
|
1
|
+
import { DataType, define, JsExternal, load, open, unwrapPointer } from 'ffi-rs'
|
|
2
|
+
|
|
3
|
+
import { CHANNEL_FORMATS } from '../consts.js'
|
|
4
|
+
import { LslErrorCode } from '../handleError.js'
|
|
16
5
|
|
|
17
6
|
export default class LiblslAdapter implements Liblsl {
|
|
18
|
-
public static
|
|
19
|
-
public static
|
|
7
|
+
public static open = open
|
|
8
|
+
public static define = define
|
|
9
|
+
public static load = load
|
|
10
|
+
|
|
20
11
|
private static instance?: Liblsl
|
|
21
12
|
|
|
22
|
-
|
|
13
|
+
public liblslPath: string
|
|
23
14
|
private bindings!: LiblslBindings
|
|
24
15
|
|
|
16
|
+
private readonly defaultMacOsPath = `/opt/homebrew/Cellar/lsl/1.16.2/lib/liblsl.1.16.2.dylib`
|
|
17
|
+
|
|
25
18
|
protected constructor() {
|
|
26
|
-
this.
|
|
19
|
+
this.liblslPath = process.env.LIBLSL_PATH ?? this.defaultMacOsPath
|
|
27
20
|
this.tryToLoadBindings()
|
|
28
21
|
}
|
|
29
22
|
|
|
30
23
|
private tryToLoadBindings() {
|
|
31
24
|
try {
|
|
32
|
-
this.
|
|
25
|
+
this.loadBindings()
|
|
33
26
|
} catch (error) {
|
|
34
|
-
|
|
27
|
+
this.throwFailedToLoadLiblsl(error as Error)
|
|
35
28
|
}
|
|
36
29
|
}
|
|
37
30
|
|
|
38
|
-
private
|
|
39
|
-
|
|
31
|
+
private throwFailedToLoadLiblsl(error: Error) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Loading the liblsl dylib failed! I tried to load it from ${this.liblslPath}.\n\n${error.message}\n\n`
|
|
34
|
+
)
|
|
40
35
|
}
|
|
41
36
|
|
|
42
37
|
public static getInstance() {
|
|
@@ -54,13 +49,193 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
54
49
|
delete this.instance
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
private loadBindings(
|
|
58
|
-
|
|
52
|
+
private loadBindings() {
|
|
53
|
+
this.openLiblsl()
|
|
54
|
+
this.bindings = this.defineLiblslBindings()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private openLiblsl() {
|
|
58
|
+
this.open({
|
|
59
|
+
library: 'lsl',
|
|
60
|
+
path: this.liblslPath,
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private defineLiblslBindings() {
|
|
65
|
+
return this.define(this.liblslFuncs) as unknown as LiblslBindings
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public createStreamInfo(options: CreateStreamInfoOptions) {
|
|
69
|
+
const {
|
|
70
|
+
name,
|
|
71
|
+
type,
|
|
72
|
+
channelCount,
|
|
73
|
+
sampleRateHz,
|
|
74
|
+
channelFormat,
|
|
75
|
+
sourceId,
|
|
76
|
+
} = options
|
|
77
|
+
|
|
78
|
+
return this.bindings.lsl_create_streaminfo([
|
|
79
|
+
name,
|
|
80
|
+
type,
|
|
81
|
+
channelCount,
|
|
82
|
+
sampleRateHz,
|
|
83
|
+
channelFormat,
|
|
84
|
+
sourceId,
|
|
85
|
+
])
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public appendChannelsToStreamInfo(
|
|
89
|
+
options: AppendChannelsToStreamInfoOptions
|
|
90
|
+
) {
|
|
91
|
+
const { info, channels } = options
|
|
92
|
+
|
|
93
|
+
const description = this.bindings.lsl_get_desc([info])
|
|
94
|
+
const parent = this.bindings.lsl_append_child([description, 'channels'])
|
|
95
|
+
|
|
96
|
+
for (const channel of channels) {
|
|
97
|
+
const child = this.bindings.lsl_append_child([parent, 'channel'])
|
|
98
|
+
this.bindings.lsl_append_child_value([
|
|
99
|
+
child,
|
|
100
|
+
'label',
|
|
101
|
+
channel.label,
|
|
102
|
+
])
|
|
103
|
+
this.bindings.lsl_append_child_value([child, 'unit', channel.units])
|
|
104
|
+
this.bindings.lsl_append_child_value([child, 'type', channel.type])
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public createOutlet(options: CreateOutletOptions) {
|
|
109
|
+
const { info, chunkSize, maxBufferedMs } = options
|
|
110
|
+
|
|
111
|
+
return this.bindings.lsl_create_outlet([
|
|
112
|
+
info,
|
|
113
|
+
chunkSize,
|
|
114
|
+
maxBufferedMs / 1000,
|
|
115
|
+
])
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public pushSampleFloatTimestamp(options: PushSampleFloatTimestampOptions) {
|
|
119
|
+
const { outlet, sample, timestamp } = options
|
|
120
|
+
return this.bindings.lsl_push_sample_ft([outlet, sample, timestamp])
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public pushSampleStringTimestamp(
|
|
124
|
+
options: PushSampleStringTimestampOptions
|
|
125
|
+
) {
|
|
126
|
+
const { outlet, sample, timestamp } = options
|
|
127
|
+
return this.bindings.lsl_push_sample_strt([outlet, sample, timestamp])
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public destroyOutlet(options: DestroyOutletOptions) {
|
|
131
|
+
const { outlet } = options
|
|
132
|
+
this.bindings.lsl_destroy_outlet([outlet])
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public createInlet(options: CreateInletOptions) {
|
|
136
|
+
const { info, chunkSize, maxBufferedMs } = options
|
|
137
|
+
|
|
138
|
+
return this.bindings.lsl_create_inlet([
|
|
139
|
+
info,
|
|
140
|
+
chunkSize,
|
|
141
|
+
maxBufferedMs / 1000,
|
|
142
|
+
])
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public pullSample(options: PullSampleOptions) {
|
|
146
|
+
const {
|
|
147
|
+
inlet,
|
|
148
|
+
dataBufferPtr,
|
|
149
|
+
dataBufferElements,
|
|
150
|
+
timeout,
|
|
151
|
+
errcodePtr,
|
|
152
|
+
} = options
|
|
153
|
+
|
|
154
|
+
return this.load({
|
|
155
|
+
library: 'lsl',
|
|
156
|
+
funcName: 'lsl_pull_sample_f',
|
|
157
|
+
retType: DataType.Double,
|
|
158
|
+
paramsType: [
|
|
159
|
+
DataType.External,
|
|
160
|
+
DataType.External,
|
|
161
|
+
DataType.I32,
|
|
162
|
+
DataType.Double,
|
|
163
|
+
DataType.External,
|
|
164
|
+
],
|
|
165
|
+
paramsValue: [
|
|
166
|
+
inlet,
|
|
167
|
+
dataBufferPtr,
|
|
168
|
+
dataBufferElements,
|
|
169
|
+
timeout,
|
|
170
|
+
errcodePtr,
|
|
171
|
+
],
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public pullChunk(options: PullChunkOptions) {
|
|
176
|
+
const {
|
|
177
|
+
inlet,
|
|
178
|
+
dataBufferPtr,
|
|
179
|
+
timestampBufferPtr,
|
|
180
|
+
dataBufferElements,
|
|
181
|
+
timestampBufferElements,
|
|
182
|
+
timeout,
|
|
183
|
+
errcodePtr,
|
|
184
|
+
} = options
|
|
185
|
+
|
|
186
|
+
return this.load({
|
|
59
187
|
library: 'lsl',
|
|
60
|
-
|
|
188
|
+
funcName: 'lsl_pull_chunk_f',
|
|
189
|
+
retType: DataType.Double,
|
|
190
|
+
paramsType: [
|
|
191
|
+
DataType.External,
|
|
192
|
+
DataType.External,
|
|
193
|
+
DataType.External,
|
|
194
|
+
DataType.I32,
|
|
195
|
+
DataType.I32,
|
|
196
|
+
DataType.Double,
|
|
197
|
+
DataType.External,
|
|
198
|
+
],
|
|
199
|
+
paramsValue: [
|
|
200
|
+
inlet,
|
|
201
|
+
unwrapPointer([dataBufferPtr])[0],
|
|
202
|
+
unwrapPointer([timestampBufferPtr])[0],
|
|
203
|
+
dataBufferElements,
|
|
204
|
+
timestampBufferElements,
|
|
205
|
+
timeout,
|
|
206
|
+
unwrapPointer([errcodePtr])[0],
|
|
207
|
+
],
|
|
61
208
|
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
public flushInlet(options: FlushInletOptions) {
|
|
212
|
+
const { inlet } = options
|
|
213
|
+
this.bindings.lsl_flush_inlet([inlet])
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
public destroyInlet(options: DestroyInletOptions) {
|
|
217
|
+
const { inlet } = options
|
|
218
|
+
this.bindings.lsl_destroy_inlet([inlet])
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
public localClock() {
|
|
222
|
+
return this.bindings.lsl_local_clock([])
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private get open() {
|
|
226
|
+
return LiblslAdapter.open
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private get define() {
|
|
230
|
+
return LiblslAdapter.define
|
|
231
|
+
}
|
|
62
232
|
|
|
63
|
-
|
|
233
|
+
private get load() {
|
|
234
|
+
return LiblslAdapter.load
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private get liblslFuncs() {
|
|
238
|
+
return {
|
|
64
239
|
lsl_create_streaminfo: {
|
|
65
240
|
library: 'lsl',
|
|
66
241
|
retType: DataType.External,
|
|
@@ -80,7 +255,7 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
80
255
|
},
|
|
81
256
|
lsl_push_sample_ft: {
|
|
82
257
|
library: 'lsl',
|
|
83
|
-
retType: DataType.
|
|
258
|
+
retType: DataType.I32,
|
|
84
259
|
paramsType: [
|
|
85
260
|
DataType.External,
|
|
86
261
|
DataType.FloatArray,
|
|
@@ -89,7 +264,7 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
89
264
|
},
|
|
90
265
|
lsl_push_sample_strt: {
|
|
91
266
|
library: 'lsl',
|
|
92
|
-
retType: DataType.
|
|
267
|
+
retType: DataType.I32,
|
|
93
268
|
paramsType: [
|
|
94
269
|
DataType.External,
|
|
95
270
|
DataType.StringArray,
|
|
@@ -140,87 +315,137 @@ export default class LiblslAdapter implements Liblsl {
|
|
|
140
315
|
retType: DataType.Double,
|
|
141
316
|
paramsType: [],
|
|
142
317
|
},
|
|
143
|
-
}
|
|
318
|
+
}
|
|
144
319
|
}
|
|
320
|
+
}
|
|
145
321
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
name,
|
|
149
|
-
type,
|
|
150
|
-
channelCount,
|
|
151
|
-
sampleRate,
|
|
152
|
-
channelFormat,
|
|
153
|
-
sourceId,
|
|
154
|
-
} = options
|
|
322
|
+
export interface Liblsl {
|
|
323
|
+
liblslPath: string
|
|
155
324
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
type,
|
|
159
|
-
channelCount,
|
|
160
|
-
sampleRate,
|
|
161
|
-
channelFormat,
|
|
162
|
-
sourceId,
|
|
163
|
-
])
|
|
164
|
-
}
|
|
325
|
+
createStreamInfo(options: CreateStreamInfoOptions): BoundStreamInfo
|
|
326
|
+
appendChannelsToStreamInfo(options: AppendChannelsToStreamInfoOptions): void
|
|
165
327
|
|
|
166
|
-
|
|
167
|
-
options: AppendChannelsToStreamInfoOptions
|
|
168
|
-
) {
|
|
169
|
-
const { info, channels } = options
|
|
328
|
+
createOutlet(options: CreateOutletOptions): BoundOutlet
|
|
170
329
|
|
|
171
|
-
|
|
172
|
-
|
|
330
|
+
pushSampleFloatTimestamp(
|
|
331
|
+
options: PushSampleFloatTimestampOptions
|
|
332
|
+
): LslErrorCode
|
|
173
333
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
child,
|
|
178
|
-
'label',
|
|
179
|
-
channel.label,
|
|
180
|
-
])
|
|
181
|
-
this.bindings.lsl_append_child_value([child, 'unit', channel.unit])
|
|
182
|
-
this.bindings.lsl_append_child_value([child, 'type', channel.type])
|
|
183
|
-
}
|
|
184
|
-
}
|
|
334
|
+
pushSampleStringTimestamp(
|
|
335
|
+
options: PushSampleStringTimestampOptions
|
|
336
|
+
): LslErrorCode
|
|
185
337
|
|
|
186
|
-
|
|
187
|
-
const { info, chunkSize, maxBuffered } = options
|
|
188
|
-
return this.bindings.lsl_create_outlet([info, chunkSize, maxBuffered])
|
|
189
|
-
}
|
|
338
|
+
destroyOutlet(options: DestroyOutletOptions): void
|
|
190
339
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
340
|
+
createInlet(options: CreateInletOptions): BoundInlet
|
|
341
|
+
pullSample(options: PullSampleOptions): number
|
|
342
|
+
pullChunk(options: PullChunkOptions): number
|
|
343
|
+
flushInlet(options: FlushInletOptions): void
|
|
344
|
+
destroyInlet(options: DestroyInletOptions): void
|
|
195
345
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
) {
|
|
199
|
-
const { outlet, sample, timestamp } = options
|
|
200
|
-
this.bindings.lsl_push_sample_strt([outlet, sample, timestamp])
|
|
201
|
-
}
|
|
346
|
+
localClock(): number
|
|
347
|
+
}
|
|
202
348
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
349
|
+
export interface CreateStreamInfoOptions {
|
|
350
|
+
name: string
|
|
351
|
+
type: string
|
|
352
|
+
channelCount: number
|
|
353
|
+
sampleRateHz: number
|
|
354
|
+
channelFormat: number
|
|
355
|
+
sourceId: string
|
|
356
|
+
manufacturer?: string
|
|
357
|
+
units?: string
|
|
358
|
+
}
|
|
207
359
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
360
|
+
export interface AppendChannelsToStreamInfoOptions {
|
|
361
|
+
info: BoundStreamInfo
|
|
362
|
+
channels: LslChannel[]
|
|
363
|
+
}
|
|
212
364
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
365
|
+
export interface CreateOutletOptions {
|
|
366
|
+
info: BoundStreamInfo
|
|
367
|
+
chunkSize: number
|
|
368
|
+
maxBufferedMs: number
|
|
369
|
+
}
|
|
217
370
|
|
|
218
|
-
|
|
371
|
+
export interface PushSampleFloatTimestampOptions {
|
|
372
|
+
outlet: BoundOutlet
|
|
373
|
+
sample: number[]
|
|
374
|
+
timestamp: number
|
|
375
|
+
}
|
|
219
376
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
377
|
+
export interface PushSampleStringTimestampOptions {
|
|
378
|
+
outlet: BoundOutlet
|
|
379
|
+
sample: string[]
|
|
380
|
+
timestamp: number
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export interface DestroyOutletOptions {
|
|
384
|
+
outlet: BoundOutlet
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export interface CreateInletOptions {
|
|
388
|
+
info: BoundStreamInfo
|
|
389
|
+
chunkSize: number
|
|
390
|
+
maxBufferedMs: number
|
|
391
|
+
}
|
|
223
392
|
|
|
224
|
-
|
|
225
|
-
|
|
393
|
+
export interface PullSampleOptions {
|
|
394
|
+
inlet: BoundInlet
|
|
395
|
+
dataBufferPtr: JsExternal
|
|
396
|
+
dataBufferElements: number
|
|
397
|
+
timeout: number
|
|
398
|
+
errcodePtr: JsExternal
|
|
226
399
|
}
|
|
400
|
+
|
|
401
|
+
export interface PullChunkOptions {
|
|
402
|
+
inlet: BoundInlet
|
|
403
|
+
dataBufferPtr: JsExternal
|
|
404
|
+
timestampBufferPtr: JsExternal
|
|
405
|
+
dataBufferElements: number
|
|
406
|
+
timestampBufferElements: number
|
|
407
|
+
timeout: number
|
|
408
|
+
errcodePtr: JsExternal
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export interface FlushInletOptions {
|
|
412
|
+
inlet: BoundInlet
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export interface DestroyInletOptions {
|
|
416
|
+
inlet: BoundInlet
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export interface LiblslBindings {
|
|
420
|
+
lsl_create_streaminfo(
|
|
421
|
+
args: [string, string, number, number, number, string]
|
|
422
|
+
): BoundStreamInfo
|
|
423
|
+
|
|
424
|
+
lsl_create_outlet(args: [BoundStreamInfo, number, number]): BoundOutlet
|
|
425
|
+
lsl_push_sample_ft(args: [BoundOutlet, LslSample, number]): LslErrorCode
|
|
426
|
+
lsl_push_sample_strt(args: [BoundOutlet, LslSample, number]): LslErrorCode
|
|
427
|
+
lsl_destroy_outlet(args: [BoundOutlet]): void
|
|
428
|
+
lsl_create_inlet(args: any): BoundInlet
|
|
429
|
+
lsl_flush_inlet(args: [BoundInlet]): void
|
|
430
|
+
lsl_destroy_inlet(args: any): void
|
|
431
|
+
lsl_local_clock(args: []): number
|
|
432
|
+
lsl_get_desc(args: [BoundStreamInfo]): BoundDescription
|
|
433
|
+
lsl_append_child(args: [BoundDescription, string]): BoundChild
|
|
434
|
+
lsl_append_child_value(args: [BoundChild, string, string]): void
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export type ChannelFormat = (typeof CHANNEL_FORMATS)[number]
|
|
438
|
+
|
|
439
|
+
export interface LslChannel {
|
|
440
|
+
label: string
|
|
441
|
+
units: string
|
|
442
|
+
type: string
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export type LslSample = (number | string | undefined)[]
|
|
446
|
+
|
|
447
|
+
export interface BoundStreamInfo {}
|
|
448
|
+
export interface BoundOutlet {}
|
|
449
|
+
export interface BoundInlet {}
|
|
450
|
+
export interface BoundDescription {}
|
|
451
|
+
export interface BoundChild {}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { DurationMarker } from '../types.js'
|
|
2
1
|
import LslStreamOutlet, {
|
|
3
2
|
StreamOutletOptions,
|
|
4
3
|
StreamOutlet,
|
|
@@ -21,13 +20,13 @@ export default class LslEventMarkerOutlet implements EventMarkerOutlet {
|
|
|
21
20
|
name: 'Event markers',
|
|
22
21
|
type: 'Markers',
|
|
23
22
|
channelNames: ['Markers'],
|
|
24
|
-
|
|
23
|
+
sampleRateHz: 0,
|
|
25
24
|
channelFormat: 'string',
|
|
26
25
|
sourceId: 'event-markers',
|
|
27
26
|
manufacturer: 'N/A',
|
|
28
|
-
|
|
27
|
+
units: 'N/A',
|
|
29
28
|
chunkSize: 0,
|
|
30
|
-
|
|
29
|
+
maxBufferedMs: 0,
|
|
31
30
|
} as StreamOutletOptions
|
|
32
31
|
|
|
33
32
|
const outlet = await LslStreamOutlet.Create({
|
|
@@ -86,3 +85,8 @@ export interface EventMarkerOutlet {
|
|
|
86
85
|
export type EventMarkerOutletConstructor = new (
|
|
87
86
|
outlet: StreamOutlet
|
|
88
87
|
) => EventMarkerOutlet
|
|
88
|
+
|
|
89
|
+
export interface DurationMarker {
|
|
90
|
+
name: string
|
|
91
|
+
durationMs: number
|
|
92
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import generateId from '@neurodevs/generate-id'
|
|
2
2
|
|
|
3
3
|
import { CHANNEL_FORMATS_MAP } from '../consts.js'
|
|
4
|
-
import { BoundStreamInfo, ChannelFormat } from '
|
|
4
|
+
import { BoundStreamInfo, ChannelFormat } from './LiblslAdapter.js'
|
|
5
5
|
import LiblslAdapter from './LiblslAdapter.js'
|
|
6
6
|
|
|
7
7
|
export default class LslStreamInfo implements StreamInfo {
|
|
@@ -14,16 +14,16 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
14
14
|
protected streamInfo!: BoundStreamInfo
|
|
15
15
|
private channelNames: string[]
|
|
16
16
|
private channelFormat: ChannelFormat
|
|
17
|
-
private
|
|
17
|
+
private sampleRateHz: number
|
|
18
18
|
|
|
19
19
|
protected constructor(options: StreamInfoOptions) {
|
|
20
20
|
const {
|
|
21
|
-
channelNames,
|
|
22
|
-
channelFormat,
|
|
23
|
-
sampleRate,
|
|
24
21
|
name = this.defaultName,
|
|
25
22
|
type = this.defaultType,
|
|
26
23
|
sourceId = this.defaultSourceId,
|
|
24
|
+
channelNames,
|
|
25
|
+
channelFormat,
|
|
26
|
+
sampleRateHz,
|
|
27
27
|
units = this.defaultUnits,
|
|
28
28
|
} = options
|
|
29
29
|
|
|
@@ -32,8 +32,8 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
32
32
|
this.sourceId = sourceId
|
|
33
33
|
this.channelNames = channelNames
|
|
34
34
|
this.channelFormat = channelFormat
|
|
35
|
+
this.sampleRateHz = sampleRateHz
|
|
35
36
|
this.units = units
|
|
36
|
-
this.sampleRate = sampleRate
|
|
37
37
|
|
|
38
38
|
this.createStreamInfo()
|
|
39
39
|
this.appendChannelsToStreamInfo()
|
|
@@ -50,7 +50,7 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
50
50
|
sourceId: this.sourceId,
|
|
51
51
|
channelCount: this.channelCount,
|
|
52
52
|
channelFormat: this.lslChannelFormat,
|
|
53
|
-
|
|
53
|
+
sampleRateHz: this.sampleRateHz,
|
|
54
54
|
})
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -59,7 +59,7 @@ export default class LslStreamInfo implements StreamInfo {
|
|
|
59
59
|
info: this.streamInfo,
|
|
60
60
|
channels: this.channelNames.map((label: string) => ({
|
|
61
61
|
label,
|
|
62
|
-
|
|
62
|
+
units: this.units,
|
|
63
63
|
type: this.type,
|
|
64
64
|
})),
|
|
65
65
|
})
|
|
@@ -96,7 +96,7 @@ type StreamInfoConstructor = new (options: StreamInfoOptions) => StreamInfo
|
|
|
96
96
|
export interface StreamInfoOptions {
|
|
97
97
|
channelNames: string[]
|
|
98
98
|
channelFormat: ChannelFormat
|
|
99
|
-
|
|
99
|
+
sampleRateHz: number
|
|
100
100
|
name?: string
|
|
101
101
|
type?: string
|
|
102
102
|
sourceId?: string
|