@neurodevs/node-lsl 16.0.2 → 16.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 (34) hide show
  1. package/build/__tests__/AbstractPackageTest.js +0 -2
  2. package/build/__tests__/AbstractPackageTest.js.map +1 -1
  3. package/build/__tests__/impl/LiblslAdapter.test.d.ts +15 -1
  4. package/build/__tests__/impl/LiblslAdapter.test.js +111 -9
  5. package/build/__tests__/impl/LiblslAdapter.test.js.map +1 -1
  6. package/build/__tests__/impl/LslStreamInfo.test.d.ts +2 -1
  7. package/build/__tests__/impl/LslStreamInfo.test.js +16 -6
  8. package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
  9. package/build/__tests__/impl/LslStreamInlet.test.js +5 -5
  10. package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
  11. package/build/__tests__/impl/LslWebSocketBridge.test.js +1 -0
  12. package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
  13. package/build/impl/LiblslAdapter.d.ts +16 -5
  14. package/build/impl/LiblslAdapter.js +60 -8
  15. package/build/impl/LiblslAdapter.js.map +1 -1
  16. package/build/impl/LslStreamInfo.d.ts +1 -1
  17. package/build/impl/LslStreamInfo.js +9 -20
  18. package/build/impl/LslStreamInfo.js.map +1 -1
  19. package/build/impl/LslStreamInlet.d.ts +3 -0
  20. package/build/impl/LslStreamInlet.js +7 -8
  21. package/build/impl/LslStreamInlet.js.map +1 -1
  22. package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +8 -4
  23. package/build/testDoubles/Liblsl/FakeLiblsl.js +12 -4
  24. package/build/testDoubles/Liblsl/FakeLiblsl.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/__tests__/AbstractPackageTest.ts +0 -4
  27. package/src/__tests__/impl/LiblslAdapter.test.ts +149 -10
  28. package/src/__tests__/impl/LslStreamInfo.test.ts +20 -6
  29. package/src/__tests__/impl/LslStreamInlet.test.ts +5 -5
  30. package/src/__tests__/impl/LslWebSocketBridge.test.ts +1 -0
  31. package/src/impl/LiblslAdapter.ts +96 -15
  32. package/src/impl/LslStreamInfo.ts +9 -31
  33. package/src/impl/LslStreamInlet.ts +12 -9
  34. package/src/testDoubles/Liblsl/FakeLiblsl.ts +18 -6
@@ -18,6 +18,7 @@ import {
18
18
  Liblsl,
19
19
  LiblslBindings,
20
20
  LslChannel,
21
+ ResolveByPropOptions,
21
22
  } from 'impl/LiblslAdapter.js'
22
23
  import LiblslAdapter from '../../impl/LiblslAdapter.js'
23
24
  import FakeLiblsl from '../../testDoubles/Liblsl/FakeLiblsl.js'
@@ -97,7 +98,7 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
97
98
 
98
99
  LiblslAdapter.load = (options) => {
99
100
  this.ffiRsLoadOptions = options
100
- return {} as any
101
+ return this.fakeNumResolveResults as any
101
102
  }
102
103
 
103
104
  LiblslAdapter.resetInstance()
@@ -200,7 +201,12 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
200
201
  lsl_create_inlet: {
201
202
  library: 'lsl',
202
203
  retType: DataType.External,
203
- paramsType: [DataType.External, DataType.I32, DataType.I32],
204
+ paramsType: [
205
+ DataType.External,
206
+ DataType.I32,
207
+ DataType.I32,
208
+ DataType.I32,
209
+ ],
204
210
  },
205
211
  lsl_flush_inlet: {
206
212
  library: 'lsl',
@@ -260,6 +266,89 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
260
266
  )
261
267
  }
262
268
 
269
+ @test()
270
+ protected static async resolvesStreamInfoByProp() {
271
+ await this.resolveByProp()
272
+
273
+ assert.isEqualDeep(
274
+ this.ffiRsLoadOptions,
275
+ {
276
+ library: 'lsl',
277
+ funcName: 'lsl_resolve_byprop',
278
+ retType: DataType.I32,
279
+ paramsType: [
280
+ DataType.External,
281
+ DataType.I32,
282
+ DataType.String,
283
+ DataType.String,
284
+ DataType.I32,
285
+ DataType.Double,
286
+ ],
287
+ paramsValue: [
288
+ this.resultsBufferPtr,
289
+ this.maxResults,
290
+ this.prop,
291
+ this.value,
292
+ this.minResults,
293
+ this.timeoutMs / 1000,
294
+ ],
295
+ runInNewThread: true,
296
+ },
297
+ 'Did not call resolveByProp with expected params!'
298
+ )
299
+ }
300
+
301
+ @test()
302
+ protected static async resolveByPropAcceptsOptionalArgs() {
303
+ const minResults = randomInt(0, 10)
304
+ const timeoutMs = Math.random() * 1000
305
+
306
+ await this.resolveByProp({
307
+ minResults,
308
+ timeoutMs,
309
+ })
310
+
311
+ assert.isEqualDeep(
312
+ {
313
+ minResults: this.ffiRsLoadOptions?.['paramsValue']?.[4],
314
+ timeoutMs: this.ffiRsLoadOptions?.['paramsValue']?.[5],
315
+ },
316
+ { minResults, timeoutMs: timeoutMs / 1000 },
317
+ 'Did not call resolveByProp with expected params!'
318
+ )
319
+ }
320
+
321
+ @test()
322
+ protected static async returnsHandlesForResolvedStreamInfos() {
323
+ LiblslAdapter.alloc = (size: number) => {
324
+ const buffer = Buffer.alloc(size)
325
+
326
+ for (let i = 0; i < this.fakeNumResolveResults; i++) {
327
+ const offset = i * this.bytesPerPointer
328
+ buffer.writeBigUInt64LE(BigInt(i + 1), offset)
329
+ }
330
+
331
+ return buffer
332
+ }
333
+
334
+ const expectedHandles: bigint[] = []
335
+
336
+ for (let i = 0; i < this.fakeNumResolveResults; i++) {
337
+ expectedHandles.push(BigInt(i + 1))
338
+ }
339
+
340
+ const actualHandles = await this.resolveByProp()
341
+
342
+ const actual = actualHandles.map((h) => h.toString())
343
+ const expected = expectedHandles.map((h) => h.toString())
344
+
345
+ assert.isEqualDeep(
346
+ actual,
347
+ expected,
348
+ 'Did not receive expected resolved stream info handles!'
349
+ )
350
+ }
351
+
263
352
  @test()
264
353
  protected static async createsOutletWithRequiredParams() {
265
354
  const { options, outlet } = this.createRandomOutlet()
@@ -396,7 +485,7 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
396
485
  delete process.env.LIBLSL_PATH
397
486
 
398
487
  LiblslAdapter.resetInstance()
399
- this.instance = LiblslAdapter.getInstance()
488
+ this.instance = LiblslAdapter.getInstance() as FakeLiblsl
400
489
 
401
490
  assert.isEqual(
402
491
  this.ffiRsOpenOptions?.path,
@@ -407,14 +496,23 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
407
496
  @test()
408
497
  protected static async createInletWithRequiredParams() {
409
498
  const { options, inlet } = this.createRandomInlet()
499
+ const { maxBufferedMs } = options
410
500
 
411
501
  const expected = {
412
502
  ...options,
413
- maxBufferedMs: options.maxBufferedMs / 1000,
503
+ maxBufferedMs: maxBufferedMs / 1000,
414
504
  }
415
505
 
416
- assert.isEqualDeep(this.createInletParams, Object.values(expected))
417
- assert.isEqual(inlet, this.fakeInlet)
506
+ const maxChunkSize = 0
507
+ const shouldRecover = 1
508
+
509
+ assert.isEqualDeep(
510
+ this.createInletParams,
511
+ [...Object.values(expected), maxChunkSize, shouldRecover],
512
+ 'Did not call createInlet with expected params!'
513
+ )
514
+
515
+ assert.isEqual(inlet, this.fakeInlet, 'Did not receive expected inlet!')
418
516
  }
419
517
 
420
518
  @test()
@@ -572,23 +670,44 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
572
670
  )
573
671
  }
574
672
 
673
+ private static async resolveByProp(
674
+ options?: Partial<ResolveByPropOptions>
675
+ ) {
676
+ return this.instance.resolveByProp({
677
+ prop: this.prop,
678
+ value: this.value,
679
+ minResults: this.minResults,
680
+ timeoutMs: this.timeoutMs,
681
+ ...options,
682
+ })
683
+ }
684
+
575
685
  private static createRandomOutlet() {
576
- const options = this.createRandomOptions()
686
+ const options = this.createRandomOutletOptions()
577
687
  const outlet = this.instance.createOutlet(options)
578
688
  return { options, outlet }
579
689
  }
580
690
 
691
+ private static createRandomOutletOptions() {
692
+ const info = this.createRandomStreamInfo()
693
+ const options = {
694
+ info,
695
+ chunkSize: randomInt(10),
696
+ maxBufferedMs: randomInt(10),
697
+ }
698
+ return options
699
+ }
700
+
581
701
  private static createRandomInlet() {
582
- const options = this.createRandomOptions()
702
+ const options = this.createRandomInletOptions()
583
703
  const inlet = this.instance.createInlet(options)
584
704
  return { options, inlet }
585
705
  }
586
706
 
587
- private static createRandomOptions() {
707
+ private static createRandomInletOptions() {
588
708
  const info = this.createRandomStreamInfo()
589
709
  const options = {
590
710
  info,
591
- chunkSize: randomInt(10),
592
711
  maxBufferedMs: randomInt(10),
593
712
  }
594
713
  return options
@@ -613,6 +732,26 @@ export default class LiblslAdapterTest extends AbstractPackageTest {
613
732
  }
614
733
  }
615
734
 
735
+ // resolveByProp
736
+ private static readonly maxResults = 1024
737
+ private static readonly bytesPerPointer = 8
738
+ private static readonly minResults = 1
739
+ private static readonly timeoutMs = 1000
740
+ private static readonly prop = this.generateId()
741
+ private static readonly value = this.generateId()
742
+ private static readonly fakeNumResolveResults = 2
743
+
744
+ private static readonly resultsBuffer = Buffer.alloc(
745
+ this.maxResults * this.bytesPerPointer
746
+ )
747
+
748
+ private static readonly resultsBufferPtr = unwrapPointer(
749
+ createPointer({
750
+ paramsType: [DataType.U8Array],
751
+ paramsValue: [this.resultsBuffer],
752
+ })
753
+ )[0]
754
+
616
755
  private static generateFailedMessage() {
617
756
  return `Loading the liblsl dylib failed! I tried to load it from ${process.env.LIBLSL_PATH}.`
618
757
  }
@@ -11,10 +11,9 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
11
11
  protected static async beforeEach() {
12
12
  await super.beforeEach()
13
13
 
14
+ this.setFakeLiblsl()
14
15
  this.setSpyStreamInfo()
15
16
 
16
- LslStreamInfo['instanceCache'] = {}
17
-
18
17
  this.instance = this.LslStreamInfo()
19
18
  }
20
19
 
@@ -220,13 +219,28 @@ export default class LslStreamInfoTest extends AbstractPackageTest {
220
219
  }
221
220
 
222
221
  @test()
223
- protected static async cachesInfoIfPassedSameOptions() {
224
- this.LslStreamInfo()
222
+ protected static async doesNotCreateNewStreamInfoIfPassedBoundStreamInfo() {
223
+ this.LslStreamInfo({
224
+ boundStreamInfo: this.instance.getBoundInfo(),
225
+ })
225
226
 
226
227
  assert.isEqual(
227
- SpyStreamInfo.numCallsToConstructor,
228
+ this.fakeLiblsl.createStreamInfoHitCount,
228
229
  1,
229
- 'Did not cache stream info!'
230
+ 'Should not have created new stream info!'
231
+ )
232
+ }
233
+
234
+ @test()
235
+ protected static async setsBoundStreamInfoWhenPassed() {
236
+ const instance = this.LslStreamInfo({
237
+ boundStreamInfo: this.instance.getBoundInfo(),
238
+ })
239
+
240
+ assert.isEqualDeep(
241
+ instance.getBoundInfo(),
242
+ this.instance.getBoundInfo(),
243
+ 'Should have set bound stream info!'
230
244
  )
231
245
  }
232
246
 
@@ -15,8 +15,9 @@ export default class LslStreamInletTest extends AbstractPackageTest {
15
15
  protected static async beforeEach() {
16
16
  await super.beforeEach()
17
17
 
18
- this.setSpyStreamInlet()
18
+ this.setFakeLiblsl()
19
19
  this.setFakeStreamInfo()
20
+ this.setSpyStreamInlet()
20
21
 
21
22
  this.callsToOnData = []
22
23
 
@@ -65,8 +66,7 @@ export default class LslStreamInletTest extends AbstractPackageTest {
65
66
  this.fakeLiblsl.lastCreateInletOptions,
66
67
  {
67
68
  info: fakeInfo.boundStreamInfo,
68
- chunkSize: this.chunkSize,
69
- maxBufferedMs: this.maxBufferedMs / 1000,
69
+ maxBufferedMs: this.maxBufferedMs,
70
70
  },
71
71
  'Should have called createInlet!'
72
72
  )
@@ -212,11 +212,11 @@ export default class LslStreamInletTest extends AbstractPackageTest {
212
212
  maxBufferedMs: undefined,
213
213
  })
214
214
 
215
- const sixMinutesInSeconds = 360
215
+ const sixMinutesInMs = 360 * 1000
216
216
 
217
217
  assert.isEqualDeep(
218
218
  this.fakeLiblsl.lastCreateInletOptions?.maxBufferedMs,
219
- sixMinutesInSeconds
219
+ sixMinutesInMs
220
220
  )
221
221
  }
222
222
 
@@ -17,6 +17,7 @@ export default class LslWebSocketBridgeTest extends AbstractPackageTest {
17
17
  protected static async beforeEach() {
18
18
  await super.beforeEach()
19
19
 
20
+ this.setFakeLiblsl()
20
21
  this.setFakeStreamInlet()
21
22
  this.setFakeWebSocket()
22
23
  this.setFakeWebSocketServer()
@@ -1,4 +1,12 @@
1
- import { DataType, define, JsExternal, load, open, unwrapPointer } from 'ffi-rs'
1
+ import {
2
+ createPointer,
3
+ DataType,
4
+ define,
5
+ JsExternal,
6
+ load,
7
+ open,
8
+ unwrapPointer,
9
+ } from 'ffi-rs'
2
10
 
3
11
  import { CHANNEL_FORMATS } from '../consts.js'
4
12
  import { LslErrorCode } from '../handleError.js'
@@ -7,6 +15,7 @@ export default class LiblslAdapter implements Liblsl {
7
15
  public static open = open
8
16
  public static define = define
9
17
  public static load = load
18
+ public static alloc = Buffer.alloc
10
19
 
11
20
  private static instance?: Liblsl
12
21
 
@@ -62,7 +71,7 @@ export default class LiblslAdapter implements Liblsl {
62
71
  }
63
72
 
64
73
  private defineLiblslBindings() {
65
- return this.define(this.liblslFuncs) as unknown as LiblslBindings
74
+ return this.define(this.liblslFuncs) as LiblslBindings
66
75
  }
67
76
 
68
77
  public createStreamInfo(options: CreateStreamInfoOptions) {
@@ -85,11 +94,6 @@ export default class LiblslAdapter implements Liblsl {
85
94
  ])
86
95
  }
87
96
 
88
- public destroyStreamInfo(options: DestroyStreamInfoOptions) {
89
- const { info } = options
90
- this.bindings.lsl_destroy_streaminfo([info])
91
- }
92
-
93
97
  public appendChannelsToStreamInfo(
94
98
  options: AppendChannelsToStreamInfoOptions
95
99
  ) {
@@ -110,6 +114,62 @@ export default class LiblslAdapter implements Liblsl {
110
114
  }
111
115
  }
112
116
 
117
+ public destroyStreamInfo(options: DestroyStreamInfoOptions) {
118
+ const { info } = options
119
+ this.bindings.lsl_destroy_streaminfo([info])
120
+ }
121
+
122
+ public async resolveByProp(options: ResolveByPropOptions) {
123
+ const { prop, value, minResults = 1, timeoutMs = 1000 } = options
124
+
125
+ const maxResults = 1024
126
+ const bytesPerPointer = 8
127
+
128
+ const resultsBuffer = this.alloc(maxResults * bytesPerPointer)
129
+
130
+ const resultsBufferPtr = unwrapPointer(
131
+ createPointer({
132
+ paramsType: [DataType.U8Array],
133
+ paramsValue: [resultsBuffer],
134
+ })
135
+ )[0]
136
+
137
+ const numResults = await this.load({
138
+ library: 'lsl',
139
+ funcName: 'lsl_resolve_byprop',
140
+ retType: DataType.I32,
141
+ paramsType: [
142
+ DataType.External,
143
+ DataType.I32,
144
+ DataType.String,
145
+ DataType.String,
146
+ DataType.I32,
147
+ DataType.Double,
148
+ ],
149
+ paramsValue: [
150
+ resultsBufferPtr,
151
+ maxResults,
152
+ prop,
153
+ value,
154
+ minResults,
155
+ timeoutMs / 1000,
156
+ ],
157
+ runInNewThread: true,
158
+ })
159
+
160
+ const handles: bigint[] = []
161
+
162
+ for (let i = 0; i < numResults; i++) {
163
+ const handle = resultsBuffer.readBigUInt64LE(i * bytesPerPointer)
164
+
165
+ if (handle !== 0n) {
166
+ handles.push(handle)
167
+ }
168
+ }
169
+
170
+ return handles
171
+ }
172
+
113
173
  public createOutlet(options: CreateOutletOptions) {
114
174
  const { info, chunkSize, maxBufferedMs } = options
115
175
 
@@ -138,15 +198,19 @@ export default class LiblslAdapter implements Liblsl {
138
198
  }
139
199
 
140
200
  public createInlet(options: CreateInletOptions) {
141
- const { info, chunkSize, maxBufferedMs } = options
201
+ const { info, maxBufferedMs } = options
142
202
 
143
203
  return this.bindings.lsl_create_inlet([
144
204
  info,
145
- chunkSize,
146
205
  maxBufferedMs / 1000,
206
+ this.maxChunkSize,
207
+ this.shouldRecover,
147
208
  ])
148
209
  }
149
210
 
211
+ private readonly maxChunkSize = 0
212
+ private readonly shouldRecover = 1
213
+
150
214
  public pullSample(options: PullSampleOptions) {
151
215
  const {
152
216
  inlet,
@@ -239,6 +303,10 @@ export default class LiblslAdapter implements Liblsl {
239
303
  return LiblslAdapter.load
240
304
  }
241
305
 
306
+ private get alloc() {
307
+ return LiblslAdapter.alloc
308
+ }
309
+
242
310
  private get liblslFuncs() {
243
311
  return {
244
312
  lsl_create_streaminfo: {
@@ -289,7 +357,12 @@ export default class LiblslAdapter implements Liblsl {
289
357
  lsl_create_inlet: {
290
358
  library: 'lsl',
291
359
  retType: DataType.External,
292
- paramsType: [DataType.External, DataType.I32, DataType.I32],
360
+ paramsType: [
361
+ DataType.External,
362
+ DataType.I32,
363
+ DataType.I32,
364
+ DataType.I32,
365
+ ],
293
366
  },
294
367
  lsl_flush_inlet: {
295
368
  library: 'lsl',
@@ -336,6 +409,8 @@ export interface Liblsl {
336
409
  destroyStreamInfo(options: DestroyStreamInfoOptions): void
337
410
  appendChannelsToStreamInfo(options: AppendChannelsToStreamInfoOptions): void
338
411
 
412
+ resolveByProp(options: ResolveByPropOptions): Promise<bigint[]>
413
+
339
414
  createOutlet(options: CreateOutletOptions): BoundOutlet
340
415
 
341
416
  pushSampleFloatTimestamp(
@@ -373,14 +448,21 @@ export interface AppendChannelsToStreamInfoOptions {
373
448
  channels: LslChannel[]
374
449
  }
375
450
 
376
- export interface CreateOutletOptions {
451
+ export interface DestroyStreamInfoOptions {
377
452
  info: BoundStreamInfo
378
- chunkSize: number
379
- maxBufferedMs: number
380
453
  }
381
454
 
382
- export interface DestroyStreamInfoOptions {
455
+ export interface ResolveByPropOptions {
456
+ prop: string
457
+ value: string
458
+ minResults?: number
459
+ timeoutMs?: number
460
+ }
461
+
462
+ export interface CreateOutletOptions {
383
463
  info: BoundStreamInfo
464
+ chunkSize: number
465
+ maxBufferedMs: number
384
466
  }
385
467
 
386
468
  export interface PushSampleFloatTimestampOptions {
@@ -401,7 +483,6 @@ export interface DestroyOutletOptions {
401
483
 
402
484
  export interface CreateInletOptions {
403
485
  info: BoundStreamInfo
404
- chunkSize: number
405
486
  maxBufferedMs: number
406
487
  }
407
488
 
@@ -7,8 +7,6 @@ import LiblslAdapter from './LiblslAdapter.js'
7
7
  export default class LslStreamInfo implements StreamInfo {
8
8
  public static Class?: StreamInfoConstructor
9
9
 
10
- private static instanceCache: Record<string, StreamInfo> = {}
11
-
12
10
  public readonly name: string
13
11
  public readonly type: string
14
12
  public readonly sourceId: string
@@ -36,6 +34,7 @@ export default class LslStreamInfo implements StreamInfo {
36
34
  channelFormat,
37
35
  sampleRateHz,
38
36
  units = this.defaultUnits,
37
+ boundStreamInfo,
39
38
  } = options
40
39
 
41
40
  this.name = name
@@ -47,38 +46,16 @@ export default class LslStreamInfo implements StreamInfo {
47
46
  this.sampleRateHz = sampleRateHz
48
47
  this.units = units
49
48
 
50
- this.createStreamInfo()
51
- this.appendChannelsToStreamInfo()
49
+ if (!boundStreamInfo) {
50
+ this.createStreamInfo()
51
+ this.appendChannelsToStreamInfo()
52
+ } else {
53
+ this.boundInfo = boundStreamInfo
54
+ }
52
55
  }
53
56
 
54
57
  public static Create(options: StreamInfoOptions) {
55
- const {
56
- name,
57
- type,
58
- sourceId,
59
- channelNames,
60
- channelFormat,
61
- sampleRateHz,
62
- } = options
63
-
64
- const channelCount = channelNames.length
65
-
66
- const key = JSON.stringify({
67
- name,
68
- type,
69
- sourceId,
70
- channelCount,
71
- channelFormat,
72
- sampleRateHz,
73
- })
74
-
75
- let instance = this.instanceCache[key]
76
-
77
- if (instance === undefined) {
78
- instance = new (this.Class ?? this)(options)
79
- this.instanceCache[key] = instance
80
- }
81
- return instance
58
+ return new (this.Class ?? this)(options)
82
59
  }
83
60
 
84
61
  private createStreamInfo() {
@@ -139,4 +116,5 @@ export interface StreamInfoOptions {
139
116
  type?: string
140
117
  sourceId?: string
141
118
  units?: string
119
+ boundStreamInfo?: BoundStreamInfo
142
120
  }
@@ -92,8 +92,7 @@ export default class LslStreamInlet implements StreamInlet {
92
92
  private createBoundInlet() {
93
93
  this.inlet = this.lsl.createInlet({
94
94
  info: this.boundStreamInfo,
95
- chunkSize: this.chunkSize,
96
- maxBufferedMs: this.maxBufferedMs / 1000,
95
+ maxBufferedMs: this.maxBufferedMs,
97
96
  })
98
97
  }
99
98
 
@@ -117,23 +116,27 @@ export default class LslStreamInlet implements StreamInlet {
117
116
  }
118
117
 
119
118
  private createDataBuffer() {
120
- const bytesPerFloat = 4
121
-
122
119
  this.dataBuffer = Buffer.alloc(
123
- bytesPerFloat * this.chunkSize * this.channelCount
120
+ this.bytesPerFloat * this.chunkSize * this.channelCount
124
121
  )
125
122
  }
126
123
 
124
+ private readonly bytesPerFloat = 4
125
+
127
126
  private createTimestampBuffer() {
128
- const bytesPerDouble = 8
129
- this.timestampBuffer = Buffer.alloc(bytesPerDouble * this.chunkSize)
127
+ this.timestampBuffer = Buffer.alloc(
128
+ this.bytesPerDouble * this.chunkSize
129
+ )
130
130
  }
131
131
 
132
+ private readonly bytesPerDouble = 8
133
+
132
134
  private createErrorCodeBuffer() {
133
- const bytesPerInt = 4
134
- this.errorCodeBuffer = Buffer.alloc(bytesPerInt)
135
+ this.errorCodeBuffer = Buffer.alloc(this.bytesPerInt)
135
136
  }
136
137
 
138
+ private readonly bytesPerInt = 4
139
+
137
140
  private createPointersToBuffers() {
138
141
  this.createDataBufferPtr()
139
142
  this.createTimestampBufferPtr()
@@ -16,9 +16,13 @@ import {
16
16
  PullChunkOptions,
17
17
  PullSampleOptions,
18
18
  DestroyStreamInfoOptions,
19
+ ResolveByPropOptions,
20
+ DestroyOutletOptions,
19
21
  } from 'impl/LiblslAdapter.js'
20
22
 
21
23
  export default class FakeLiblsl implements Liblsl {
24
+ public static fakeResolveHandles: bigint[] = []
25
+
22
26
  public static fakeSamples: Float32Array[] = [
23
27
  new Float32Array([1, 2, 3]),
24
28
  new Float32Array([4, 5, 6]),
@@ -46,12 +50,14 @@ export default class FakeLiblsl implements Liblsl {
46
50
  public streamInfo: BoundStreamInfo = {} as BoundStreamInfo
47
51
 
48
52
  public lastCreateStreamInfoOptions?: CreateStreamInfoOptions
49
- public lastDestroyStreamInfoOptions?: DestroyStreamInfoOptions
50
53
  public lastAppendChannelsToStreamInfoOptions?: AppendChannelsToStreamInfoOptions
54
+ public lastDestroyStreamInfoOptions?: DestroyStreamInfoOptions
55
+ public lastResolveByPropOptions?: ResolveByPropOptions
51
56
  public lastCreateOutletOptions?: CreateOutletOptions
52
57
  public lastPushSampleFloatTimestampOptions?: PushSampleFloatTimestampOptions
53
58
  public lastPushSampleStringTimestampOptions?: PushSampleStringTimestampOptions
54
59
  public lastCreateInletOptions?: CreateInletOptions
60
+ public lastDestroyOutletOptions?: DestroyOutletOptions
55
61
  public lastPullSampleOptions?: PullSampleOptions
56
62
  public lastPullChunkOptions?: PullChunkOptions
57
63
  public lastFlushInletOptions?: FlushInletOptions
@@ -72,16 +78,21 @@ export default class FakeLiblsl implements Liblsl {
72
78
  return this.streamInfo
73
79
  }
74
80
 
75
- public destroyStreamInfo(options: DestroyStreamInfoOptions) {
76
- this.lastDestroyStreamInfoOptions = options
77
- }
78
-
79
81
  public appendChannelsToStreamInfo(
80
82
  options: AppendChannelsToStreamInfoOptions
81
83
  ) {
82
84
  this.lastAppendChannelsToStreamInfoOptions = options
83
85
  }
84
86
 
87
+ public destroyStreamInfo(options: DestroyStreamInfoOptions) {
88
+ this.lastDestroyStreamInfoOptions = options
89
+ }
90
+
91
+ public async resolveByProp(options: ResolveByPropOptions) {
92
+ this.lastResolveByPropOptions = options
93
+ return FakeLiblsl.fakeResolveHandles
94
+ }
95
+
85
96
  public pushSampleFloatTimestamp(options: PushSampleFloatTimestampOptions) {
86
97
  this.lastPushSampleFloatTimestampOptions = options
87
98
  return FakeLiblsl.fakeErrorCode
@@ -101,8 +112,9 @@ export default class FakeLiblsl implements Liblsl {
101
112
  return this.outlet
102
113
  }
103
114
 
104
- public destroyOutlet() {
115
+ public destroyOutlet(options: DestroyOutletOptions) {
105
116
  this.destroyOutletHitCount++
117
+ this.lastDestroyOutletOptions = options
106
118
  }
107
119
 
108
120
  public createInlet(options: CreateInletOptions) {