@neurodevs/node-lsl 7.1.3 → 7.1.5

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 (32) hide show
  1. package/build/__tests__/behavioral/LslOutlet.test.js +8 -8
  2. package/build/__tests__/behavioral/LslOutlet.test.js.map +1 -1
  3. package/build/__tests__/behavioral/TimeMarkerOutlet.test.js +2 -2
  4. package/build/__tests__/behavioral/TimeMarkerOutlet.test.js.map +1 -1
  5. package/build/__tests__/implementation/Liblsl.test.d.ts +8 -5
  6. package/build/__tests__/implementation/Liblsl.test.js +92 -48
  7. package/build/__tests__/implementation/Liblsl.test.js.map +1 -1
  8. package/build/implementations/Liblsl.d.ts +8 -7
  9. package/build/implementations/Liblsl.js +65 -22
  10. package/build/implementations/Liblsl.js.map +1 -1
  11. package/build/implementations/LslOutlet.js +2 -2
  12. package/build/implementations/LslOutlet.js.map +1 -1
  13. package/build/nodeLsl.types.d.ts +9 -14
  14. package/build/nodeLsl.types.js +0 -11
  15. package/build/nodeLsl.types.js.map +1 -1
  16. package/build/testDoubles/FakeLiblsl.d.ts +6 -6
  17. package/build/testDoubles/FakeLiblsl.js +6 -6
  18. package/build/testDoubles/FakeLiblsl.js.map +1 -1
  19. package/build/testDoubles/MockTimeMarkerOutlet.js.map +1 -1
  20. package/build/validations.js +2 -0
  21. package/build/validations.js.map +1 -1
  22. package/package.json +8 -5
  23. package/src/__tests__/behavioral/LslOutlet.test.ts +15 -8
  24. package/src/__tests__/behavioral/TimeMarkerOutlet.test.ts +2 -2
  25. package/src/__tests__/implementation/Liblsl.test.ts +100 -59
  26. package/src/assertions.ts +5 -5
  27. package/src/implementations/Liblsl.ts +78 -39
  28. package/src/implementations/LslOutlet.ts +8 -8
  29. package/src/nodeLsl.types.ts +13 -14
  30. package/src/testDoubles/FakeLiblsl.ts +12 -12
  31. package/src/testDoubles/MockTimeMarkerOutlet.ts +4 -4
  32. package/src/validations.ts +5 -3
package/src/assertions.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  isStringInArray,
9
9
  } from './validations'
10
10
 
11
- export function assertValidMaxBuffered(maxBuffered: number): void {
11
+ export function assertValidMaxBuffered(maxBuffered: number) {
12
12
  if (!isPositiveIntegerOrZero(maxBuffered)) {
13
13
  throw new SchemaError({
14
14
  code: 'INVALID_PARAMETERS',
@@ -18,7 +18,7 @@ export function assertValidMaxBuffered(maxBuffered: number): void {
18
18
  }
19
19
  }
20
20
 
21
- export function assertValidChunkSize(chunkSize: number): void {
21
+ export function assertValidChunkSize(chunkSize: number) {
22
22
  if (!isPositiveIntegerOrZero(chunkSize)) {
23
23
  throw new SchemaError({
24
24
  code: 'INVALID_PARAMETERS',
@@ -28,7 +28,7 @@ export function assertValidChunkSize(chunkSize: number): void {
28
28
  }
29
29
  }
30
30
 
31
- export function assertValidChannelFormat(channelFormat: ChannelFormat): void {
31
+ export function assertValidChannelFormat(channelFormat: ChannelFormat) {
32
32
  if (!isStringInArray(channelFormat, CHANNEL_FORMATS)) {
33
33
  throw new SchemaError({
34
34
  code: 'INVALID_PARAMETERS',
@@ -38,7 +38,7 @@ export function assertValidChannelFormat(channelFormat: ChannelFormat): void {
38
38
  }
39
39
  }
40
40
 
41
- export function assertValidSampleRate(sampleRate: number): void {
41
+ export function assertValidSampleRate(sampleRate: number) {
42
42
  if (!isGreaterThanOrEqualToZero(sampleRate)) {
43
43
  throw new SchemaError({
44
44
  code: 'INVALID_PARAMETERS',
@@ -48,7 +48,7 @@ export function assertValidSampleRate(sampleRate: number): void {
48
48
  }
49
49
  }
50
50
 
51
- export function assertValidChannelCount(channelCount: number): void {
51
+ export function assertValidChannelCount(channelCount: number) {
52
52
  if (!isPositiveInteger(channelCount)) {
53
53
  throw new SchemaError({
54
54
  code: 'INVALID_PARAMETERS',
@@ -1,41 +1,36 @@
1
1
  import { assertOptions } from '@sprucelabs/schema'
2
- import ffi from 'ffi-napi'
2
+ import { DataType, define, open } from 'ffi-rs'
3
3
  import SpruceError from '../errors/SpruceError'
4
4
  import {
5
5
  Liblsl,
6
6
  LiblslBindings,
7
- streamInfo,
8
- outletType,
9
- FloatArray,
10
- StringArray,
11
- xmlPtr,
12
7
  CreateStreamInfoOptions,
13
- BoundStreamInfo,
14
8
  AppendChannelsToStreamInfoOptions,
15
9
  CreateOutletOptions,
16
- BoundOutlet,
17
10
  DestroyOutletOptions,
18
- PushSampleFtOptions,
19
- PushSampleStrtOptions,
11
+ PushSampleFloatTimestampOptions,
12
+ PushSampleStringTimestampOptions,
20
13
  } from '../nodeLsl.types'
21
14
 
22
15
  export default class LiblslImpl implements Liblsl {
23
16
  private static instance?: Liblsl
24
- public static ffi = ffi
17
+ public static ffiRsOpen = open
18
+ public static ffiRsDefine = define
19
+
25
20
  private bindings: LiblslBindings
26
21
 
27
- public static getInstance(): Liblsl {
22
+ public static getInstance() {
28
23
  if (!this.instance) {
29
24
  this.setInstance(new this())
30
25
  }
31
26
  return this.instance!
32
27
  }
33
28
 
34
- public static setInstance(instance: Liblsl): void {
29
+ public static setInstance(instance: Liblsl) {
35
30
  this.instance = instance
36
31
  }
37
32
 
38
- public static resetInstance(): void {
33
+ public static resetInstance() {
39
34
  delete this.instance
40
35
  }
41
36
 
@@ -56,25 +51,69 @@ export default class LiblslImpl implements Liblsl {
56
51
  }
57
52
  }
58
53
 
59
- private loadBindings(path: string) {
60
- //@ts-ignore
61
- return LiblslImpl.ffi.Library(path!, {
62
- lsl_create_streaminfo: [
63
- streamInfo,
64
- ['string', 'string', 'int', 'double', 'int', 'string'],
65
- ],
66
- lsl_create_outlet: [outletType, [streamInfo, 'int', 'int']],
67
- lsl_destroy_outlet: ['void', [outletType]],
68
- lsl_local_clock: ['double', []],
69
- lsl_push_sample_ft: ['void', [outletType, FloatArray, 'double']],
70
- lsl_push_sample_strt: ['void', [outletType, StringArray, 'double']],
71
- lsl_get_desc: [xmlPtr, [streamInfo]],
72
- lsl_append_child: [xmlPtr, [xmlPtr, 'string']],
73
- lsl_append_child_value: [xmlPtr, [xmlPtr, 'string', 'string']],
74
- }) as LiblslBindings
54
+ private loadBindings(liblslPath: string) {
55
+ LiblslImpl.ffiRsOpen({
56
+ library: 'lsl',
57
+ path: liblslPath,
58
+ })
59
+
60
+ return LiblslImpl.ffiRsDefine({
61
+ lsl_create_streaminfo: {
62
+ library: 'lsl',
63
+ retType: DataType.External,
64
+ paramsType: [
65
+ DataType.String,
66
+ DataType.String,
67
+ DataType.I32,
68
+ DataType.Double,
69
+ DataType.I32,
70
+ DataType.String,
71
+ ],
72
+ },
73
+ lsl_create_outlet: {
74
+ library: 'lsl',
75
+ retType: DataType.External,
76
+ paramsType: [DataType.External, DataType.I32, DataType.I32],
77
+ },
78
+ lsl_destroy_outlet: {
79
+ library: 'lsl',
80
+ retType: DataType.Void,
81
+ paramsType: [DataType.External],
82
+ },
83
+ lsl_local_clock: {
84
+ library: 'lsl',
85
+ retType: DataType.Double,
86
+ paramsType: [],
87
+ },
88
+ lsl_push_sample_ft: {
89
+ library: 'lsl',
90
+ retType: DataType.Void,
91
+ paramsType: [DataType.External, DataType.DoubleArray, DataType.Double],
92
+ },
93
+ lsl_push_sample_strt: {
94
+ library: 'lsl',
95
+ retType: DataType.Void,
96
+ paramsType: [DataType.External, DataType.StringArray, DataType.Double],
97
+ },
98
+ lsl_get_desc: {
99
+ library: 'lsl',
100
+ retType: DataType.External,
101
+ paramsType: [DataType.External],
102
+ },
103
+ lsl_append_child: {
104
+ library: 'lsl',
105
+ retType: DataType.External,
106
+ paramsType: [DataType.External, DataType.String],
107
+ },
108
+ lsl_append_child_value: {
109
+ library: 'lsl',
110
+ retType: DataType.External,
111
+ paramsType: [DataType.External, DataType.String, DataType.String],
112
+ },
113
+ }) as unknown as LiblslBindings
75
114
  }
76
115
 
77
- public createStreamInfo(options: CreateStreamInfoOptions): BoundStreamInfo {
116
+ public createStreamInfo(options: CreateStreamInfoOptions) {
78
117
  const { name, type, channelCount, sampleRate, channelFormat, sourceId } =
79
118
  assertOptions(options, [
80
119
  'name',
@@ -97,11 +136,11 @@ export default class LiblslImpl implements Liblsl {
97
136
 
98
137
  public appendChannelsToStreamInfo(
99
138
  options: AppendChannelsToStreamInfoOptions
100
- ): void {
139
+ ) {
101
140
  const { info, channels } = assertOptions(options, ['info', 'channels'])
102
141
 
103
- const desc = this.bindings.lsl_get_desc(info)
104
- const parent = this.bindings.lsl_append_child(desc, 'channels')
142
+ const description = this.bindings.lsl_get_desc(info)
143
+ const parent = this.bindings.lsl_append_child(description, 'channels')
105
144
 
106
145
  for (const channel of channels) {
107
146
  const child = this.bindings.lsl_append_child(parent, 'channel')
@@ -111,7 +150,7 @@ export default class LiblslImpl implements Liblsl {
111
150
  }
112
151
  }
113
152
 
114
- public createOutlet(options: CreateOutletOptions): BoundOutlet {
153
+ public createOutlet(options: CreateOutletOptions) {
115
154
  const { info, chunkSize, maxBuffered } = assertOptions(options, [
116
155
  'info',
117
156
  'chunkSize',
@@ -121,12 +160,12 @@ export default class LiblslImpl implements Liblsl {
121
160
  return this.bindings.lsl_create_outlet(info, chunkSize, maxBuffered)
122
161
  }
123
162
 
124
- public destroyOutlet(options: DestroyOutletOptions): void {
163
+ public destroyOutlet(options: DestroyOutletOptions) {
125
164
  const { outlet } = assertOptions(options, ['outlet'])
126
165
  this.bindings.lsl_destroy_outlet(outlet)
127
166
  }
128
167
 
129
- public pushSampleFt(options: PushSampleFtOptions): void {
168
+ public pushSampleFloatTimestamp(options: PushSampleFloatTimestampOptions) {
130
169
  const { outlet, sample, timestamp } = assertOptions(options, [
131
170
  'outlet',
132
171
  'sample',
@@ -135,7 +174,7 @@ export default class LiblslImpl implements Liblsl {
135
174
  this.bindings.lsl_push_sample_ft(outlet, sample, timestamp)
136
175
  }
137
176
 
138
- public pushSampleStrt(options: PushSampleStrtOptions): void {
177
+ public pushSampleStringTimestamp(options: PushSampleStringTimestampOptions) {
139
178
  const { outlet, sample, timestamp } = assertOptions(options, [
140
179
  'outlet',
141
180
  'sample',
@@ -144,7 +183,7 @@ export default class LiblslImpl implements Liblsl {
144
183
  this.bindings.lsl_push_sample_strt(outlet, sample, timestamp)
145
184
  }
146
185
 
147
- public localClock(): number {
186
+ public localClock() {
148
187
  return this.bindings.lsl_local_clock()
149
188
  }
150
189
  }
@@ -25,7 +25,7 @@ export default class LslOutletImpl implements LslOutlet {
25
25
  private outlet: BoundOutlet
26
26
  private pushSampleByType: (options: any) => void
27
27
 
28
- public static Outlet(options: LslOutletOptions): LslOutlet {
28
+ public static Outlet(options: LslOutletOptions) {
29
29
  return new (this.Class ?? this)(options)
30
30
  }
31
31
 
@@ -84,11 +84,11 @@ export default class LslOutletImpl implements LslOutlet {
84
84
  this.pushSampleByType = this.lsl[pushMethod].bind(this.lsl)
85
85
  }
86
86
 
87
- public destroy(): void {
87
+ public destroy() {
88
88
  this.lsl.destroyOutlet({ outlet: this.outlet })
89
89
  }
90
90
 
91
- public pushSample(sample: LslSample): void {
91
+ public pushSample(sample: LslSample) {
92
92
  const timestamp = this.lsl.localClock()
93
93
 
94
94
  this.pushSampleByType({
@@ -98,12 +98,12 @@ export default class LslOutletImpl implements LslOutlet {
98
98
  })
99
99
  }
100
100
 
101
- private getPushMethod(): keyof Liblsl {
101
+ private getPushMethod() {
102
102
  const channelFormat = this.options.channelFormat
103
103
 
104
104
  const methodMap: Record<string, keyof Liblsl> = {
105
- float32: 'pushSampleFt',
106
- string: 'pushSampleStrt',
105
+ float32: 'pushSampleFloatTimestamp',
106
+ string: 'pushSampleStringTimestamp',
107
107
  }
108
108
 
109
109
  if (!(channelFormat in methodMap)) {
@@ -114,11 +114,11 @@ export default class LslOutletImpl implements LslOutlet {
114
114
  return methodMap[channelFormat]
115
115
  }
116
116
 
117
- private lookupChannelFormat(channelFormat: ChannelFormat): number {
117
+ private lookupChannelFormat(channelFormat: ChannelFormat) {
118
118
  return CHANNEL_FORMATS_MAP[channelFormat]
119
119
  }
120
120
 
121
- private get lsl(): Liblsl {
121
+ private get lsl() {
122
122
  return LiblslImpl.getInstance()
123
123
  }
124
124
  }
@@ -1,5 +1,4 @@
1
- import ArrayType from 'ref-array-napi'
2
- import ref from 'ref-napi'
1
+ import { FFIParams } from 'ffi-rs'
3
2
  import { CHANNEL_FORMATS } from './consts'
4
3
 
5
4
  export interface LslOutlet {
@@ -41,8 +40,8 @@ export interface Liblsl {
41
40
  appendChannelsToStreamInfo(options: AppendChannelsToStreamInfoOptions): void
42
41
  createOutlet(options: CreateOutletOptions): BoundOutlet
43
42
  destroyOutlet(options: DestroyOutletOptions): void
44
- pushSampleFt(options: PushSampleFtOptions): void
45
- pushSampleStrt(options: PushSampleStrtOptions): void
43
+ pushSampleFloatTimestamp(options: PushSampleFloatTimestampOptions): void
44
+ pushSampleStringTimestamp(options: PushSampleStringTimestampOptions): void
46
45
  localClock(): number
47
46
  }
48
47
 
@@ -72,13 +71,13 @@ export interface DestroyOutletOptions {
72
71
  outlet: BoundOutlet
73
72
  }
74
73
 
75
- export interface PushSampleFtOptions {
74
+ export interface PushSampleFloatTimestampOptions {
76
75
  outlet: BoundOutlet
77
76
  sample: number[]
78
77
  timestamp: number
79
78
  }
80
79
 
81
- export interface PushSampleStrtOptions {
80
+ export interface PushSampleStringTimestampOptions {
82
81
  outlet: BoundOutlet
83
82
  sample: string[]
84
83
  timestamp: number
@@ -89,6 +88,7 @@ export interface LslChannel {
89
88
  unit: string
90
89
  type: string
91
90
  }
91
+
92
92
  export type LslSample = (number | string | undefined)[]
93
93
 
94
94
  export interface LiblslBindings {
@@ -122,18 +122,17 @@ export interface LiblslBindings {
122
122
  ): void
123
123
 
124
124
  lsl_local_clock(): number
125
- lsl_get_desc(info: BoundStreamInfo): BoundDesc
126
- lsl_append_child(desc: BoundDesc, name: string): BoundChild
125
+ lsl_get_desc(info: BoundStreamInfo): BoundDescription
126
+ lsl_append_child(desc: BoundDescription, name: string): BoundChild
127
127
  lsl_append_child_value(child: BoundChild, name: string, value: string): void
128
128
  }
129
129
 
130
130
  export interface BoundStreamInfo {}
131
131
  export interface BoundOutlet {}
132
- export interface BoundDesc {}
132
+ export interface BoundDescription {}
133
133
  export interface BoundChild {}
134
134
 
135
- export const streamInfo = ref.refType(ref.types.void)
136
- export const outletType = ref.refType(ref.types.void)
137
- export const FloatArray = ArrayType(ref.types.float)
138
- export const StringArray = ArrayType(ref.types.CString)
139
- export const xmlPtr = ref.refType(ref.types.void)
135
+ export type FfiRsDefineOptions = Record<
136
+ string,
137
+ Omit<FFIParams<any>, 'funcName' | 'paramsValue'>
138
+ >
@@ -4,8 +4,8 @@ import {
4
4
  CreateStreamInfoOptions,
5
5
  AppendChannelsToStreamInfoOptions,
6
6
  CreateOutletOptions,
7
- PushSampleFtOptions,
8
- PushSampleStrtOptions,
7
+ PushSampleFloatTimestampOptions,
8
+ PushSampleStringTimestampOptions,
9
9
  Liblsl,
10
10
  } from '../nodeLsl.types'
11
11
 
@@ -16,15 +16,15 @@ export default class FakeLiblsl implements Liblsl {
16
16
  public lastCreateStreamInfoOptions?: CreateStreamInfoOptions
17
17
  public lastAppendChannelsToStreamInfoOptions?: AppendChannelsToStreamInfoOptions
18
18
  public lastCreateOutletOptions?: CreateOutletOptions
19
- public lastPushSampleFtOptions?: PushSampleFtOptions
20
- public lastPushSampleStrtOptions?: PushSampleStrtOptions
19
+ public lastPushSampleFloatTimestampOptions?: PushSampleFloatTimestampOptions
20
+ public lastPushSampleStringTimestampOptions?: PushSampleStringTimestampOptions
21
21
 
22
22
  public createStreamInfoHitCount = 0
23
23
  public destroyOutletHitCount = 0
24
24
  public localClockHitCount = 0
25
- public pushSampleStrtHitCount = 0
25
+ public pushSampleStringTimestampHitCount = 0
26
26
 
27
- public createStreamInfo(options: CreateStreamInfoOptions): BoundStreamInfo {
27
+ public createStreamInfo(options: CreateStreamInfoOptions) {
28
28
  this.createStreamInfoHitCount++
29
29
  this.lastCreateStreamInfoOptions = options
30
30
  return this.streamInfo
@@ -36,7 +36,7 @@ export default class FakeLiblsl implements Liblsl {
36
36
  this.lastAppendChannelsToStreamInfoOptions = options
37
37
  }
38
38
 
39
- public createOutlet(options: CreateOutletOptions): BoundOutlet {
39
+ public createOutlet(options: CreateOutletOptions) {
40
40
  this.lastCreateOutletOptions = options
41
41
  return this.outlet
42
42
  }
@@ -45,13 +45,13 @@ export default class FakeLiblsl implements Liblsl {
45
45
  this.destroyOutletHitCount++
46
46
  }
47
47
 
48
- public pushSampleFt(options: PushSampleFtOptions) {
49
- this.lastPushSampleFtOptions = options
48
+ public pushSampleFloatTimestamp(options: PushSampleFloatTimestampOptions) {
49
+ this.lastPushSampleFloatTimestampOptions = options
50
50
  }
51
51
 
52
- public pushSampleStrt(options: PushSampleStrtOptions) {
53
- this.lastPushSampleStrtOptions = options
54
- this.pushSampleStrtHitCount++
52
+ public pushSampleStringTimestamp(options: PushSampleStringTimestampOptions) {
53
+ this.lastPushSampleStringTimestampOptions = options
54
+ this.pushSampleStringTimestampHitCount++
55
55
  }
56
56
 
57
57
  public localClock() {
@@ -7,10 +7,10 @@ export default class MockTimeMarkerOutlet implements TimeMarkerOutlet {
7
7
  private didPushSamples = false
8
8
  private pushedSamples?: LslSample[]
9
9
 
10
- public stop(): void {}
11
- public destroy(): void {}
10
+ public stop() {}
11
+ public destroy() {}
12
12
 
13
- public pushSample(sample: LslSample): void {
13
+ public pushSample(sample: LslSample) {
14
14
  if (!this.didPushSamples) {
15
15
  this.didPushSamples = true
16
16
  this.pushedSamples = []
@@ -18,7 +18,7 @@ export default class MockTimeMarkerOutlet implements TimeMarkerOutlet {
18
18
  this.pushedSamples?.push(sample)
19
19
  }
20
20
 
21
- public async pushMarkers(markers: DurationMarker[]): Promise<void> {
21
+ public async pushMarkers(markers: DurationMarker[]) {
22
22
  this.didPushMarkers = true
23
23
  this.pushedMarkers = markers
24
24
  }
@@ -2,14 +2,16 @@ export function isStringInArray(value: string, array: readonly string[]) {
2
2
  return array.indexOf(value) !== -1
3
3
  }
4
4
 
5
- export function isGreaterThanOrEqualToZero(value: number): boolean {
5
+ export function isGreaterThanOrEqualToZero(value: number) {
6
6
  return value >= 0
7
7
  }
8
8
 
9
- export function isPositiveInteger(value: number): boolean {
9
+ export function isPositiveInteger(value: number) {
10
+ //@ts-ignore
10
11
  return Number.isInteger(value) && value > 0
11
12
  }
12
13
 
13
- export function isPositiveIntegerOrZero(value: number): boolean {
14
+ export function isPositiveIntegerOrZero(value: number) {
15
+ //@ts-ignore
14
16
  return Number.isInteger(value) && value >= 0
15
17
  }