@neurodevs/node-lsl 14.0.0 → 14.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 (57) hide show
  1. package/build/__tests__/impl/LiblslAdapter.test.d.ts +7 -5
  2. package/build/__tests__/impl/LiblslAdapter.test.js +27 -10
  3. package/build/__tests__/impl/LiblslAdapter.test.js.map +1 -1
  4. package/build/__tests__/impl/LslEventMarkerOutlet.test.d.ts +1 -0
  5. package/build/__tests__/impl/LslEventMarkerOutlet.test.js +7 -0
  6. package/build/__tests__/impl/LslEventMarkerOutlet.test.js.map +1 -1
  7. package/build/__tests__/impl/LslStreamInfo.test.d.ts +1 -0
  8. package/build/__tests__/impl/LslStreamInfo.test.js +8 -1
  9. package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
  10. package/build/__tests__/impl/LslStreamInlet.test.d.ts +1 -0
  11. package/build/__tests__/impl/LslStreamInlet.test.js +8 -1
  12. package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
  13. package/build/__tests__/impl/LslStreamOutlet.test.d.ts +1 -0
  14. package/build/__tests__/impl/LslStreamOutlet.test.js +8 -0
  15. package/build/__tests__/impl/LslStreamOutlet.test.js.map +1 -1
  16. package/build/impl/LiblslAdapter.d.ts +8 -2
  17. package/build/impl/LiblslAdapter.js +10 -1
  18. package/build/impl/LiblslAdapter.js.map +1 -1
  19. package/build/impl/LslEventMarkerOutlet.d.ts +2 -0
  20. package/build/impl/LslEventMarkerOutlet.js +3 -0
  21. package/build/impl/LslEventMarkerOutlet.js.map +1 -1
  22. package/build/impl/LslStreamInfo.d.ts +11 -9
  23. package/build/impl/LslStreamInfo.js +17 -14
  24. package/build/impl/LslStreamInfo.js.map +1 -1
  25. package/build/impl/LslStreamInlet.d.ts +3 -0
  26. package/build/impl/LslStreamInlet.js +11 -1
  27. package/build/impl/LslStreamInlet.js.map +1 -1
  28. package/build/impl/LslStreamOutlet.d.ts +18 -17
  29. package/build/impl/LslStreamOutlet.js +61 -65
  30. package/build/impl/LslStreamOutlet.js.map +1 -1
  31. package/build/impl/LslWebSocketBridge.d.ts +1 -1
  32. package/build/impl/LslWebSocketBridge.js +2 -2
  33. package/build/impl/LslWebSocketBridge.js.map +1 -1
  34. package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +3 -1
  35. package/build/testDoubles/Liblsl/FakeLiblsl.js +4 -0
  36. package/build/testDoubles/Liblsl/FakeLiblsl.js.map +1 -1
  37. package/build/testDoubles/StreamInfo/FakeStreamInfo.d.ts +2 -0
  38. package/build/testDoubles/StreamInfo/FakeStreamInfo.js +5 -0
  39. package/build/testDoubles/StreamInfo/FakeStreamInfo.js.map +1 -1
  40. package/build/testDoubles/StreamInfo/SpyStreamInfo.d.ts +1 -1
  41. package/build/testDoubles/StreamInfo/SpyStreamInfo.js +2 -2
  42. package/build/testDoubles/StreamInfo/SpyStreamInfo.js.map +1 -1
  43. package/package.json +1 -1
  44. package/src/__tests__/impl/LiblslAdapter.test.ts +27 -5
  45. package/src/__tests__/impl/LslEventMarkerOutlet.test.ts +11 -0
  46. package/src/__tests__/impl/LslStreamInfo.test.ts +12 -1
  47. package/src/__tests__/impl/LslStreamInlet.test.ts +12 -1
  48. package/src/__tests__/impl/LslStreamOutlet.test.ts +12 -0
  49. package/src/impl/LiblslAdapter.ts +20 -4
  50. package/src/impl/LslEventMarkerOutlet.ts +5 -0
  51. package/src/impl/LslStreamInfo.ts +22 -17
  52. package/src/impl/LslStreamInlet.ts +14 -1
  53. package/src/impl/LslStreamOutlet.ts +94 -85
  54. package/src/impl/LslWebSocketBridge.ts +2 -2
  55. package/src/testDoubles/Liblsl/FakeLiblsl.ts +6 -0
  56. package/src/testDoubles/StreamInfo/FakeStreamInfo.ts +7 -0
  57. package/src/testDoubles/StreamInfo/SpyStreamInfo.ts +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"SpyStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/SpyStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,aAAoC,MAAM,6BAA6B,CAAA;AAE9E,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,aAAa;IACpD,YAAmB,OAA0B;QACzC,KAAK,CAAC,OAAO,CAAC,CAAA;IAClB,CAAC;IAEM,aAAa;QAChB,OAAO,IAAI,CAAC,UAAU,CAAA;IAC1B,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,WAAW;QACd,OAAO,IAAI,CAAC,QAAQ,CAAA;IACxB,CAAC;IAEM,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAA;IACrB,CAAC;CACJ"}
1
+ {"version":3,"file":"SpyStreamInfo.js","sourceRoot":"","sources":["../../../src/testDoubles/StreamInfo/SpyStreamInfo.ts"],"names":[],"mappings":"AAAA,OAAO,aAAoC,MAAM,6BAA6B,CAAA;AAE9E,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,aAAa;IACpD,YAAmB,OAA0B;QACzC,KAAK,CAAC,OAAO,CAAC,CAAA;IAClB,CAAC;IAEM,YAAY;QACf,OAAO,IAAI,CAAC,SAAS,CAAA;IACzB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,OAAO;QACV,OAAO,IAAI,CAAC,IAAI,CAAA;IACpB,CAAC;IAEM,WAAW;QACd,OAAO,IAAI,CAAC,QAAQ,CAAA;IACxB,CAAC;IAEM,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAA;IACrB,CAAC;CACJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neurodevs/node-lsl",
3
- "version": "14.0.0",
3
+ "version": "14.1.0",
4
4
  "description": "Lab Streaming Layer (LSL) bindings for Node",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -33,7 +33,9 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
33
33
  private static fakeInlet: BoundInlet = {}
34
34
  private static fakeDesc: BoundDescription
35
35
  private static fakeChildNamedChannels: BoundChild
36
+
36
37
  private static createStreamInfoParams?: any[]
38
+ private static destroyStreamInfoParams?: any[]
37
39
  private static appendChildParams: any[] = []
38
40
  private static createOutletParams?: any[]
39
41
  private static destroyOutletParams?: any[]
@@ -162,6 +164,11 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
162
164
  DataType.String,
163
165
  ],
164
166
  },
167
+ lsl_destroy_streaminfo: {
168
+ library: 'lsl',
169
+ retType: DataType.Void,
170
+ paramsType: [DataType.External],
171
+ },
165
172
  lsl_create_outlet: {
166
173
  library: 'lsl',
167
174
  retType: DataType.External,
@@ -233,7 +240,7 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
233
240
  }
234
241
 
235
242
  @test()
236
- protected static async canCreateStreamInfoWithRequiredParams() {
243
+ protected static async createsStreamInfoWithRequiredParams() {
237
244
  const options = this.generateRandomCreateStreamInfoOptions()
238
245
  const actual = this.instance.createStreamInfo(options)
239
246
 
@@ -242,7 +249,19 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
242
249
  }
243
250
 
244
251
  @test()
245
- protected static async canCreateOutletWithRequiredParams() {
252
+ protected static async destroysStreamInfoWithBoundInfo() {
253
+ const info = this.createRandomStreamInfo()
254
+ this.instance.destroyStreamInfo({ info })
255
+
256
+ assert.isEqualDeep(
257
+ this.destroyStreamInfoParams,
258
+ [info],
259
+ 'Did not call destroyStreamInfo with expected params!'
260
+ )
261
+ }
262
+
263
+ @test()
264
+ protected static async createsOutletWithRequiredParams() {
246
265
  const { options, outlet } = this.createRandomOutlet()
247
266
 
248
267
  const expected = {
@@ -255,7 +274,7 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
255
274
  }
256
275
 
257
276
  @test()
258
- protected static async canPushFloatSample() {
277
+ protected static async pushesFloatSample() {
259
278
  const expected = [1.0, 2.0, 3.0]
260
279
  const timestamp = randomInt(100)
261
280
  const options = {
@@ -273,7 +292,7 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
273
292
  }
274
293
 
275
294
  @test()
276
- protected static async canPushStringSample() {
295
+ protected static async pushesStringSample() {
277
296
  const expected = [this.generateId()]
278
297
  const timestamp = randomInt(100)
279
298
  const options = {
@@ -386,7 +405,7 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
386
405
  }
387
406
 
388
407
  @test()
389
- protected static async canCreateInletWithRequiredParams() {
408
+ protected static async createInletWithRequiredParams() {
390
409
  const { options, inlet } = this.createRandomInlet()
391
410
 
392
411
  const expected = {
@@ -604,6 +623,9 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
604
623
  this.createStreamInfoParams = params
605
624
  return this.fakeStreamInfo
606
625
  },
626
+ lsl_destroy_streaminfo: (params: any[]) => {
627
+ this.destroyStreamInfoParams = params
628
+ },
607
629
  lsl_create_outlet: (params: any[]) => {
608
630
  this.createOutletParams = params
609
631
  return this.fakeOutlet
@@ -148,6 +148,17 @@ export default class EventMarkerOutletTest extends AbstractPackageTest {
148
148
  assert.isEqual(FakeStreamOutlet.callsToPushSample[0][0], markerName)
149
149
  }
150
150
 
151
+ @test()
152
+ protected static async destroyCallsDestroyOnInternalStreamOutlet() {
153
+ this.instance.destroy()
154
+
155
+ assert.isEqual(
156
+ FakeStreamOutlet.numCallsToDestroy,
157
+ 1,
158
+ 'Did not call destroy on outlet!'
159
+ )
160
+ }
161
+
151
162
  private static get streamOutlet() {
152
163
  return this.instance.getStreamOutlet()
153
164
  }
@@ -170,7 +170,7 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
170
170
  assert.isEqualDeep(
171
171
  this.fakeLiblsl.lastAppendChannelsToStreamInfoOptions,
172
172
  {
173
- info: this.instance.getStreamInfo(),
173
+ info: this.instance.getBoundInfo(),
174
174
  channels: this.channelNames.map((label: string) => ({
175
175
  label,
176
176
  units: this.units,
@@ -181,6 +181,17 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
181
181
  )
182
182
  }
183
183
 
184
+ @test()
185
+ protected static async callsBindingsToDestroyStreamInfo() {
186
+ this.instance.destroy()
187
+
188
+ assert.isEqualDeep(
189
+ this.fakeLiblsl.lastDestroyStreamInfoOptions?.info,
190
+ this.instance.getBoundInfo(),
191
+ 'Should have called destroyStreamInfo!'
192
+ )
193
+ }
194
+
184
195
  private static readonly defaultOptions = {
185
196
  name: this.generateId(),
186
197
  type: this.generateId(),
@@ -90,7 +90,18 @@ export default class LslStreamInletTest extends AbstractPackageTest {
90
90
  assert.isEqualDeep(
91
91
  this.fakeLiblsl.lastDestroyInletOptions,
92
92
  { inlet: this.boundInlet },
93
- 'Should have called destroyInlet!'
93
+ 'Did not destroy inlet!'
94
+ )
95
+ }
96
+
97
+ @test()
98
+ protected static async destroyAlsoCallsDestroyStreamInfo() {
99
+ this.instance.destroy()
100
+
101
+ assert.isEqualDeep(
102
+ this.fakeLiblsl.lastDestroyStreamInfoOptions,
103
+ { info: this.instance.getStreamInfo().boundStreamInfo },
104
+ 'Did not destroy stream info!'
94
105
  )
95
106
  }
96
107
 
@@ -193,6 +193,18 @@ export default class LslStreamOutletTest extends AbstractPackageTest {
193
193
  assert.isEqual(this.fakeLiblsl.destroyOutletHitCount, 1)
194
194
  }
195
195
 
196
+ @test()
197
+ protected static async destroyAlsoCallsDestroyStreamInfo() {
198
+ const outlet = await this.LslStreamOutlet()
199
+ outlet.destroy()
200
+
201
+ assert.isEqualDeep(
202
+ this.fakeLiblsl.lastDestroyStreamInfoOptions,
203
+ { info: this.fakeLiblsl.streamInfo },
204
+ 'Did not call destroyStreamInfo on destroy!'
205
+ )
206
+ }
207
+
196
208
  @test()
197
209
  protected static async pushSampleShouldNotCreateMultipleOutlets() {
198
210
  const outlet = await this.FloatOutlet()
@@ -69,10 +69,10 @@ export default class LiblslAdapter implements Liblsl {
69
69
  const {
70
70
  name,
71
71
  type,
72
+ sourceId,
72
73
  channelCount,
73
- sampleRateHz,
74
74
  channelFormat,
75
- sourceId,
75
+ sampleRateHz,
76
76
  } = options
77
77
 
78
78
  return this.bindings.lsl_create_streaminfo([
@@ -85,6 +85,11 @@ export default class LiblslAdapter implements Liblsl {
85
85
  ])
86
86
  }
87
87
 
88
+ public destroyStreamInfo(options: DestroyStreamInfoOptions) {
89
+ const { info } = options
90
+ this.bindings.lsl_destroy_streaminfo([info])
91
+ }
92
+
88
93
  public appendChannelsToStreamInfo(
89
94
  options: AppendChannelsToStreamInfoOptions
90
95
  ) {
@@ -248,6 +253,11 @@ export default class LiblslAdapter implements Liblsl {
248
253
  DataType.String,
249
254
  ],
250
255
  },
256
+ lsl_destroy_streaminfo: {
257
+ library: 'lsl',
258
+ retType: DataType.Void,
259
+ paramsType: [DataType.External],
260
+ },
251
261
  lsl_create_outlet: {
252
262
  library: 'lsl',
253
263
  retType: DataType.External,
@@ -323,6 +333,7 @@ export interface Liblsl {
323
333
  liblslPath: string
324
334
 
325
335
  createStreamInfo(options: CreateStreamInfoOptions): BoundStreamInfo
336
+ destroyStreamInfo(options: DestroyStreamInfoOptions): void
326
337
  appendChannelsToStreamInfo(options: AppendChannelsToStreamInfoOptions): void
327
338
 
328
339
  createOutlet(options: CreateOutletOptions): BoundOutlet
@@ -349,10 +360,10 @@ export interface Liblsl {
349
360
  export interface CreateStreamInfoOptions {
350
361
  name: string
351
362
  type: string
363
+ sourceId: string
352
364
  channelCount: number
353
- sampleRateHz: number
354
365
  channelFormat: number
355
- sourceId: string
366
+ sampleRateHz: number
356
367
  manufacturer?: string
357
368
  units?: string
358
369
  }
@@ -368,6 +379,10 @@ export interface CreateOutletOptions {
368
379
  maxBufferedMs: number
369
380
  }
370
381
 
382
+ export interface DestroyStreamInfoOptions {
383
+ info: BoundStreamInfo
384
+ }
385
+
371
386
  export interface PushSampleFloatTimestampOptions {
372
387
  outlet: BoundOutlet
373
388
  sample: number[]
@@ -421,6 +436,7 @@ export interface LiblslBindings {
421
436
  args: [string, string, number, number, number, string]
422
437
  ): BoundStreamInfo
423
438
 
439
+ lsl_destroy_streaminfo(args: [BoundStreamInfo]): void
424
440
  lsl_create_outlet(args: [BoundStreamInfo, number, number]): BoundOutlet
425
441
  lsl_push_sample_ft(args: [BoundOutlet, LslSample, number]): LslErrorCode
426
442
  lsl_push_sample_strt(args: [BoundOutlet, LslSample, number]): LslErrorCode
@@ -74,12 +74,17 @@ export default class LslEventMarkerOutlet implements EventMarkerOutlet {
74
74
  clearTimeout(this.timeout)
75
75
  this.isPlaying = false
76
76
  }
77
+
78
+ public destroy() {
79
+ this.outlet.destroy()
80
+ }
77
81
  }
78
82
 
79
83
  export interface EventMarkerOutlet {
80
84
  pushMarker(markerName: string): void
81
85
  pushMarkers(markers: DurationMarker[]): Promise<void>
82
86
  stop(): void
87
+ destroy(): void
83
88
  }
84
89
 
85
90
  export type EventMarkerOutletConstructor = new (
@@ -11,11 +11,16 @@ export default class LslStreamInfo implements StreamInfo {
11
11
  protected type: string
12
12
  protected sourceId: string
13
13
  protected units: string
14
- protected streamInfo!: BoundStreamInfo
14
+ protected boundInfo!: BoundStreamInfo
15
15
  private channelNames: string[]
16
16
  private channelFormat: ChannelFormat
17
17
  private sampleRateHz: number
18
18
 
19
+ private readonly defaultName = `lsl-stream-info-${generateId()}`
20
+ private readonly defaultType = generateId()
21
+ private readonly defaultSourceId = generateId()
22
+ private readonly defaultUnits = 'N/A'
23
+
19
24
  protected constructor(options: StreamInfoOptions) {
20
25
  const {
21
26
  name = this.defaultName,
@@ -44,7 +49,7 @@ export default class LslStreamInfo implements StreamInfo {
44
49
  }
45
50
 
46
51
  private createStreamInfo() {
47
- this.streamInfo = this.lsl.createStreamInfo({
52
+ this.boundInfo = this.lsl.createStreamInfo({
48
53
  name: this.name,
49
54
  type: this.type,
50
55
  sourceId: this.sourceId,
@@ -54,9 +59,17 @@ export default class LslStreamInfo implements StreamInfo {
54
59
  })
55
60
  }
56
61
 
62
+ private get channelCount() {
63
+ return this.channelNames.length
64
+ }
65
+
66
+ private get lslChannelFormat() {
67
+ return CHANNEL_FORMATS_MAP[this.channelFormat]
68
+ }
69
+
57
70
  private appendChannelsToStreamInfo() {
58
71
  this.lsl.appendChannelsToStreamInfo({
59
- info: this.streamInfo,
72
+ info: this.boundInfo,
60
73
  channels: this.channelNames.map((label: string) => ({
61
74
  label,
62
75
  units: this.units,
@@ -65,30 +78,22 @@ export default class LslStreamInfo implements StreamInfo {
65
78
  })
66
79
  }
67
80
 
68
- public get boundStreamInfo() {
69
- return this.streamInfo
81
+ public destroy() {
82
+ this.lsl.destroyStreamInfo({ info: this.boundInfo })
70
83
  }
71
84
 
72
- private get channelCount() {
73
- return this.channelNames.length
74
- }
75
-
76
- private get lslChannelFormat() {
77
- return CHANNEL_FORMATS_MAP[this.channelFormat]
85
+ public get boundStreamInfo() {
86
+ return this.boundInfo
78
87
  }
79
88
 
80
89
  private get lsl() {
81
90
  return LiblslAdapter.getInstance()
82
91
  }
83
-
84
- private readonly defaultName = `lsl-stream-info-${generateId()}`
85
- private readonly defaultType = generateId()
86
- private readonly defaultSourceId = generateId()
87
- private readonly defaultUnits = 'N/A'
88
92
  }
89
93
 
90
94
  export interface StreamInfo {
91
- boundStreamInfo: BoundStreamInfo
95
+ destroy(): void
96
+ readonly boundStreamInfo: BoundStreamInfo
92
97
  }
93
98
 
94
99
  type StreamInfoConstructor = new (options: StreamInfoOptions) => StreamInfo
@@ -88,12 +88,16 @@ export default class LslStreamInlet implements StreamInlet {
88
88
 
89
89
  private createBoundInlet() {
90
90
  this.inlet = this.lsl.createInlet({
91
- info: this.info.boundStreamInfo,
91
+ info: this.boundStreamInfo,
92
92
  chunkSize: this.chunkSize,
93
93
  maxBufferedMs: this.maxBufferedMs / 1000,
94
94
  })
95
95
  }
96
96
 
97
+ private get boundStreamInfo() {
98
+ return this.info.boundStreamInfo
99
+ }
100
+
97
101
  public startPulling() {
98
102
  this.isRunning = true
99
103
 
@@ -250,6 +254,15 @@ export default class LslStreamInlet implements StreamInlet {
250
254
  }
251
255
 
252
256
  public destroy() {
257
+ this.destroyBoundStreamInfo()
258
+ this.destroyBoundInlet()
259
+ }
260
+
261
+ private destroyBoundStreamInfo() {
262
+ this.lsl.destroyStreamInfo({ info: this.boundStreamInfo })
263
+ }
264
+
265
+ private destroyBoundInlet() {
253
266
  this.lsl.destroyInlet({ inlet: this.inlet })
254
267
  }
255
268
 
@@ -21,14 +21,48 @@ import LslStreamInfo, {
21
21
  export default class LslStreamOutlet implements StreamOutlet {
22
22
  public static Class?: StreamOutletConstructor
23
23
 
24
+ public readonly name: string
25
+ public readonly type: string
26
+ public readonly sourceId: string
27
+ public readonly channelNames: string[]
28
+ public readonly channelFormat: ChannelFormat
29
+ public readonly channelCount: number
30
+ public readonly sampleRateHz: number
31
+ public readonly chunkSize: number
32
+ public readonly maxBufferedMs = 360 * 1000
33
+ public readonly manufacturer: string = 'N/A'
34
+ public readonly units: string = 'N/A'
35
+
24
36
  private info: StreamInfo
25
- private options: StreamOutletOptions
26
37
  private outlet!: BoundOutlet
27
38
  private pushSampleMethod!: (options: unknown) => LslErrorCode
28
39
 
29
40
  protected constructor(info: StreamInfo, options: StreamOutletOptions) {
41
+ const {
42
+ name,
43
+ type,
44
+ sourceId,
45
+ channelNames,
46
+ channelFormat,
47
+ sampleRateHz,
48
+ chunkSize,
49
+ maxBufferedMs,
50
+ manufacturer,
51
+ units,
52
+ } = options
53
+
30
54
  this.info = info
31
- this.options = options
55
+ this.name = name
56
+ this.type = type
57
+ this.sourceId = sourceId
58
+ this.channelNames = channelNames
59
+ this.channelFormat = channelFormat
60
+ this.channelCount = channelNames.length
61
+ this.sampleRateHz = sampleRateHz
62
+ this.chunkSize = chunkSize
63
+ this.maxBufferedMs = maxBufferedMs ?? this.maxBufferedMs
64
+ this.manufacturer = manufacturer ?? this.manufacturer
65
+ this.units = units ?? this.units
32
66
 
33
67
  this.validateOptions()
34
68
  this.createStreamOutlet()
@@ -38,20 +72,10 @@ export default class LslStreamOutlet implements StreamOutlet {
38
72
  public static async Create(options: StreamOutletOptions) {
39
73
  const { waitAfterConstructionMs = 10 } = options ?? {}
40
74
 
41
- const infoOptions = {
42
- channelNames: options.channelNames,
43
- channelFormat: options.channelFormat,
44
- sampleRateHz: options.sampleRateHz,
45
- name: options.name,
46
- type: options.type,
47
- sourceId: options.sourceId,
48
- units: options.units,
49
- }
50
-
51
- const info = this.LslStreamInfo(infoOptions)
75
+ const info = this.LslStreamInfo(options)
52
76
  const instance = new (this.Class ?? this)(info, options)
53
77
 
54
- await this.wait(waitAfterConstructionMs)
78
+ await this.waitToAllowSetup(waitAfterConstructionMs)
55
79
 
56
80
  return instance
57
81
  }
@@ -62,6 +86,23 @@ export default class LslStreamOutlet implements StreamOutlet {
62
86
  assertValidChannelFormat(this.channelFormat)
63
87
  assertValidChunkSize(this.chunkSize)
64
88
  assertValidMaxBufferedMs(this.maxBufferedMs)
89
+ this.validateChannelFormat()
90
+ }
91
+
92
+ private validateChannelFormat() {
93
+ if (!this.isChannelFormatSupported) {
94
+ this.throwUnsupportedChannelFormat()
95
+ }
96
+ }
97
+
98
+ private get isChannelFormatSupported() {
99
+ return this.channelFormat in this.methodMap
100
+ }
101
+
102
+ private throwUnsupportedChannelFormat() {
103
+ throw new Error(
104
+ `This method currently does not support the ${this.channelFormat} type! Please implement it.`
105
+ )
65
106
  }
66
107
 
67
108
  private createStreamOutlet() {
@@ -72,28 +113,16 @@ export default class LslStreamOutlet implements StreamOutlet {
72
113
  })
73
114
  }
74
115
 
75
- private setPushSampleMethod() {
76
- this.validateChannelFormat()
116
+ private get boundStreamInfo() {
117
+ return this.info.boundStreamInfo
118
+ }
77
119
 
120
+ private setPushSampleMethod() {
78
121
  this.pushSampleMethod = (
79
122
  this.lsl[this.pushMethod] as (options: unknown) => LslErrorCode
80
123
  ).bind(this.lsl)
81
124
  }
82
125
 
83
- private validateChannelFormat() {
84
- if (!(this.channelFormat in this.methodMap)) {
85
- this.throwUnsupportedChannelFormat()
86
- }
87
- }
88
-
89
- private throwUnsupportedChannelFormat() {
90
- throw new Error(this.unsupportedChannelMessage)
91
- }
92
-
93
- private get unsupportedChannelMessage() {
94
- return `This method currently does not support the ${this.channelFormat} type! Please implement it.`
95
- }
96
-
97
126
  private get pushMethod() {
98
127
  return this.methodMap[this.channelFormat]
99
128
  }
@@ -106,77 +135,57 @@ export default class LslStreamOutlet implements StreamOutlet {
106
135
  public pushSample(sample: LslSample) {
107
136
  const timestamp = this.lsl.localClock()
108
137
 
109
- handleError(
110
- this.pushSampleMethod({
111
- outlet: this.outlet,
112
- sample,
113
- timestamp,
114
- })
115
- )
138
+ const err = this.pushSampleMethod({
139
+ outlet: this.outlet,
140
+ sample,
141
+ timestamp,
142
+ })
143
+ handleError(err)
116
144
  }
117
145
 
118
146
  public destroy() {
119
- this.lsl.destroyOutlet({ outlet: this.outlet })
120
- }
121
-
122
- public get name() {
123
- return this.options.name
124
- }
125
-
126
- public get type() {
127
- return this.options.type
128
- }
129
-
130
- public get sourceId() {
131
- return this.options.sourceId
132
- }
133
-
134
- public get channelNames() {
135
- return this.options.channelNames
136
- }
137
-
138
- public get channelCount() {
139
- return this.channelNames.length
147
+ this.destroyBoundStreamInfo()
148
+ this.destroyBoundOutlet()
140
149
  }
141
150
 
142
- public get channelFormat() {
143
- return this.options.channelFormat
151
+ private destroyBoundStreamInfo() {
152
+ this.lsl.destroyStreamInfo({ info: this.boundStreamInfo })
144
153
  }
145
154
 
146
- public get sampleRateHz() {
147
- return this.options.sampleRateHz
148
- }
149
-
150
- public get chunkSize() {
151
- return this.options.chunkSize
152
- }
153
-
154
- public get maxBufferedMs() {
155
- return this.options.maxBufferedMs ?? 360 * 1000
156
- }
157
-
158
- public get manufacturer() {
159
- return this.options.manufacturer ?? 'N/A'
160
- }
161
-
162
- public get units() {
163
- return this.options.units ?? 'N/A'
164
- }
165
-
166
- private get boundStreamInfo() {
167
- return this.info.boundStreamInfo
155
+ private destroyBoundOutlet() {
156
+ this.lsl.destroyOutlet({ outlet: this.outlet })
168
157
  }
169
158
 
170
159
  private get lsl() {
171
160
  return LiblslAdapter.getInstance()
172
161
  }
173
162
 
174
- private static async wait(waitMs: number) {
175
- return new Promise((resolve) => setTimeout(resolve, waitMs))
163
+ private static async waitToAllowSetup(waitAfterConstructionMs: number) {
164
+ await new Promise((resolve) =>
165
+ setTimeout(resolve, waitAfterConstructionMs)
166
+ )
176
167
  }
177
168
 
178
169
  private static LslStreamInfo(options: StreamInfoOptions) {
179
- return LslStreamInfo.Create(options)
170
+ const {
171
+ channelNames,
172
+ channelFormat,
173
+ sampleRateHz,
174
+ name,
175
+ type,
176
+ sourceId,
177
+ units,
178
+ } = options
179
+
180
+ return LslStreamInfo.Create({
181
+ name,
182
+ type,
183
+ sourceId,
184
+ channelNames,
185
+ channelFormat,
186
+ sampleRateHz,
187
+ units,
188
+ })
180
189
  }
181
190
  }
182
191
 
@@ -51,12 +51,12 @@ export default class LslWebSocketBridge implements WebSocketBridge {
51
51
  }
52
52
 
53
53
  public destroy() {
54
- this.destroyCppBoundInlet()
54
+ this.destroyBoundInlet()
55
55
  this.closeWebSocketServer()
56
56
  this.isDestroyed = true
57
57
  }
58
58
 
59
- private destroyCppBoundInlet() {
59
+ private destroyBoundInlet() {
60
60
  this.inlet.destroy()
61
61
  }
62
62
 
@@ -15,6 +15,7 @@ import {
15
15
  FlushInletOptions,
16
16
  PullChunkOptions,
17
17
  PullSampleOptions,
18
+ DestroyStreamInfoOptions,
18
19
  } from 'impl/LiblslAdapter.js'
19
20
 
20
21
  export default class FakeLiblsl implements Liblsl {
@@ -45,6 +46,7 @@ export default class FakeLiblsl implements Liblsl {
45
46
  public streamInfo: BoundStreamInfo = {} as BoundStreamInfo
46
47
 
47
48
  public lastCreateStreamInfoOptions?: CreateStreamInfoOptions
49
+ public lastDestroyStreamInfoOptions?: DestroyStreamInfoOptions
48
50
  public lastAppendChannelsToStreamInfoOptions?: AppendChannelsToStreamInfoOptions
49
51
  public lastCreateOutletOptions?: CreateOutletOptions
50
52
  public lastPushSampleFloatTimestampOptions?: PushSampleFloatTimestampOptions
@@ -70,6 +72,10 @@ export default class FakeLiblsl implements Liblsl {
70
72
  return this.streamInfo
71
73
  }
72
74
 
75
+ public destroyStreamInfo(options: DestroyStreamInfoOptions) {
76
+ this.lastDestroyStreamInfoOptions = options
77
+ }
78
+
73
79
  public appendChannelsToStreamInfo(
74
80
  options: AppendChannelsToStreamInfoOptions
75
81
  ) {