@neurodevs/node-lsl 12.0.6 → 13.0.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.
Files changed (122) hide show
  1. package/README.md +2 -5
  2. package/build/__tests__/AbstractPackageTest.d.ts +9 -3
  3. package/build/__tests__/AbstractPackageTest.js +37 -3
  4. package/build/__tests__/AbstractPackageTest.js.map +1 -1
  5. package/build/__tests__/impl/LiblslAdapter.test.d.ts +6 -0
  6. package/build/__tests__/impl/LiblslAdapter.test.js +133 -12
  7. package/build/__tests__/impl/LiblslAdapter.test.js.map +1 -1
  8. package/build/__tests__/impl/LslEventMarkerOutlet.test.js +5 -5
  9. package/build/__tests__/impl/LslEventMarkerOutlet.test.js.map +1 -1
  10. package/build/__tests__/impl/LslStreamInfo.test.js +3 -3
  11. package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
  12. package/build/__tests__/impl/LslStreamInlet.test.d.ts +30 -2
  13. package/build/__tests__/impl/LslStreamInlet.test.js +181 -18
  14. package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
  15. package/build/__tests__/impl/LslStreamOutlet.test.d.ts +16 -7
  16. package/build/__tests__/impl/LslStreamOutlet.test.js +84 -23
  17. package/build/__tests__/impl/LslStreamOutlet.test.js.map +1 -1
  18. package/build/__tests__/impl/LslWebSocketBridge.test.d.ts +15 -0
  19. package/build/__tests__/impl/LslWebSocketBridge.test.js +112 -2
  20. package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
  21. package/build/assertions.d.ts +3 -3
  22. package/build/assertions.js +6 -6
  23. package/build/assertions.js.map +1 -1
  24. package/build/handleError.d.ts +8 -0
  25. package/build/handleError.js +25 -0
  26. package/build/handleError.js.map +1 -0
  27. package/build/impl/LiblslAdapter.d.ts +128 -13
  28. package/build/impl/LiblslAdapter.js +149 -71
  29. package/build/impl/LiblslAdapter.js.map +1 -1
  30. package/build/impl/LslEventMarkerOutlet.d.ts +4 -1
  31. package/build/impl/LslEventMarkerOutlet.js +3 -3
  32. package/build/impl/LslEventMarkerOutlet.js.map +1 -1
  33. package/build/impl/LslStreamInfo.d.ts +3 -3
  34. package/build/impl/LslStreamInfo.js +5 -5
  35. package/build/impl/LslStreamInfo.js.map +1 -1
  36. package/build/impl/LslStreamInlet.d.ts +52 -14
  37. package/build/impl/LslStreamInlet.js +157 -20
  38. package/build/impl/LslStreamInlet.js.map +1 -1
  39. package/build/impl/LslStreamOutlet.d.ts +13 -13
  40. package/build/impl/LslStreamOutlet.js +22 -21
  41. package/build/impl/LslStreamOutlet.js.map +1 -1
  42. package/build/impl/LslWebSocketBridge.d.ts +35 -3
  43. package/build/impl/LslWebSocketBridge.js +66 -3
  44. package/build/impl/LslWebSocketBridge.js.map +1 -1
  45. package/build/index.d.ts +0 -1
  46. package/build/index.js +0 -1
  47. package/build/index.js.map +1 -1
  48. package/build/scripts/runLslStreamOutlet.js +2 -3
  49. package/build/scripts/runLslStreamOutlet.js.map +1 -1
  50. package/build/scripts/runOutletToInlet.d.ts +1 -0
  51. package/build/scripts/runOutletToInlet.js +45 -0
  52. package/build/scripts/runOutletToInlet.js.map +1 -0
  53. package/build/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.d.ts +1 -2
  54. package/build/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.js.map +1 -1
  55. package/build/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.d.ts +2 -2
  56. package/build/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.js.map +1 -1
  57. package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.d.ts +1 -2
  58. package/build/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.js.map +1 -1
  59. package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +15 -3
  60. package/build/testDoubles/Liblsl/FakeLiblsl.js +42 -0
  61. package/build/testDoubles/Liblsl/FakeLiblsl.js.map +1 -1
  62. package/build/testDoubles/StreamInfo/FakeStreamInfo.d.ts +1 -1
  63. package/build/testDoubles/StreamInfo/SpyStreamInfo.d.ts +1 -1
  64. package/build/testDoubles/StreamInlet/FakeStreamInlet.d.ts +12 -3
  65. package/build/testDoubles/StreamInlet/FakeStreamInlet.js +25 -5
  66. package/build/testDoubles/StreamInlet/FakeStreamInlet.js.map +1 -1
  67. package/build/testDoubles/StreamInlet/SpyStreamInlet.d.ts +3 -3
  68. package/build/testDoubles/StreamInlet/SpyStreamInlet.js +2 -2
  69. package/build/testDoubles/StreamInlet/SpyStreamInlet.js.map +1 -1
  70. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.d.ts +4 -4
  71. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js +6 -6
  72. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js.map +1 -1
  73. package/build/testDoubles/StreamTransportBridge/FakeStreamTransportBridge.d.ts +6 -0
  74. package/build/testDoubles/StreamTransportBridge/FakeStreamTransportBridge.js +15 -0
  75. package/build/testDoubles/StreamTransportBridge/FakeStreamTransportBridge.js.map +1 -1
  76. package/build/testDoubles/StreamTransportBridge/SpyLslWebSocketBridge.d.ts +4 -0
  77. package/build/testDoubles/StreamTransportBridge/SpyLslWebSocketBridge.js +7 -0
  78. package/build/testDoubles/StreamTransportBridge/SpyLslWebSocketBridge.js.map +1 -0
  79. package/build/testDoubles/WebSockets/FakeWebSocket.d.ts +10 -0
  80. package/build/testDoubles/WebSockets/FakeWebSocket.js +14 -0
  81. package/build/testDoubles/WebSockets/FakeWebSocket.js.map +1 -0
  82. package/build/testDoubles/WebSockets/FakeWebSocketServer.d.ts +13 -0
  83. package/build/testDoubles/WebSockets/FakeWebSocketServer.js +22 -0
  84. package/build/testDoubles/WebSockets/FakeWebSocketServer.js.map +1 -0
  85. package/build/testDoubles/generateRandomOutletOptions.js +3 -3
  86. package/build/testDoubles/generateRandomOutletOptions.js.map +1 -1
  87. package/package.json +5 -3
  88. package/src/__tests__/AbstractPackageTest.ts +52 -4
  89. package/src/__tests__/impl/LiblslAdapter.test.ts +181 -16
  90. package/src/__tests__/impl/LslEventMarkerOutlet.test.ts +5 -5
  91. package/src/__tests__/impl/LslStreamInfo.test.ts +3 -3
  92. package/src/__tests__/impl/LslStreamInlet.test.ts +253 -20
  93. package/src/__tests__/impl/LslStreamOutlet.test.ts +111 -24
  94. package/src/__tests__/impl/LslWebSocketBridge.test.ts +163 -5
  95. package/src/assertions.ts +7 -7
  96. package/src/handleError.ts +24 -0
  97. package/src/impl/LiblslAdapter.ts +322 -97
  98. package/src/impl/LslEventMarkerOutlet.ts +8 -4
  99. package/src/impl/LslStreamInfo.ts +9 -9
  100. package/src/impl/LslStreamInlet.ts +233 -25
  101. package/src/impl/LslStreamOutlet.ts +43 -33
  102. package/src/impl/LslWebSocketBridge.ts +115 -5
  103. package/src/index.ts +0 -2
  104. package/src/scripts/runLslStreamOutlet.ts +2 -3
  105. package/src/scripts/runOutletToInlet.ts +53 -0
  106. package/src/testDoubles/EventMarkerOutlet/FakeEventMarkerOutlet.ts +4 -2
  107. package/src/testDoubles/EventMarkerOutlet/MockEventMarkerOutlet.ts +5 -2
  108. package/src/testDoubles/EventMarkerOutlet/ThrowingEventMarkerOutlet.ts +4 -2
  109. package/src/testDoubles/Liblsl/FakeLiblsl.ts +61 -1
  110. package/src/testDoubles/StreamInfo/FakeStreamInfo.ts +1 -1
  111. package/src/testDoubles/StreamInlet/FakeStreamInlet.ts +36 -5
  112. package/src/testDoubles/StreamInlet/SpyStreamInlet.ts +7 -2
  113. package/src/testDoubles/StreamOutlet/FakeStreamOutlet.ts +7 -7
  114. package/src/testDoubles/StreamTransportBridge/FakeStreamTransportBridge.ts +18 -0
  115. package/src/testDoubles/StreamTransportBridge/SpyLslWebSocketBridge.ts +9 -0
  116. package/src/testDoubles/WebSockets/FakeWebSocket.ts +17 -0
  117. package/src/testDoubles/WebSockets/FakeWebSocketServer.ts +32 -0
  118. package/src/testDoubles/generateRandomOutletOptions.ts +3 -3
  119. package/build/types.d.ts +0 -95
  120. package/build/types.js +0 -2
  121. package/build/types.js.map +0 -1
  122. 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 assertValidMaxBuffered(maxBuffered: number) {
19
- if (!isPositiveIntegerOrZero(maxBuffered)) {
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: ${maxBuffered}.`
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 assertValidSampleRate(sampleRate: number) {
35
- if (!isGreaterThanOrEqualToZero(sampleRate)) {
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: ${sampleRate}.`
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
- Liblsl,
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 ffiRsOpen = open
19
- public static ffiRsDefine = define
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
- private path: string
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.path = process.env.LIBLSL_PATH! ?? this.defaultMacOsPath
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.bindings = this.loadBindings(this.path)
25
+ this.loadBindings()
33
26
  } catch (error) {
34
- throw new Error(this.generateFailedMessage(error as Error))
27
+ this.throwFailedToLoadLiblsl(error as Error)
35
28
  }
36
29
  }
37
30
 
38
- private generateFailedMessage(error: Error) {
39
- return `Loading the liblsl dylib failed! I tried to load it from ${this.path}.\n\n${error.message}\n\n`
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(liblslPath: string) {
58
- LiblslAdapter.ffiRsOpen({
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
- path: liblslPath,
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
- return LiblslAdapter.ffiRsDefine({
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.Void,
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.Void,
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
- }) as unknown as LiblslBindings
318
+ }
144
319
  }
320
+ }
145
321
 
146
- public createStreamInfo(options: CreateStreamInfoOptions) {
147
- const {
148
- name,
149
- type,
150
- channelCount,
151
- sampleRate,
152
- channelFormat,
153
- sourceId,
154
- } = options
322
+ export interface Liblsl {
323
+ liblslPath: string
155
324
 
156
- return this.bindings.lsl_create_streaminfo([
157
- name,
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
- public appendChannelsToStreamInfo(
167
- options: AppendChannelsToStreamInfoOptions
168
- ) {
169
- const { info, channels } = options
328
+ createOutlet(options: CreateOutletOptions): BoundOutlet
170
329
 
171
- const description = this.bindings.lsl_get_desc([info])
172
- const parent = this.bindings.lsl_append_child([description, 'channels'])
330
+ pushSampleFloatTimestamp(
331
+ options: PushSampleFloatTimestampOptions
332
+ ): LslErrorCode
173
333
 
174
- for (const channel of channels) {
175
- const child = this.bindings.lsl_append_child([parent, 'channel'])
176
- this.bindings.lsl_append_child_value([
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
- public createOutlet(options: CreateOutletOptions) {
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
- public pushSampleFloatTimestamp(options: PushSampleFloatTimestampOptions) {
192
- const { outlet, sample, timestamp } = options
193
- this.bindings.lsl_push_sample_ft([outlet, sample, timestamp])
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
- public pushSampleStringTimestamp(
197
- options: PushSampleStringTimestampOptions
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
- public destroyOutlet(options: DestroyOutletOptions) {
204
- const { outlet } = options
205
- this.bindings.lsl_destroy_outlet([outlet])
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
- public createInlet(options: CreateInletOptions) {
209
- const { info, chunkSize, maxBuffered } = options
210
- return this.bindings.lsl_create_inlet([info, chunkSize, maxBuffered])
211
- }
360
+ export interface AppendChannelsToStreamInfoOptions {
361
+ info: BoundStreamInfo
362
+ channels: LslChannel[]
363
+ }
212
364
 
213
- public flushInlet(options: FlushInletOptions) {
214
- const { inlet } = options
215
- this.bindings.lsl_flush_inlet([inlet])
216
- }
365
+ export interface CreateOutletOptions {
366
+ info: BoundStreamInfo
367
+ chunkSize: number
368
+ maxBufferedMs: number
369
+ }
217
370
 
218
- public destroyInlet(_options: DestroyInletOptions) {}
371
+ export interface PushSampleFloatTimestampOptions {
372
+ outlet: BoundOutlet
373
+ sample: number[]
374
+ timestamp: number
375
+ }
219
376
 
220
- public localClock() {
221
- return this.bindings.lsl_local_clock([])
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
- private readonly defaultMacOsPath =
225
- '/opt/homebrew/Cellar/lsl/1.16.2/lib/liblsl.1.16.2.dylib'
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
- sampleRate: 0,
23
+ sampleRateHz: 0,
25
24
  channelFormat: 'string',
26
25
  sourceId: 'event-markers',
27
26
  manufacturer: 'N/A',
28
- unit: 'N/A',
27
+ units: 'N/A',
29
28
  chunkSize: 0,
30
- maxBuffered: 0,
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 '../types.js'
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 sampleRate: number
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
- sampleRate: this.sampleRate,
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
- unit: this.units,
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
- sampleRate: number
99
+ sampleRateHz: number
100
100
  name?: string
101
101
  type?: string
102
102
  sourceId?: string