@neurodevs/ndx-native 0.0.1
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.
- package/.nvmrc +1 -0
- package/.vscode/launch.json +58 -0
- package/.vscode/settings.json +67 -0
- package/.vscode/tasks.json +130 -0
- package/LICENSE +21 -0
- package/README.md +2 -0
- package/build/.spruce/settings.json +11 -0
- package/build/__tests__/AbstractPackageTest.d.ts +7 -0
- package/build/__tests__/AbstractPackageTest.js +14 -0
- package/build/__tests__/AbstractPackageTest.js.map +1 -0
- package/build/__tests__/impl/LabrecorderAdapter.test.d.ts +30 -0
- package/build/__tests__/impl/LabrecorderAdapter.test.js +164 -0
- package/build/__tests__/impl/LabrecorderAdapter.test.js.map +1 -0
- package/build/__tests__/impl/LiblslAdapter.test.d.ts +84 -0
- package/build/__tests__/impl/LiblslAdapter.test.js +750 -0
- package/build/__tests__/impl/LiblslAdapter.test.js.map +1 -0
- package/build/__tests__/impl/LibxdfAdapter.test.d.ts +45 -0
- package/build/__tests__/impl/LibxdfAdapter.test.js +243 -0
- package/build/__tests__/impl/LibxdfAdapter.test.js.map +1 -0
- package/build/consts.d.ts +11 -0
- package/build/consts.js +21 -0
- package/build/consts.js.map +1 -0
- package/build/impl/LabrecorderAdapter.d.ts +30 -0
- package/build/impl/LabrecorderAdapter.js +69 -0
- package/build/impl/LabrecorderAdapter.js.map +1 -0
- package/build/impl/LiblslAdapter.d.ts +172 -0
- package/build/impl/LiblslAdapter.js +360 -0
- package/build/impl/LiblslAdapter.js.map +1 -0
- package/build/impl/LibxdfAdapter.d.ts +92 -0
- package/build/impl/LibxdfAdapter.js +130 -0
- package/build/impl/LibxdfAdapter.js.map +1 -0
- package/build/index.d.ts +14 -0
- package/build/index.js +18 -0
- package/build/index.js.map +1 -0
- package/build/lib/handleError.d.ts +8 -0
- package/build/lib/handleError.js +25 -0
- package/build/lib/handleError.js.map +1 -0
- package/build/testDoubles/Labrecorder/FakeLabrecorder.d.ts +15 -0
- package/build/testDoubles/Labrecorder/FakeLabrecorder.js +26 -0
- package/build/testDoubles/Labrecorder/FakeLabrecorder.js.map +1 -0
- package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +57 -0
- package/build/testDoubles/Liblsl/FakeLiblsl.js +140 -0
- package/build/testDoubles/Liblsl/FakeLiblsl.js.map +1 -0
- package/build/testDoubles/Libxdf/FakeLibxdf.d.ts +13 -0
- package/build/testDoubles/Libxdf/FakeLibxdf.js +25 -0
- package/build/testDoubles/Libxdf/FakeLibxdf.js.map +1 -0
- package/build/testDoubles/Libxdf/SpyLibxdf.d.ts +6 -0
- package/build/testDoubles/Libxdf/SpyLibxdf.js +10 -0
- package/build/testDoubles/Libxdf/SpyLibxdf.js.map +1 -0
- package/eslint.config.mjs +3 -0
- package/package.json +84 -0
- package/src/.spruce/settings.json +11 -0
- package/src/__tests__/AbstractPackageTest.ts +16 -0
- package/src/__tests__/impl/LabrecorderAdapter.test.ts +197 -0
- package/src/__tests__/impl/LiblslAdapter.test.ts +907 -0
- package/src/__tests__/impl/LibxdfAdapter.test.ts +290 -0
- package/src/consts.ts +21 -0
- package/src/impl/LabrecorderAdapter.ts +100 -0
- package/src/impl/LiblslAdapter.ts +616 -0
- package/src/impl/LibxdfAdapter.ts +227 -0
- package/src/index.ts +26 -0
- package/src/lib/handleError.ts +24 -0
- package/src/testDoubles/Labrecorder/FakeLabrecorder.ts +37 -0
- package/src/testDoubles/Liblsl/FakeLiblsl.ts +204 -0
- package/src/testDoubles/Libxdf/FakeLibxdf.ts +33 -0
- package/src/testDoubles/Libxdf/SpyLibxdf.ts +13 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import generateId from '@neurodevs/generate-id'
|
|
2
|
+
import {
|
|
3
|
+
MangledNameExtractor,
|
|
4
|
+
FakeNameExtractor,
|
|
5
|
+
} from '@neurodevs/node-mangled-names'
|
|
6
|
+
import { test, assert } from '@neurodevs/node-tdd'
|
|
7
|
+
import { DataType, OpenParams } from 'ffi-rs'
|
|
8
|
+
|
|
9
|
+
import LibxdfAdapter, {
|
|
10
|
+
FfiRsDefineOptions,
|
|
11
|
+
LibxdfBindings,
|
|
12
|
+
XdfFile,
|
|
13
|
+
} from '../../impl/LibxdfAdapter.js'
|
|
14
|
+
import SpyLibxdf from '../../testDoubles/Libxdf/SpyLibxdf.js'
|
|
15
|
+
import AbstractPackageTest from '../AbstractPackageTest.js'
|
|
16
|
+
|
|
17
|
+
export default class LibxdfTest extends AbstractPackageTest {
|
|
18
|
+
private static instance: SpyLibxdf
|
|
19
|
+
private static libxdfPath = generateId()
|
|
20
|
+
private static path = generateId()
|
|
21
|
+
private static shouldThrowWhenLoadingBindings: boolean
|
|
22
|
+
private static mangledLoadXdfName: string
|
|
23
|
+
private static fakeBindings: LibxdfBindings
|
|
24
|
+
private static ffiRsOpenOptions?: OpenParams
|
|
25
|
+
private static ffiRsDefineOptions?: FfiRsDefineOptions
|
|
26
|
+
private static loadXdfCalls: string[][] = []
|
|
27
|
+
|
|
28
|
+
protected static async beforeEach() {
|
|
29
|
+
await super.beforeEach()
|
|
30
|
+
|
|
31
|
+
LibxdfAdapter.Class = SpyLibxdf
|
|
32
|
+
|
|
33
|
+
MangledNameExtractor.Class = FakeNameExtractor
|
|
34
|
+
FakeNameExtractor.clearTestDouble()
|
|
35
|
+
|
|
36
|
+
this.shouldThrowWhenLoadingBindings = false
|
|
37
|
+
this.mangledLoadXdfName = this.generateMangledName()
|
|
38
|
+
this.fakeBindings = this.FakeBindings()
|
|
39
|
+
|
|
40
|
+
this.setFakeExtractResult()
|
|
41
|
+
this.clearAndFakeFfi()
|
|
42
|
+
|
|
43
|
+
this.instance = await this.LibxdfAdapter()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@test()
|
|
47
|
+
protected static canCreateInstance() {
|
|
48
|
+
assert.isTruthy(this.instance, 'Should create an instance!')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@test()
|
|
52
|
+
protected static async throwsWhenBindingsFailToLoad() {
|
|
53
|
+
this.shouldThrowWhenLoadingBindings = true
|
|
54
|
+
|
|
55
|
+
const err = await assert.doesThrowAsync(
|
|
56
|
+
async () => await this.LibxdfAdapter()
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
const actual = (err.message ?? err.stack).replace(/\s+/g, '')
|
|
60
|
+
|
|
61
|
+
const expected = this.generateFailedMessageWithFakeError().replace(
|
|
62
|
+
/\s+/g,
|
|
63
|
+
''
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
assert.isEqual(actual, expected, 'Did not receive the expected error!')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@test()
|
|
70
|
+
protected static async callsFfiRsOpenWithRequiredOptions() {
|
|
71
|
+
assert.isEqualDeep(this.ffiRsOpenOptions, {
|
|
72
|
+
library: 'xdf',
|
|
73
|
+
path: this.libxdfPath,
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@test()
|
|
78
|
+
protected static async callsFfiRsDefineWithRequiredOptions() {
|
|
79
|
+
const mangledLoadXdfName = generateId()
|
|
80
|
+
this.setFakeExtractResult(mangledLoadXdfName)
|
|
81
|
+
|
|
82
|
+
await this.LibxdfAdapter()
|
|
83
|
+
|
|
84
|
+
assert.isEqualDeep(
|
|
85
|
+
this.ffiRsDefineOptions,
|
|
86
|
+
{
|
|
87
|
+
[mangledLoadXdfName.slice(1)]: {
|
|
88
|
+
library: 'xdf',
|
|
89
|
+
retType: DataType.String,
|
|
90
|
+
paramsType: [DataType.String],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
'Please pass valid options to ffiRsDefine!'
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@test()
|
|
98
|
+
protected static async loadXdfCallsBindings() {
|
|
99
|
+
this.loadXdf()
|
|
100
|
+
|
|
101
|
+
assert.isEqualDeep(
|
|
102
|
+
this.loadXdfCalls[0],
|
|
103
|
+
[this.path],
|
|
104
|
+
'Should have called load_xdf_to_json(path)!'
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@test()
|
|
109
|
+
protected static async createsMangledNameExtractor() {
|
|
110
|
+
assert.isEqual(FakeNameExtractor.numConstructorCalls, 1)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@test()
|
|
114
|
+
protected static async callsExtractorWithCorrectParams() {
|
|
115
|
+
assert.isEqualDeep(FakeNameExtractor.extractCalls[0], {
|
|
116
|
+
libPath: this.libxdfPath,
|
|
117
|
+
unmangledNames: [this.loadXdfName],
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@test()
|
|
122
|
+
protected static async returnsResultInJson() {
|
|
123
|
+
const result = this.loadXdf()
|
|
124
|
+
assert.isEqualDeep(result, this.fakeParsedXdf)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@test()
|
|
128
|
+
protected static async throwsIfLibxdfPathDoesNotExist() {
|
|
129
|
+
this.libxdfPath = generateId()
|
|
130
|
+
|
|
131
|
+
const err = await assert.doesThrowAsync(
|
|
132
|
+
async () => await this.LibxdfAdapter(this.libxdfPath, true)
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const actual = (err.message ?? err.stack).replace(/\s+/g, '')
|
|
136
|
+
const expected = this.generateFailedMessage().replace(/\s+/g, '')
|
|
137
|
+
|
|
138
|
+
assert.isEqual(actual, expected, 'Did not receive the expected error!')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@test()
|
|
142
|
+
protected static async doesNotThrowIfEventsUndefined() {
|
|
143
|
+
this.fakeSerializedXdf = `{"streams": [{"stream_id": ${this.fakeStreamId}, "time_series": [], "time_stamps": [], "stream_info": {"channel_count": ${this.fakeChannelCount}, "channel_format": "${this.fakeChannelFormat}", "nominal_srate": ${this.fakeNominalSampleRate}, "stream_name": "${this.fakeStreamName}", "stream_type": "${this.fakeStreamType}"}}]}`
|
|
144
|
+
this.loadXdf()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private static setFakeExtractResult(
|
|
148
|
+
mangledLoadXdfName = this.mangledLoadXdfName
|
|
149
|
+
) {
|
|
150
|
+
FakeNameExtractor.fakeResult = {
|
|
151
|
+
load_xdf_to_json: mangledLoadXdfName,
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private static generateMangledName() {
|
|
156
|
+
return `${generateId()}${this.loadXdfName}${generateId()}`
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private static clearAndFakeFfi() {
|
|
160
|
+
delete this.ffiRsOpenOptions
|
|
161
|
+
delete this.ffiRsDefineOptions
|
|
162
|
+
this.fakeFfiRsOpen()
|
|
163
|
+
this.fakeFfiRsDefine()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private static fakeFfiRsOpen() {
|
|
167
|
+
LibxdfAdapter.ffiRsOpen = (options) => {
|
|
168
|
+
this.ffiRsOpenOptions = options
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private static fakeFfiRsDefine() {
|
|
173
|
+
LibxdfAdapter.ffiRsDefine = (options) => {
|
|
174
|
+
this.ffiRsDefineOptions = options
|
|
175
|
+
|
|
176
|
+
if (this.shouldThrowWhenLoadingBindings) {
|
|
177
|
+
throw new Error(this.fakeErrorMessage)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return this.fakeBindings as any
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private static generateFailedMessage() {
|
|
185
|
+
return `
|
|
186
|
+
\n -----------------------------------
|
|
187
|
+
\n Failed to load libxdf! Tried to load from:
|
|
188
|
+
\n ${this.libxdfPath}
|
|
189
|
+
\n Instructions to save your day (on MacOS):
|
|
190
|
+
\n 1. git clone https://github.com/neurodevs/libxdf.git
|
|
191
|
+
\n 2. cd libxdf && cmake -S . -B build && cmake --build build
|
|
192
|
+
\n 3. sudo cp build/libxdf.dylib /opt/local/lib/
|
|
193
|
+
\n 4. Try whatever you were doing again!
|
|
194
|
+
\n Modify step 3 for your OS if you are not on MacOS.
|
|
195
|
+
\n Check the official repo for OS-specific instructions:
|
|
196
|
+
\n https://github.com/xdf-modules/libxdf
|
|
197
|
+
\n If you're still unsure, ask an LLM with this error and your OS.
|
|
198
|
+
\n You could also post an issue on the repo:
|
|
199
|
+
\n https://github.com/neurodevs/node-xdf/issues
|
|
200
|
+
\n Good luck!
|
|
201
|
+
\n @ericthecurious
|
|
202
|
+
\n -----------------------------------
|
|
203
|
+
`
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private static generateFailedMessageWithFakeError() {
|
|
207
|
+
return `
|
|
208
|
+
\n -----------------------------------
|
|
209
|
+
\n Failed to load libxdf! Tried to load from:
|
|
210
|
+
\n ${this.libxdfPath}
|
|
211
|
+
\n Instructions to save your day (on MacOS):
|
|
212
|
+
\n 1. git clone https://github.com/neurodevs/libxdf.git
|
|
213
|
+
\n 2. cd libxdf && cmake -S . -B build && cmake --build build
|
|
214
|
+
\n 3. sudo cp build/libxdf.dylib /opt/local/lib/
|
|
215
|
+
\n 4. Try whatever you were doing again!
|
|
216
|
+
\n Modify step 3 for your OS if you are not on MacOS.
|
|
217
|
+
\n Check the official repo for OS-specific instructions:
|
|
218
|
+
\n https://github.com/xdf-modules/libxdf
|
|
219
|
+
\n If you're still unsure, ask an LLM with this error and your OS.
|
|
220
|
+
\n You could also post an issue on the repo:
|
|
221
|
+
\n https://github.com/neurodevs/node-xdf/issues
|
|
222
|
+
\n Good luck!
|
|
223
|
+
\n @ericthecurious
|
|
224
|
+
\n -----------------------------------
|
|
225
|
+
\n Error: ${this.fakeErrorMessage}
|
|
226
|
+
\n
|
|
227
|
+
`
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private static loadXdf() {
|
|
231
|
+
return this.instance.loadXdf(this.path)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private static readonly loadXdfName = 'load_xdf_to_json'
|
|
235
|
+
|
|
236
|
+
private static readonly fakeStreamId = 0
|
|
237
|
+
private static readonly fakeStreamName = generateId()
|
|
238
|
+
private static readonly fakeStreamType = generateId()
|
|
239
|
+
private static readonly fakeChannelCount = 0
|
|
240
|
+
private static readonly fakeChannelFormat = generateId()
|
|
241
|
+
private static readonly fakeNominalSampleRate = 0
|
|
242
|
+
private static readonly fakeEventName = generateId()
|
|
243
|
+
private static readonly fakeEventTimestamp = 0
|
|
244
|
+
private static readonly fakeErrorMessage = 'Fake error message!'
|
|
245
|
+
|
|
246
|
+
private static fakeSerializedXdf = `{"streams": [{"stream_id": ${this.fakeStreamId}, "time_series": [], "time_stamps": [], "stream_info": {"channel_count": ${this.fakeChannelCount}, "channel_format": "${this.fakeChannelFormat}", "nominal_srate": ${this.fakeNominalSampleRate}, "stream_name": "${this.fakeStreamName}", "stream_type": "${this.fakeStreamType}"}}], "events": [{"stream_id": ${this.fakeStreamId}, "event_name": "${this.fakeEventName}", "event_timestamp": ${this.fakeEventTimestamp}}]}`
|
|
247
|
+
|
|
248
|
+
private static readonly fakeParsedXdf: XdfFile = {
|
|
249
|
+
path: this.path,
|
|
250
|
+
streams: [
|
|
251
|
+
{
|
|
252
|
+
id: this.fakeStreamId,
|
|
253
|
+
name: this.fakeStreamName,
|
|
254
|
+
type: this.fakeStreamType,
|
|
255
|
+
channelCount: this.fakeChannelCount,
|
|
256
|
+
channelFormat: this.fakeChannelFormat,
|
|
257
|
+
nominalSampleRateHz: this.fakeNominalSampleRate,
|
|
258
|
+
data: [],
|
|
259
|
+
timestamps: [],
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
events: [
|
|
263
|
+
{
|
|
264
|
+
name: this.fakeEventName,
|
|
265
|
+
timestamp: this.fakeEventTimestamp,
|
|
266
|
+
streamId: this.fakeStreamId,
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private static FakeBindings(mangledLoadXdfName = this.mangledLoadXdfName) {
|
|
272
|
+
return {
|
|
273
|
+
[mangledLoadXdfName.slice(1)]: (path: string[]) => {
|
|
274
|
+
this.loadXdfCalls.push(path)
|
|
275
|
+
return this.fakeSerializedXdf
|
|
276
|
+
},
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private static async LibxdfAdapter(
|
|
281
|
+
libxdfPath?: string,
|
|
282
|
+
throwIfPathNotExists = false
|
|
283
|
+
) {
|
|
284
|
+
const libxdf = await LibxdfAdapter.Create(
|
|
285
|
+
libxdfPath ?? this.libxdfPath,
|
|
286
|
+
throwIfPathNotExists
|
|
287
|
+
)
|
|
288
|
+
return libxdf as SpyLibxdf
|
|
289
|
+
}
|
|
290
|
+
}
|
package/src/consts.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const CHANNEL_FORMATS = [
|
|
2
|
+
'undefined',
|
|
3
|
+
'float32',
|
|
4
|
+
'double64',
|
|
5
|
+
'string',
|
|
6
|
+
'int32',
|
|
7
|
+
'int16',
|
|
8
|
+
'int8',
|
|
9
|
+
'int64',
|
|
10
|
+
] as const
|
|
11
|
+
|
|
12
|
+
export const CHANNEL_FORMATS_MAP = {
|
|
13
|
+
undefined: 0,
|
|
14
|
+
float32: 1,
|
|
15
|
+
double64: 2,
|
|
16
|
+
string: 3,
|
|
17
|
+
int32: 4,
|
|
18
|
+
int16: 5,
|
|
19
|
+
int8: 6,
|
|
20
|
+
int64: 7,
|
|
21
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { DataType, define, open } from 'ffi-rs'
|
|
2
|
+
|
|
3
|
+
export default class LabrecorderAdapter implements Labrecorder {
|
|
4
|
+
public static Class?: LabrecorderConstructor
|
|
5
|
+
public static ffiRsOpen = open
|
|
6
|
+
public static ffiRsDefine = define
|
|
7
|
+
|
|
8
|
+
private labrecorderPath: string
|
|
9
|
+
private bindings: LabrecorderBindings
|
|
10
|
+
|
|
11
|
+
protected constructor(labrecorderPath: string) {
|
|
12
|
+
this.labrecorderPath = labrecorderPath
|
|
13
|
+
this.loadCppLibrary()
|
|
14
|
+
|
|
15
|
+
this.bindings = this.defineBindingFunctions()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public static Create(labrecorderPath?: string) {
|
|
19
|
+
const path = labrecorderPath ?? '/opt/local/lib/liblabrecorder.dylib'
|
|
20
|
+
return new (this.Class ?? this)(path)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private loadCppLibrary() {
|
|
24
|
+
this.ffiRsOpen({
|
|
25
|
+
library: 'labrecorder',
|
|
26
|
+
path: this.labrecorderPath,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private defineBindingFunctions() {
|
|
31
|
+
return this.ffiRsDefine(this.functions) as LabrecorderBindings
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private get functions() {
|
|
35
|
+
return {
|
|
36
|
+
recording_create: {
|
|
37
|
+
library: 'labrecorder',
|
|
38
|
+
retType: DataType.External,
|
|
39
|
+
paramsType: [
|
|
40
|
+
DataType.String,
|
|
41
|
+
DataType.StringArray,
|
|
42
|
+
DataType.U64,
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
recording_stop: {
|
|
46
|
+
library: 'labrecorder',
|
|
47
|
+
retType: DataType.Void,
|
|
48
|
+
paramsType: [DataType.External],
|
|
49
|
+
},
|
|
50
|
+
recording_delete: {
|
|
51
|
+
library: 'labrecorder',
|
|
52
|
+
retType: DataType.Void,
|
|
53
|
+
paramsType: [DataType.External],
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public createRecording(filename: string, watchFor: string[]) {
|
|
59
|
+
return this.bindings.recording_create([
|
|
60
|
+
filename,
|
|
61
|
+
watchFor,
|
|
62
|
+
watchFor.length,
|
|
63
|
+
])
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public stopRecording(recording: RecordingHandle) {
|
|
67
|
+
this.bindings.recording_stop([recording])
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public deleteRecording(recording: RecordingHandle) {
|
|
71
|
+
this.bindings.recording_delete([recording])
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private get ffiRsOpen() {
|
|
75
|
+
return LabrecorderAdapter.ffiRsOpen
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private get ffiRsDefine() {
|
|
79
|
+
return LabrecorderAdapter.ffiRsDefine
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface Labrecorder {
|
|
84
|
+
createRecording(filename: string, watchFor: string[]): RecordingHandle
|
|
85
|
+
stopRecording(recording: RecordingHandle): void
|
|
86
|
+
deleteRecording(recording: RecordingHandle): void
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type LabrecorderConstructor = new (
|
|
90
|
+
labrecorderPath: string
|
|
91
|
+
) => Labrecorder
|
|
92
|
+
|
|
93
|
+
export interface LabrecorderBindings {
|
|
94
|
+
recording_create(args: [string, string[], number]): RecordingHandle
|
|
95
|
+
|
|
96
|
+
recording_stop(args: [RecordingHandle]): void
|
|
97
|
+
recording_delete(args: [RecordingHandle]): void
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export type RecordingHandle = DataType.External
|