@neurodevs/node-lsl 17.0.0 → 17.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.
Files changed (56) hide show
  1. package/build/__tests__/AbstractPackageTest.d.ts +2 -0
  2. package/build/__tests__/AbstractPackageTest.js +2 -6
  3. package/build/__tests__/AbstractPackageTest.js.map +1 -1
  4. package/build/__tests__/impl/LslStreamInfo.test.d.ts +3 -3
  5. package/build/__tests__/impl/LslStreamInfo.test.js +12 -12
  6. package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
  7. package/build/__tests__/impl/LslStreamInlet.test.d.ts +0 -3
  8. package/build/__tests__/impl/LslStreamInlet.test.js +1 -27
  9. package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
  10. package/build/__tests__/impl/LslWebSocketBridge.test.js +6 -3
  11. package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
  12. package/build/impl/LslStreamInfo.d.ts +3 -9
  13. package/build/impl/LslStreamInfo.js +6 -16
  14. package/build/impl/LslStreamInfo.js.map +1 -1
  15. package/build/impl/LslStreamInlet.d.ts +4 -5
  16. package/build/impl/LslStreamInlet.js +2 -15
  17. package/build/impl/LslStreamInlet.js.map +1 -1
  18. package/build/impl/LslStreamOutlet.d.ts +3 -3
  19. package/build/impl/LslStreamOutlet.js +5 -8
  20. package/build/impl/LslStreamOutlet.js.map +1 -1
  21. package/build/impl/LslWebSocketBridge.d.ts +2 -1
  22. package/build/impl/LslWebSocketBridge.js +1 -1
  23. package/build/impl/LslWebSocketBridge.js.map +1 -1
  24. package/build/scripts/runLslStreamOutlet.js +15 -10
  25. package/build/scripts/runLslStreamOutlet.js.map +1 -1
  26. package/build/scripts/runOutletToInlet.js +1 -6
  27. package/build/scripts/runOutletToInlet.js.map +1 -1
  28. package/build/testDoubles/StreamInfo/FakeStreamInfo.d.ts +4 -4
  29. package/build/testDoubles/StreamInfo/FakeStreamInfo.js +3 -3
  30. package/build/testDoubles/StreamInfo/FakeStreamInfo.js.map +1 -1
  31. package/build/testDoubles/StreamInfo/SpyStreamInfo.d.ts +0 -1
  32. package/build/testDoubles/StreamInfo/SpyStreamInfo.js +0 -3
  33. package/build/testDoubles/StreamInfo/SpyStreamInfo.js.map +1 -1
  34. package/build/testDoubles/StreamInlet/FakeStreamInlet.d.ts +3 -3
  35. package/build/testDoubles/StreamInlet/FakeStreamInlet.js.map +1 -1
  36. package/build/testDoubles/StreamInlet/SpyStreamInlet.d.ts +2 -2
  37. package/build/testDoubles/StreamInlet/SpyStreamInlet.js.map +1 -1
  38. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.d.ts +1 -0
  39. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js +3 -0
  40. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js.map +1 -1
  41. package/package.json +11 -11
  42. package/src/__tests__/AbstractPackageTest.ts +2 -6
  43. package/src/__tests__/impl/LslStreamInfo.test.ts +10 -10
  44. package/src/__tests__/impl/LslStreamInlet.test.ts +2 -36
  45. package/src/__tests__/impl/LslWebSocketBridge.test.ts +7 -5
  46. package/src/impl/LslStreamInfo.ts +13 -27
  47. package/src/impl/LslStreamInlet.ts +8 -22
  48. package/src/impl/LslStreamOutlet.ts +6 -9
  49. package/src/impl/LslWebSocketBridge.ts +4 -4
  50. package/src/scripts/runLslStreamOutlet.ts +16 -10
  51. package/src/scripts/runOutletToInlet.ts +1 -6
  52. package/src/testDoubles/StreamInfo/FakeStreamInfo.ts +5 -5
  53. package/src/testDoubles/StreamInfo/SpyStreamInfo.ts +0 -4
  54. package/src/testDoubles/StreamInlet/FakeStreamInlet.ts +6 -3
  55. package/src/testDoubles/StreamInlet/SpyStreamInlet.ts +2 -2
  56. package/src/testDoubles/StreamOutlet/FakeStreamOutlet.ts +4 -0
@@ -17,26 +17,20 @@ export default class LslStreamInfo implements StreamInfo {
17
17
  public readonly channelFormat: ChannelFormat
18
18
  public readonly sampleRateHz: number
19
19
  public readonly units: string
20
-
21
- protected boundInfo!: BoundStreamInfo
22
-
23
- private readonly defaultName = `lsl-stream-info-${generateId()}`
24
- private readonly defaultType = generateId()
25
- private readonly defaultSourceId = generateId()
26
- private readonly defaultUnits = 'N/A'
20
+ public readonly boundInfo: BoundStreamInfo
27
21
 
28
22
  private lsl = LiblslAdapter.getInstance()
29
23
 
30
24
  protected constructor(options: StreamInfoOptions) {
31
25
  const {
32
- name = this.defaultName,
33
- type = this.defaultType,
34
- sourceId = this.defaultSourceId,
26
+ name = `lsl-stream-info-${generateId()}`,
27
+ type = generateId(),
28
+ sourceId = generateId(),
35
29
  channelNames,
36
30
  channelFormat,
37
31
  sampleRateHz,
38
- units = this.defaultUnits,
39
- boundStreamInfo,
32
+ units = 'N/A',
33
+ boundInfo,
40
34
  } = options
41
35
 
42
36
  this.name = name
@@ -48,18 +42,18 @@ export default class LslStreamInfo implements StreamInfo {
48
42
  this.sampleRateHz = sampleRateHz
49
43
  this.units = units
50
44
 
51
- if (!boundStreamInfo) {
52
- this.createStreamInfo()
45
+ if (!boundInfo) {
46
+ this.boundInfo = this.createStreamInfo()
53
47
  this.appendChannelsToStreamInfo()
54
48
  } else {
55
- this.boundInfo = boundStreamInfo
49
+ this.boundInfo = boundInfo
56
50
  }
57
51
  }
58
52
 
59
53
  public static Create(options: StreamInfoOptions) {
60
54
  const instance = new (this.Class ?? this)(options)
61
55
 
62
- const { boundStreamInfo: handle } = instance
56
+ const { boundInfo: handle } = instance
63
57
  this.instanceCache.set(handle, instance)
64
58
 
65
59
  return instance
@@ -70,7 +64,7 @@ export default class LslStreamInfo implements StreamInfo {
70
64
  }
71
65
 
72
66
  private createStreamInfo() {
73
- this.boundInfo = this.lsl.createStreamInfo({
67
+ return this.lsl.createStreamInfo({
74
68
  name: this.name,
75
69
  type: this.type,
76
70
  sourceId: this.sourceId,
@@ -98,14 +92,6 @@ export default class LslStreamInfo implements StreamInfo {
98
92
  public destroy() {
99
93
  this.lsl.destroyStreamInfo({ info: this.boundInfo })
100
94
  }
101
-
102
- public get boundStreamInfo() {
103
- return this.boundInfo
104
- }
105
-
106
- public set boundStreamInfo(boundInfo: BoundStreamInfo) {
107
- this.boundInfo = boundInfo
108
- }
109
95
  }
110
96
 
111
97
  export interface StreamInfo {
@@ -118,7 +104,7 @@ export interface StreamInfo {
118
104
  readonly channelCount: number
119
105
  readonly channelFormat: ChannelFormat
120
106
  readonly sampleRateHz: number
121
- boundStreamInfo: BoundStreamInfo
107
+ readonly boundInfo: BoundStreamInfo
122
108
  }
123
109
 
124
110
  type StreamInfoConstructor = new (options: StreamInfoOptions) => StreamInfo
@@ -131,5 +117,5 @@ export interface StreamInfoOptions {
131
117
  type?: string
132
118
  sourceId?: string
133
119
  units?: string
134
- boundStreamInfo?: BoundStreamInfo
120
+ boundInfo?: BoundStreamInfo
135
121
  }
@@ -3,7 +3,7 @@ import { createPointer, DataType, JsExternal, unwrapPointer } from 'ffi-rs'
3
3
  import handleError from '../handleError.js'
4
4
  import { BoundInlet } from './LiblslAdapter.js'
5
5
  import LiblslAdapter from './LiblslAdapter.js'
6
- import LslStreamInfo, { StreamInfo } from './LslStreamInfo.js'
6
+ import { StreamInfo } from './LslStreamInfo.js'
7
7
 
8
8
  export default class LslStreamInlet implements StreamInlet {
9
9
  public static Class?: StreamInletConstructor
@@ -39,7 +39,7 @@ export default class LslStreamInlet implements StreamInlet {
39
39
 
40
40
  protected constructor(
41
41
  info: StreamInfo,
42
- options: StreamInletOptions,
42
+ options: StreamInletConstructorOptions,
43
43
  onData: OnDataCallback
44
44
  ) {
45
45
  const { chunkSize, maxBufferedMs, timeoutMs } = options ?? {}
@@ -59,8 +59,7 @@ export default class LslStreamInlet implements StreamInlet {
59
59
  options: StreamInletOptions,
60
60
  onData: OnDataCallback
61
61
  ) {
62
- const { sourceId } = options
63
- const info = await this.LslStreamInfo(sourceId)
62
+ const { info } = options
64
63
  return new (this.Class ?? this)(info, options, onData)
65
64
  }
66
65
 
@@ -74,15 +73,11 @@ export default class LslStreamInlet implements StreamInlet {
74
73
 
75
74
  private createBoundInlet() {
76
75
  this.inlet = this.lsl.createInlet({
77
- info: this.boundStreamInfo,
76
+ info: this.info.boundInfo,
78
77
  maxBufferedMs: this.maxBufferedMs,
79
78
  })
80
79
  }
81
80
 
82
- private get boundStreamInfo() {
83
- return this.info.boundStreamInfo
84
- }
85
-
86
81
  public startPulling() {
87
82
  this.isRunning = true
88
83
 
@@ -249,17 +244,6 @@ export default class LslStreamInlet implements StreamInlet {
249
244
  private destroyBoundInlet() {
250
245
  this.lsl.destroyInlet({ inlet: this.inlet })
251
246
  }
252
-
253
- private static async LslStreamInfo(sourceId: string) {
254
- const lsl = LiblslAdapter.getInstance()
255
-
256
- const handles = await lsl.resolveByProp({
257
- prop: 'source_id',
258
- value: sourceId,
259
- })
260
-
261
- return LslStreamInfo.From(handles[0])
262
- }
263
247
  }
264
248
 
265
249
  export interface StreamInlet {
@@ -272,17 +256,19 @@ export interface StreamInlet {
272
256
 
273
257
  export type StreamInletConstructor = new (
274
258
  info: StreamInfo,
275
- options: StreamInletOptions,
259
+ options: StreamInletConstructorOptions,
276
260
  onData: OnDataCallback
277
261
  ) => StreamInlet
278
262
 
279
263
  export interface StreamInletOptions {
280
- sourceId: string
264
+ info: StreamInfo
281
265
  chunkSize: number
282
266
  maxBufferedMs?: number
283
267
  timeoutMs?: number
284
268
  }
285
269
 
270
+ export type StreamInletConstructorOptions = Omit<StreamInletOptions, 'info'>
271
+
286
272
  export type OnDataCallback = (
287
273
  samples: Float32Array,
288
274
  timestamps: Float64Array
@@ -21,6 +21,7 @@ import LslStreamInfo, {
21
21
  export default class LslStreamOutlet implements StreamOutlet {
22
22
  public static Class?: StreamOutletConstructor
23
23
 
24
+ public readonly info: StreamInfo
24
25
  public readonly name: string
25
26
  public readonly type: string
26
27
  public readonly sourceId: string
@@ -33,7 +34,6 @@ export default class LslStreamOutlet implements StreamOutlet {
33
34
  public readonly manufacturer: string = 'N/A'
34
35
  public readonly units: string = 'N/A'
35
36
 
36
- private info: StreamInfo
37
37
  private boundOutlet!: BoundOutlet
38
38
  private pushSampleMethod!: (options: unknown) => LslErrorCode
39
39
 
@@ -109,16 +109,12 @@ export default class LslStreamOutlet implements StreamOutlet {
109
109
 
110
110
  private createStreamOutlet() {
111
111
  this.boundOutlet = this.lsl.createOutlet({
112
- info: this.boundStreamInfo,
112
+ info: this.info.boundInfo,
113
113
  chunkSize: this.chunkSize,
114
114
  maxBufferedMs: this.maxBufferedMs,
115
115
  })
116
116
  }
117
117
 
118
- private get boundStreamInfo() {
119
- return this.info.boundStreamInfo
120
- }
121
-
122
118
  private setPushSampleMethod() {
123
119
  this.pushSampleMethod = (
124
120
  this.lsl[this.pushMethod] as (options: unknown) => LslErrorCode
@@ -146,12 +142,12 @@ export default class LslStreamOutlet implements StreamOutlet {
146
142
  }
147
143
 
148
144
  public destroy() {
149
- this.destroyBoundStreamInfo()
145
+ this.destroyBoundInfo()
150
146
  this.destroyBoundOutlet()
151
147
  }
152
148
 
153
- private destroyBoundStreamInfo() {
154
- this.lsl.destroyStreamInfo({ info: this.boundStreamInfo })
149
+ private destroyBoundInfo() {
150
+ this.lsl.destroyStreamInfo({ info: this.info.boundInfo })
155
151
  }
156
152
 
157
153
  private destroyBoundOutlet() {
@@ -190,6 +186,7 @@ export default class LslStreamOutlet implements StreamOutlet {
190
186
  export interface StreamOutlet {
191
187
  pushSample(sample: LslSample): void
192
188
  destroy(): void
189
+ readonly info: StreamInfo
193
190
  readonly name: string
194
191
  readonly type: string
195
192
  readonly sourceId: string
@@ -1,4 +1,5 @@
1
1
  import WebSocket, { WebSocketServer } from 'ws'
2
+ import { StreamInfo } from './LslStreamInfo.js'
2
3
  import LslStreamInlet, {
3
4
  StreamInlet,
4
5
  StreamInletOptions,
@@ -153,7 +154,7 @@ export default class LslWebSocketBridge implements WebSocketBridge {
153
154
  return listenPort ? new this.WSS({ port: listenPort }) : undefined
154
155
  }
155
156
 
156
- private static LslStreamInlet(
157
+ private static async LslStreamInlet(
157
158
  options: StreamInletOptions,
158
159
  localServer?: WebSocketServer,
159
160
  remoteSockets?: WebSocket[]
@@ -174,14 +175,13 @@ export type WebSocketBridgeConstructor = new (
174
175
  ) => WebSocketBridge
175
176
 
176
177
  export interface WebSocketBridgeOptions {
177
- sourceId: string
178
+ info: StreamInfo
178
179
  chunkSize: number
179
180
  listenPort?: number
180
181
  connectUrls?: string | string[]
181
182
  }
182
183
 
183
- export interface WebSocketBridgeConstructorOptions
184
- extends WebSocketBridgeOptions {
184
+ export interface WebSocketBridgeConstructorOptions extends WebSocketBridgeOptions {
185
185
  inlet: StreamInlet
186
186
  localServer?: WebSocketServer
187
187
  remoteSockets?: WebSocket[]
@@ -1,19 +1,25 @@
1
1
  import LslStreamOutlet from '../impl/LslStreamOutlet.js'
2
2
 
3
3
  async function main() {
4
- const instance = await LslStreamOutlet.Create({
5
- name: 'Muse S (2nd gen)',
6
- type: 'EEG',
7
- channelNames: ['TP9', 'AF7', 'AF8', 'TP10', 'AUX'],
8
- sampleRateHz: 256,
4
+ const outlet = await LslStreamOutlet.Create({
5
+ name: '10 Hz Pulse',
6
+ type: 'HZ',
7
+ sourceId: '10-hz-pulse',
8
+ channelNames: ['Ch1', 'Ch2', 'Ch3'],
9
9
  channelFormat: 'float32',
10
- sourceId: 'muse-s-eeg',
11
- manufacturer: 'Interaxon Inc.',
12
- units: 'microvolt',
13
- chunkSize: 12,
10
+ sampleRateHz: 10,
11
+ chunkSize: 1,
14
12
  })
15
13
 
16
- instance.pushSample([1, 2, 3, 4, 5])
14
+ for (let i = 0; i < 100; i++) {
15
+ await new Promise((resolve) => setTimeout(resolve, 100))
16
+
17
+ outlet.pushSample([
18
+ Math.random() * 100,
19
+ Math.random() * 100,
20
+ Math.random() * 100,
21
+ ])
22
+ }
17
23
  }
18
24
 
19
25
  main().catch((error) => {
@@ -17,12 +17,7 @@ const outlet = await LslStreamOutlet.Create({
17
17
  console.log('Creating inlet...')
18
18
 
19
19
  const inletOptions = {
20
- name: 'TestOutlet',
21
- type: 'TEST',
22
- sourceId: 'TestOutletID',
23
- sampleRateHz: 100,
24
- channelNames: ['Ch1', 'Ch2', 'Ch3'],
25
- channelFormat: 'float32' as const,
20
+ info: outlet.info,
26
21
  chunkSize: 1,
27
22
  }
28
23
 
@@ -4,10 +4,10 @@ import { BoundStreamInfo } from 'impl/LiblslAdapter.js'
4
4
  import { StreamInfo, StreamInfoOptions } from '../../impl/LslStreamInfo.js'
5
5
 
6
6
  export default class FakeStreamInfo implements StreamInfo {
7
- public static callsToConstructor: StreamInfoOptions[] = []
7
+ public static callsToConstructor: (StreamInfoOptions | undefined)[] = []
8
8
  public static numCallsToDestroy = 0
9
9
 
10
- public static boundStreamInfo = {} as BoundStreamInfo
10
+ public static boundInfo = {} as BoundStreamInfo
11
11
 
12
12
  public name = generateId()
13
13
  public type = generateId()
@@ -17,7 +17,7 @@ export default class FakeStreamInfo implements StreamInfo {
17
17
  public sampleRateHz = 0
18
18
  public units = 'N/A'
19
19
 
20
- public constructor(options: StreamInfoOptions) {
20
+ public constructor(options?: StreamInfoOptions) {
21
21
  FakeStreamInfo.callsToConstructor.push(options)
22
22
  }
23
23
 
@@ -29,8 +29,8 @@ export default class FakeStreamInfo implements StreamInfo {
29
29
  return this.channelNames.length
30
30
  }
31
31
 
32
- public get boundStreamInfo() {
33
- return FakeStreamInfo.boundStreamInfo
32
+ public get boundInfo() {
33
+ return FakeStreamInfo.boundInfo
34
34
  }
35
35
 
36
36
  public static resetTestDouble() {
@@ -8,10 +8,6 @@ export default class SpyStreamInfo extends LslStreamInfo {
8
8
  SpyStreamInfo.numCallsToConstructor++
9
9
  }
10
10
 
11
- public getBoundInfo() {
12
- return this.boundInfo
13
- }
14
-
15
11
  public getName() {
16
12
  return this.name
17
13
  }
@@ -1,10 +1,13 @@
1
1
  import { StreamInfo } from '../../impl/LslStreamInfo.js'
2
- import { StreamInlet, StreamInletOptions } from '../../impl/LslStreamInlet.js'
2
+ import {
3
+ StreamInlet,
4
+ StreamInletConstructorOptions,
5
+ } from '../../impl/LslStreamInlet.js'
3
6
 
4
7
  export default class FakeStreamInlet implements StreamInlet {
5
8
  public static callsToConstructor: {
6
9
  info?: StreamInfo
7
- options?: StreamInletOptions
10
+ options?: StreamInletConstructorOptions
8
11
  onData?: (samples: Float32Array, timestamps: Float64Array) => void
9
12
  }[] = []
10
13
 
@@ -19,7 +22,7 @@ export default class FakeStreamInlet implements StreamInlet {
19
22
 
20
23
  public constructor(
21
24
  info?: StreamInfo,
22
- options?: StreamInletOptions,
25
+ options?: StreamInletConstructorOptions,
23
26
  onData?: (samples: Float32Array, timestamps: Float64Array) => void
24
27
  ) {
25
28
  this.onData = onData ?? (() => {})
@@ -1,13 +1,13 @@
1
1
  import { StreamInfo } from '../../impl/LslStreamInfo.js'
2
2
  import LslStreamInlet, {
3
3
  OnDataCallback,
4
- StreamInletOptions,
4
+ StreamInletConstructorOptions,
5
5
  } from '../../impl/LslStreamInlet.js'
6
6
 
7
7
  export class SpyStreamInlet extends LslStreamInlet {
8
8
  public constructor(
9
9
  info: StreamInfo,
10
- options: StreamInletOptions,
10
+ options: StreamInletConstructorOptions,
11
11
  onData: OnDataCallback
12
12
  ) {
13
13
  super(info, options, onData)
@@ -7,6 +7,7 @@ import {
7
7
  StreamOutlet,
8
8
  StreamOutletOptions,
9
9
  } from '../../impl/LslStreamOutlet.js'
10
+ import FakeStreamInfo from '../StreamInfo/FakeStreamInfo.js'
10
11
 
11
12
  export default class FakeStreamOutlet implements StreamOutlet {
12
13
  public static callsToConstructor: {
@@ -17,10 +18,13 @@ export default class FakeStreamOutlet implements StreamOutlet {
17
18
  public static callsToPushSample: LslSample[] = []
18
19
  public static numCallsToDestroy = 0
19
20
 
21
+ public info: StreamInfo
20
22
  public options?: StreamOutletOptions
21
23
 
22
24
  public constructor(info?: StreamInfo, options?: StreamOutletOptions) {
23
25
  FakeStreamOutlet.callsToConstructor.push({ info, options })
26
+
27
+ this.info = info ?? new FakeStreamInfo()
24
28
  this.options = options
25
29
  }
26
30