@nonstrict/recordkit 0.87.1 → 0.97.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.
- package/bin/README.md +1 -1
- package/bin/recordkit-rpc +0 -0
- package/out/Errors.d.ts +91 -0
- package/out/Errors.js +63 -0
- package/out/Errors.js.map +1 -0
- package/out/InputEvents.d.ts +661 -0
- package/out/InputEvents.js +8 -0
- package/out/InputEvents.js.map +1 -0
- package/out/IpcRecordKit.js +13 -0
- package/out/IpcRecordKit.js.map +1 -1
- package/out/NonstrictRPC.d.ts +9 -0
- package/out/NonstrictRPC.js +27 -4
- package/out/NonstrictRPC.js.map +1 -1
- package/out/RecordKit.d.ts +267 -5
- package/out/RecordKit.js +243 -3
- package/out/RecordKit.js.map +1 -1
- package/out/Recorder.d.ts +451 -53
- package/out/Recorder.js +80 -2
- package/out/Recorder.js.map +1 -1
- package/out/RecordingMetadata.d.ts +96 -0
- package/out/RecordingMetadata.js +12 -0
- package/out/RecordingMetadata.js.map +1 -0
- package/out/WebAudioUtils.d.ts +35 -0
- package/out/WebAudioUtils.js +37 -0
- package/out/WebAudioUtils.js.map +1 -1
- package/out/WindowLevels.d.ts +46 -0
- package/out/WindowLevels.js +41 -0
- package/out/WindowLevels.js.map +1 -0
- package/out/browser.d.ts +8 -1
- package/out/browser.js +3 -1
- package/out/browser.js.map +1 -1
- package/out/index.cjs +603 -9
- package/out/index.cjs.map +1 -1
- package/out/index.d.ts +8 -0
- package/out/index.js +3 -0
- package/out/index.js.map +1 -1
- package/package.json +1 -1
- package/src/Errors.test.ts +38 -0
- package/src/Errors.ts +151 -0
- package/src/InputEvents.ts +695 -0
- package/src/IpcRecordKit.ts +12 -0
- package/src/NonstrictRPC.test.ts +24 -1
- package/src/NonstrictRPC.ts +29 -5
- package/src/RecordKit.ts +347 -11
- package/src/Recorder.schema.test.ts +167 -0
- package/src/Recorder.ts +558 -80
- package/src/RecordingMetadata.ts +125 -0
- package/src/WebAudioUtils.test.ts +78 -0
- package/src/WebAudioUtils.ts +57 -1
- package/src/WindowLevels.test.ts +34 -0
- package/src/WindowLevels.ts +47 -0
- package/src/browser.ts +12 -2
- package/src/index.ts +8 -0
- package/src/__snapshots__/NonstrictRPC.test.ts.snap +0 -24
package/src/Recorder.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
import { NSRPC } from "./NonstrictRPC.js";
|
|
3
3
|
import { EventEmitter } from "events";
|
|
4
|
-
import { AppleDevice, Camera, Display, Microphone, RunningApplication, Window } from "./RecordKit.js";
|
|
4
|
+
import { AppleDevice, Bounds, Camera, Display, Microphone, RunningApplication, Window } from "./RecordKit.js";
|
|
5
|
+
import type { RecordKitErrorCode } from "./Errors.js";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Converts RPC audio buffer data to AudioStreamBuffer format
|
|
@@ -51,6 +52,22 @@ function convertRPCParamsToAudioStreamBuffer(params: any): AudioStreamBuffer | n
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Registers the per-segment callback of a {@link JSONOutputOptions} (if any) as an RPC closure,
|
|
57
|
+
* replacing the function with the closure target so the options object can be serialized.
|
|
58
|
+
* @internal
|
|
59
|
+
*/
|
|
60
|
+
function registerJSONOutputSegmentCallback(output: JSONOutputOptions | undefined, rpc: NSRPC, object: Recorder, prefix: string) {
|
|
61
|
+
if (output && output.output == 'segmented' && output.segmentCallback) {
|
|
62
|
+
const segmentHandler = output.segmentCallback;
|
|
63
|
+
(output as any).segmentCallback = rpc.registerClosure({
|
|
64
|
+
handler: (params) => { segmentHandler(params.path as string) },
|
|
65
|
+
prefix,
|
|
66
|
+
lifecycle: object
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
54
71
|
/**
|
|
55
72
|
* @group Recording
|
|
56
73
|
*/
|
|
@@ -62,9 +79,7 @@ export class Recorder extends EventEmitter {
|
|
|
62
79
|
static async newInstance(rpc: NSRPC, schema: {
|
|
63
80
|
output_directory?: string
|
|
64
81
|
items: RecorderSchemaItem[]
|
|
65
|
-
settings?:
|
|
66
|
-
allowFrameReordering?: boolean
|
|
67
|
-
}
|
|
82
|
+
settings?: RecorderSettings
|
|
68
83
|
}): Promise<Recorder> {
|
|
69
84
|
const target = 'Recorder_' + randomUUID();
|
|
70
85
|
const object = new Recorder(rpc, target);
|
|
@@ -98,6 +113,7 @@ export class Recorder extends EventEmitter {
|
|
|
98
113
|
lifecycle: object
|
|
99
114
|
});
|
|
100
115
|
}
|
|
116
|
+
registerJSONOutputSegmentCallback(item.inputEventsOutput, rpc, object, 'Display.onInputEventsSegment')
|
|
101
117
|
}
|
|
102
118
|
if (item.type == 'windowBasedCrop') {
|
|
103
119
|
if (typeof item.window != 'number') {
|
|
@@ -111,6 +127,21 @@ export class Recorder extends EventEmitter {
|
|
|
111
127
|
lifecycle: object
|
|
112
128
|
});
|
|
113
129
|
}
|
|
130
|
+
registerJSONOutputSegmentCallback(item.inputEventsOutput, rpc, object, 'WindowBasedCrop.onInputEventsSegment')
|
|
131
|
+
}
|
|
132
|
+
if (item.type == 'desktopIndependentWindow') {
|
|
133
|
+
if (typeof item.window != 'number') {
|
|
134
|
+
item.window = item.window.id
|
|
135
|
+
}
|
|
136
|
+
if (item.output == 'segmented' && item.segmentCallback) {
|
|
137
|
+
const segmentHandler = item.segmentCallback;
|
|
138
|
+
(item as any).segmentCallback = rpc.registerClosure({
|
|
139
|
+
handler: (params) => { segmentHandler(params.path as string) },
|
|
140
|
+
prefix: 'DesktopIndependentWindow.onSegment',
|
|
141
|
+
lifecycle: object
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
registerJSONOutputSegmentCallback(item.inputEventsOutput, rpc, object, 'DesktopIndependentWindow.onInputEventsSegment')
|
|
114
145
|
}
|
|
115
146
|
if (item.type == 'appleDeviceStaticOrientation') {
|
|
116
147
|
if (typeof item.device != 'string') {
|
|
@@ -202,11 +233,16 @@ export class Recorder extends EventEmitter {
|
|
|
202
233
|
prefix: 'Recorder.onAbort',
|
|
203
234
|
lifecycle: object
|
|
204
235
|
});
|
|
236
|
+
const onSignalsChangedInstance = rpc.registerClosure({
|
|
237
|
+
handler: (params) => { weakRefObject.deref()?.emit('signals', (params as { signals: Signal[] }).signals) },
|
|
238
|
+
prefix: 'Recorder.onSignalsChanged',
|
|
239
|
+
lifecycle: object
|
|
240
|
+
});
|
|
205
241
|
|
|
206
242
|
await rpc.initialize({
|
|
207
243
|
target,
|
|
208
244
|
type: 'Recorder',
|
|
209
|
-
params: { schema, onAbortInstance },
|
|
245
|
+
params: { schema, onAbortInstance, onSignalsChangedInstance },
|
|
210
246
|
lifecycle: object
|
|
211
247
|
});
|
|
212
248
|
|
|
@@ -220,23 +256,164 @@ export class Recorder extends EventEmitter {
|
|
|
220
256
|
this.target = target;
|
|
221
257
|
}
|
|
222
258
|
|
|
223
|
-
|
|
224
|
-
|
|
259
|
+
/**
|
|
260
|
+
* Prepares the recording session for instant recording, allocating resources and validating the
|
|
261
|
+
* configuration.
|
|
262
|
+
*
|
|
263
|
+
* Preparing ahead of time lets {@link start} begin recording instantly; without it, starting incurs
|
|
264
|
+
* a setup delay.
|
|
265
|
+
*
|
|
266
|
+
* @returns The expected {@link BundleInfo} describing the file assets that will be produced by this
|
|
267
|
+
* recording, allowing you to inspect the planned output (filenames, asset types, sizes) before
|
|
268
|
+
* recording starts.
|
|
269
|
+
*/
|
|
270
|
+
async prepare(): Promise<BundleInfo> {
|
|
271
|
+
return await this.rpc.perform({ target: this.target, action: 'prepare' }) as BundleInfo;
|
|
225
272
|
}
|
|
226
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Starts recording. If the session was not already {@link prepare}d this performs setup first,
|
|
276
|
+
* incurring a short delay; call {@link prepare} ahead of time to start instantly.
|
|
277
|
+
*/
|
|
227
278
|
async start() {
|
|
228
279
|
await this.rpc.perform({ target: this.target, action: 'start' });
|
|
229
280
|
}
|
|
230
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Pauses the recording. The capture hardware remains active so recording can be resumed quickly.
|
|
284
|
+
*
|
|
285
|
+
* Call {@link resume} to continue recording, or {@link stop} to finish.
|
|
286
|
+
*/
|
|
287
|
+
async pause() {
|
|
288
|
+
await this.rpc.perform({ target: this.target, action: 'pause' });
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Resumes a recording that was previously paused with {@link pause}.
|
|
293
|
+
*/
|
|
294
|
+
async resume() {
|
|
295
|
+
await this.rpc.perform({ target: this.target, action: 'resume' });
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Stops the recording, finalizes the output files, and returns the {@link RecordingResult}
|
|
300
|
+
* describing the completed bundle. The recorder cannot be reused after stopping.
|
|
301
|
+
*
|
|
302
|
+
* @remarks Known limitation: when the recording failed, the returned promise rejects with the
|
|
303
|
+
* failure but the partial recording result is not available over the RPC bridge (the Swift API
|
|
304
|
+
* surfaces it as `PartialResultError`). Any partially-written files do remain on disk in the
|
|
305
|
+
* bundle inside the schema's `output_directory`.
|
|
306
|
+
*/
|
|
231
307
|
async stop(): Promise<RecordingResult> {
|
|
232
308
|
return await this.rpc.perform({ target: this.target, action: 'stop' }) as RecordingResult;
|
|
233
309
|
}
|
|
234
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Cancels the recording and releases its resources without finalizing output. Use this to discard
|
|
313
|
+
* an in-progress or prepared recording; call {@link stop} instead to keep the result.
|
|
314
|
+
*/
|
|
235
315
|
async cancel() {
|
|
236
316
|
await this.rpc.manualRelease(this.target)
|
|
237
317
|
}
|
|
238
318
|
}
|
|
239
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Typed event overloads for {@link Recorder}. Declaration-merges with the class so that
|
|
322
|
+
* `recorder.on('abort', reason => …)` receives a typed {@link AbortReason} instead of `any`.
|
|
323
|
+
*
|
|
324
|
+
* @group Recording
|
|
325
|
+
*/
|
|
326
|
+
export interface Recorder {
|
|
327
|
+
/** Fires when the recording is aborted by an error or a system interruption. */
|
|
328
|
+
on(event: 'abort', listener: (reason: AbortReason) => void): this;
|
|
329
|
+
/** @see {@link Recorder.on} */
|
|
330
|
+
once(event: 'abort', listener: (reason: AbortReason) => void): this;
|
|
331
|
+
/** @see {@link Recorder.on} */
|
|
332
|
+
off(event: 'abort', listener: (reason: AbortReason) => void): this;
|
|
333
|
+
/** @see {@link Recorder.on} */
|
|
334
|
+
emit(event: 'abort', reason: AbortReason): boolean;
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Fires whenever the set of active {@link Signal}s changes, with all signals active at that
|
|
338
|
+
* moment. An empty array means everything is healthy again. Events are asynchronous, so one can
|
|
339
|
+
* still arrive just after {@link Recorder.stop} resolved; the last one is always an empty array.
|
|
340
|
+
*/
|
|
341
|
+
on(event: 'signals', listener: (signals: Signal[]) => void): this;
|
|
342
|
+
/** @see {@link Recorder.on} */
|
|
343
|
+
once(event: 'signals', listener: (signals: Signal[]) => void): this;
|
|
344
|
+
/** @see {@link Recorder.on} */
|
|
345
|
+
off(event: 'signals', listener: (signals: Signal[]) => void): this;
|
|
346
|
+
/** @see {@link Recorder.on} */
|
|
347
|
+
emit(event: 'signals', signals: Signal[]): boolean;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Settings that apply to the whole recording session.
|
|
352
|
+
*
|
|
353
|
+
* @group Recording
|
|
354
|
+
*/
|
|
355
|
+
export interface RecorderSettings {
|
|
356
|
+
/**
|
|
357
|
+
* Specifies if RecordKit is allowed to do frame reordering in video files. Defaults to `true`.
|
|
358
|
+
*
|
|
359
|
+
* When enabled, to achieve the best compression some video encoders can reorder frames and
|
|
360
|
+
* generate B-frames.
|
|
361
|
+
*/
|
|
362
|
+
allowFrameReordering?: boolean
|
|
363
|
+
/**
|
|
364
|
+
* Whether a successful recording updates the user's preferred devices for the sources it used.
|
|
365
|
+
* Defaults to `true`.
|
|
366
|
+
*
|
|
367
|
+
* When enabled, starting a recording sets the devices in the schema as the user's preferred
|
|
368
|
+
* devices (for the device types that support this).
|
|
369
|
+
*/
|
|
370
|
+
updatesUserPreferred?: boolean
|
|
371
|
+
/** Target duration, in whole seconds, of each audio segment when using segmented output. Defaults to `6`. Fractional values are not supported. */
|
|
372
|
+
audioSegmentDuration?: number
|
|
373
|
+
/** Target duration, in whole seconds, of each video segment when using segmented output. Defaults to `2`. Fractional values are not supported. */
|
|
374
|
+
videoSegmentDuration?: number
|
|
375
|
+
/**
|
|
376
|
+
* Maximum interval, in seconds, between keyframes in the video stream. Defaults to no forced
|
|
377
|
+
* interval.
|
|
378
|
+
*
|
|
379
|
+
* When set, the encoder places a keyframe at least every this many seconds. The frame-count based
|
|
380
|
+
* maximum keyframe interval is computed automatically from the video frame rate. When omitted, the
|
|
381
|
+
* encoder uses its default keyframe-placement heuristic.
|
|
382
|
+
*/
|
|
383
|
+
keyframeIntervalDuration?: number
|
|
384
|
+
/**
|
|
385
|
+
* Free disk space, in bytes, below which a running recording is aborted.
|
|
386
|
+
* Defaults to `104857600` (100 MB).
|
|
387
|
+
*
|
|
388
|
+
* While recording, RecordKit periodically checks the actual available capacity of the volume the
|
|
389
|
+
* recording is written to (purgeable/opportunistic space is not counted). Shortly after the
|
|
390
|
+
* available capacity drops below this level the recording is aborted with an
|
|
391
|
+
* `insufficientDiskSpace` error. Keep it high enough to absorb whatever is still written between
|
|
392
|
+
* two checks and to leave room to finalize the recording.
|
|
393
|
+
* Set to `0` to never abort on disk space (record until the disk is full), which may result in a
|
|
394
|
+
* corrupt recording. A `diskSpaceWarningLevel` keeps being reported either way.
|
|
395
|
+
*
|
|
396
|
+
* @see {@link RecorderSettings.diskSpaceWarningLevel}, the higher level that warns instead of
|
|
397
|
+
* aborting.
|
|
398
|
+
*/
|
|
399
|
+
diskSpaceAbortLevel?: number
|
|
400
|
+
/**
|
|
401
|
+
* Free disk space, in bytes, below which the recording volume counts as running low.
|
|
402
|
+
* Defaults to `157286400` (150 MB).
|
|
403
|
+
*
|
|
404
|
+
* Checked once during `prepare()`, which fails with an `insufficientDiskSpace` error when the
|
|
405
|
+
* volume is already below it, and then periodically while recording. Dropping below it during a
|
|
406
|
+
* recording does not interrupt anything, it raises a `lowDiskSpace` {@link Signal} on the
|
|
407
|
+
* `signals` event so your app can warn the user; the signal clears again once enough space is
|
|
408
|
+
* freed up.
|
|
409
|
+
*
|
|
410
|
+
* Set this higher than `diskSpaceAbortLevel` so there is room to warn before the recording is
|
|
411
|
+
* aborted at that lower level. Set to `0` to disable both the prepare-time check and the
|
|
412
|
+
* signal.
|
|
413
|
+
*/
|
|
414
|
+
diskSpaceWarningLevel?: number
|
|
415
|
+
}
|
|
416
|
+
|
|
240
417
|
/**
|
|
241
418
|
* @group Recording
|
|
242
419
|
*/
|
|
@@ -244,6 +421,7 @@ export type RecorderSchemaItem =
|
|
|
244
421
|
| WebcamSchema
|
|
245
422
|
| DisplaySchema
|
|
246
423
|
| WindowBasedCropSchema
|
|
424
|
+
| DesktopIndependentWindowSchema
|
|
247
425
|
| AppleDeviceStaticOrientationSchema
|
|
248
426
|
| AppleDeviceSchema
|
|
249
427
|
| SystemAudioSchema
|
|
@@ -251,101 +429,302 @@ export type RecorderSchemaItem =
|
|
|
251
429
|
| MicrophoneSchema
|
|
252
430
|
|
|
253
431
|
/**
|
|
254
|
-
*
|
|
432
|
+
* A width/height pair. The unit (pixels or points) depends on the consuming API — see the
|
|
433
|
+
* documentation of the specific method or option that takes this value.
|
|
255
434
|
*
|
|
256
435
|
* @group Recording Schemas
|
|
257
436
|
*/
|
|
258
|
-
export
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
437
|
+
export interface Size {
|
|
438
|
+
width: number
|
|
439
|
+
height: number
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Content that can be excluded from a screen recording.
|
|
444
|
+
*
|
|
445
|
+
* - `currentProcess`: Exclude the windows of the process hosting the recorder from the recording.
|
|
446
|
+
* - `screenRecordingIndicator`: Exclude the orange screen-recording indicator from the recording.
|
|
447
|
+
*
|
|
448
|
+
* @remarks From Electron the process hosting the recorder is the bundled `recordkit-rpc` helper,
|
|
449
|
+
* not your app — so `currentProcess` does not exclude your app's own windows. To exclude those,
|
|
450
|
+
* pass your process IDs (e.g. `process.pid`) via the schema item's `excludedProcessIDs`.
|
|
451
|
+
*
|
|
452
|
+
* @group Recording Schemas
|
|
453
|
+
*/
|
|
454
|
+
export type ScreenRecordingExcludeOption = 'currentProcess' | 'screenRecordingIndicator'
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Output configuration for JSON sidecar files such as the mouse/keyboard input-event log.
|
|
458
|
+
*
|
|
459
|
+
* - `singleFile`: Write all events to a single JSON file (optionally named via `filename`).
|
|
460
|
+
* - `segmented`: Write events to multiple segmented JSON files; `segmentCallback` is invoked with the
|
|
461
|
+
* path of each segment as it is written to disk.
|
|
462
|
+
*
|
|
463
|
+
* @group Recording Schemas
|
|
464
|
+
*/
|
|
465
|
+
export type JSONOutputOptions =
|
|
466
|
+
| { output?: 'singleFile', filename?: string }
|
|
467
|
+
| { output: 'segmented', filenamePrefix?: string, segmentCallback?: (url: string) => void }
|
|
468
|
+
|
|
469
|
+
interface WebcamSchemaBase {
|
|
270
470
|
type: 'webcam'
|
|
471
|
+
/** The camera to record, either a {@link Camera} or its `id`. */
|
|
271
472
|
camera: Camera | string
|
|
473
|
+
/** The microphone to record alongside the camera, either a {@link Microphone} or its `id`. */
|
|
272
474
|
microphone: Microphone | string
|
|
475
|
+
/** Caps the output video to at most these dimensions (in pixels), preserving aspect ratio. */
|
|
476
|
+
maxVideoDimensions?: Size
|
|
273
477
|
/** Video codec for the recording. Defaults to 'h264'. */
|
|
274
478
|
videoCodec?: VideoCodec
|
|
479
|
+
/**
|
|
480
|
+
* When `true`, leaves the camera's active format/configuration untouched instead of letting
|
|
481
|
+
* RecordKit reconfigure the device for the requested recording. Defaults to `false`.
|
|
482
|
+
*/
|
|
275
483
|
preserveActiveCameraConfiguration?: boolean
|
|
484
|
+
/** Record only the left channel of the microphone (useful for mono lavalier mics). Defaults to `false`. */
|
|
276
485
|
leftAudioChannelOnly?: boolean
|
|
486
|
+
/** Delay applied to the microphone audio relative to the video, in seconds, to correct lip-sync. Defaults to `0`. */
|
|
277
487
|
audioDelay?: number
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
488
|
+
/** Echo cancellation applied to the microphone audio. Defaults to `'off'`. */
|
|
489
|
+
echoCancellation?: EchoCancellation
|
|
490
|
+
/** Background blur applied to the camera video. Defaults to `'off'`. */
|
|
491
|
+
backgroundBlur?: BackgroundBlur
|
|
281
492
|
}
|
|
282
493
|
|
|
283
494
|
/**
|
|
284
|
-
* Creates a recorder item for
|
|
495
|
+
* Creates a recorder item for a webcam movie file, using the provided microphone and camera. Output is stored in a RecordKit bundle.
|
|
285
496
|
*
|
|
286
497
|
* @group Recording Schemas
|
|
287
498
|
*/
|
|
288
|
-
export type
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
499
|
+
export type WebcamSchema =
|
|
500
|
+
| (WebcamSchemaBase & {
|
|
501
|
+
output?: 'singleFile'
|
|
502
|
+
filename?: string
|
|
503
|
+
})
|
|
504
|
+
| (WebcamSchemaBase & {
|
|
505
|
+
output: 'segmented'
|
|
506
|
+
filenamePrefix?: string
|
|
507
|
+
segmentCallback?: (url: string) => void
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Acoustic echo cancellation applied to microphone audio. Captures system/playback audio via Core
|
|
512
|
+
* Audio process taps and removes it from the microphone signal in real time using WebRTC AEC3.
|
|
513
|
+
*
|
|
514
|
+
* - `'off'`: No echo cancellation (default).
|
|
515
|
+
* - `'aggressive'`: Maximum echo removal at the cost of speech quality — aggressive suppression,
|
|
516
|
+
* high-pass filter, and residual echo gate at 16 kHz. Optimized for speech-to-text pipelines where
|
|
517
|
+
* echo removal matters more than audio fidelity.
|
|
518
|
+
* - `'balanced'`: Balanced echo removal that preserves speech quality — balanced suppression with
|
|
519
|
+
* high-pass filter but no residual echo gate at 48 kHz. Optimized for recording pipelines where
|
|
520
|
+
* audio fidelity is more important than pure echo removal.
|
|
521
|
+
* - An object for full control over the AEC3 configuration; omitted fields default to the `'balanced'`
|
|
522
|
+
* preset.
|
|
523
|
+
*
|
|
524
|
+
* @remarks Requires macOS 14.2 or later (Core Audio process taps). On older versions, preparing the
|
|
525
|
+
* recorder fails with a `configurationNotSupported` error.
|
|
526
|
+
*
|
|
527
|
+
* @group Recording Schemas
|
|
528
|
+
*/
|
|
529
|
+
export type EchoCancellation =
|
|
530
|
+
| 'off'
|
|
531
|
+
| 'aggressive'
|
|
532
|
+
| 'balanced'
|
|
533
|
+
| {
|
|
534
|
+
/**
|
|
535
|
+
* Sample rate the echo canceller runs at, in Hz. Defaults to `48000`. 16 kHz is sufficient for
|
|
536
|
+
* speech-to-text; 48 kHz preserves full audio fidelity.
|
|
537
|
+
*/
|
|
538
|
+
sampleRate?: 16000 | 32000 | 48000
|
|
539
|
+
/**
|
|
540
|
+
* Echo suppression mode. Defaults to `'balanced'`.
|
|
541
|
+
*
|
|
542
|
+
* - `'balanced'`: Conservative suppression that allows AEC3's transparent mode (passes audio
|
|
543
|
+
* through unchanged when no echo is detected) and protects near-end speech during double-talk.
|
|
544
|
+
* Best where speech naturalness matters.
|
|
545
|
+
* - `'aggressive'`: Disables near-end speech detection so echo is suppressed even during
|
|
546
|
+
* double-talk; removes ~2 dB more echo but attenuates speech by 3-5 dB.
|
|
547
|
+
*/
|
|
548
|
+
suppressionMode?: 'balanced' | 'aggressive'
|
|
549
|
+
/**
|
|
550
|
+
* Apply a high-pass filter on the capture signal to remove DC offset and low-frequency noise
|
|
551
|
+
* that can interfere with the adaptive filter. Defaults to `true`.
|
|
552
|
+
*/
|
|
553
|
+
highPassFilter?: boolean
|
|
554
|
+
/**
|
|
555
|
+
* Apply a post-AEC3 gate that attenuates output when the speaker is active but output is quiet
|
|
556
|
+
* (likely residual echo, not speech). Catches echo the suppressor misses, at the cost of
|
|
557
|
+
* occasional clipping of quiet speech. Defaults to `false`.
|
|
558
|
+
*/
|
|
559
|
+
residualEchoGate?: boolean
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Background blur applied to camera video. The person is segmented from each frame using Apple's
|
|
564
|
+
* Vision person segmentation and composited over a Gaussian-blurred copy of the background, keeping
|
|
565
|
+
* the foreground subject sharp while blurring the background.
|
|
566
|
+
*
|
|
567
|
+
* - `'off'`: No background blur (default).
|
|
568
|
+
* - `'balanced'`: Default-quality blur with a moderate background blur radius and soft mask edges.
|
|
569
|
+
* - `'fast'`: Faster, lower-quality blur for lower-end hardware.
|
|
570
|
+
* - An object for full control over the Vision-based configuration; omitted fields default to the
|
|
571
|
+
* `'balanced'` preset.
|
|
572
|
+
*
|
|
573
|
+
* @group Recording Schemas
|
|
574
|
+
*/
|
|
575
|
+
export type BackgroundBlur =
|
|
576
|
+
| 'off'
|
|
577
|
+
| 'balanced'
|
|
578
|
+
| 'fast'
|
|
579
|
+
| {
|
|
580
|
+
/**
|
|
581
|
+
* Trade-off between segmentation speed and accuracy. Defaults to `'balanced'`.
|
|
582
|
+
*
|
|
583
|
+
* - `'accurate'`: Best segmentation quality, highest cost.
|
|
584
|
+
* - `'balanced'`: Default trade-off between quality and cost.
|
|
585
|
+
* - `'fast'`: Lowest cost, suitable for real-time on lower-end hardware.
|
|
586
|
+
*/
|
|
587
|
+
quality?: 'accurate' | 'balanced' | 'fast'
|
|
588
|
+
/**
|
|
589
|
+
* Sigma for the Gaussian blur applied to the background. Larger values produce a stronger blur;
|
|
590
|
+
* `0` disables the blur (the background is the original image). Defaults to `10`.
|
|
591
|
+
*/
|
|
592
|
+
blurRadius?: number
|
|
593
|
+
/**
|
|
594
|
+
* Sigma for the Gaussian blur applied to the segmentation mask to soften foreground/background
|
|
595
|
+
* transitions; `0` keeps the raw mask edges. Defaults to `3`.
|
|
596
|
+
*/
|
|
597
|
+
featherRadius?: number
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
interface DisplaySchemaBase {
|
|
302
601
|
type: 'display'
|
|
602
|
+
/** The display to record, either a {@link Display} or its numeric id. */
|
|
303
603
|
display: Display | number // UInt32
|
|
604
|
+
/** Crop rectangle (in points, top-left origin) within the display. Defaults to the full display. */
|
|
605
|
+
crop?: Bounds
|
|
606
|
+
/**
|
|
607
|
+
* Content to exclude from the recording. Defaults to `['currentProcess', 'screenRecordingIndicator']`.
|
|
608
|
+
* Pass an explicit (possibly empty) array to override the default.
|
|
609
|
+
*/
|
|
610
|
+
excludeOptions?: ScreenRecordingExcludeOption[]
|
|
611
|
+
/** Process IDs of applications to exclude from the recording. */
|
|
612
|
+
excludedProcessIDs?: number[] // Int32
|
|
304
613
|
/** Color space for the recording. Defaults to 'sRGB'. Note: 'displayP3' requires 'hevc' video codec. */
|
|
305
614
|
colorSpace?: ColorSpace
|
|
615
|
+
/** Minimum interval between frames, in seconds. Caps the frame rate (e.g. `1/30` for 30 fps). Defaults to uncapped. */
|
|
616
|
+
minimumFrameInterval?: number
|
|
617
|
+
/** Caps the output video to at most these dimensions (in pixels), preserving aspect ratio. */
|
|
618
|
+
maxVideoDimensions?: Size
|
|
306
619
|
/** Video codec for the recording. Defaults to 'h264'. */
|
|
307
620
|
videoCodec?: VideoCodec
|
|
621
|
+
/** Whether to draw the mouse cursor into the recording. Defaults to `true`. */
|
|
308
622
|
shows_cursor?: boolean
|
|
623
|
+
/** Whether to capture mouse input events into a JSON sidecar file. Defaults to `false`. */
|
|
309
624
|
mouse_events?: boolean
|
|
625
|
+
/** Whether to capture keyboard input events into a JSON sidecar file. Defaults to `false`. */
|
|
310
626
|
keyboard_events?: boolean
|
|
627
|
+
/** Output configuration for the mouse/keyboard input-event JSON sidecar files. */
|
|
628
|
+
inputEventsOutput?: JSONOutputOptions
|
|
629
|
+
/** Whether to also record the display's audio. Defaults to `false`. */
|
|
311
630
|
include_audio?: boolean
|
|
312
|
-
output: 'segmented'
|
|
313
|
-
filenamePrefix?: string
|
|
314
|
-
segmentCallback?: (url: string) => void
|
|
315
631
|
}
|
|
316
632
|
|
|
317
633
|
/**
|
|
318
|
-
* Creates a recorder item for recording
|
|
634
|
+
* Creates a recorder item for recording a single display. Output is stored in a RecordKit bundle.
|
|
319
635
|
*
|
|
320
636
|
* @group Recording Schemas
|
|
321
637
|
*/
|
|
322
|
-
export type
|
|
638
|
+
export type DisplaySchema =
|
|
639
|
+
| (DisplaySchemaBase & {
|
|
640
|
+
output?: 'singleFile'
|
|
641
|
+
filename?: string
|
|
642
|
+
})
|
|
643
|
+
| (DisplaySchemaBase & {
|
|
644
|
+
output: 'segmented'
|
|
645
|
+
filenamePrefix?: string
|
|
646
|
+
segmentCallback?: (url: string) => void
|
|
647
|
+
})
|
|
648
|
+
|
|
649
|
+
interface WindowBasedCropSchemaBase {
|
|
323
650
|
type: 'windowBasedCrop'
|
|
651
|
+
/** The window to record, either a {@link Window} or its numeric id. */
|
|
324
652
|
window: Window | number // UInt32
|
|
325
653
|
/** Color space for the recording. Defaults to 'sRGB'. Note: 'displayP3' requires 'hevc' video codec. */
|
|
326
654
|
colorSpace?: ColorSpace
|
|
655
|
+
/** Minimum interval between frames, in seconds. Caps the frame rate (e.g. `1/30` for 30 fps). Defaults to uncapped. */
|
|
656
|
+
minimumFrameInterval?: number
|
|
657
|
+
/** Caps the output video to at most these dimensions (in pixels), preserving aspect ratio. */
|
|
658
|
+
maxVideoDimensions?: Size
|
|
327
659
|
/** Video codec for the recording. Defaults to 'h264'. */
|
|
328
660
|
videoCodec?: VideoCodec
|
|
661
|
+
/** Whether to draw the mouse cursor into the recording. Defaults to `true`. */
|
|
329
662
|
shows_cursor?: boolean
|
|
663
|
+
/** Whether to capture mouse input events into a JSON sidecar file. Defaults to `false`. */
|
|
330
664
|
mouse_events?: boolean
|
|
665
|
+
/** Whether to capture keyboard input events into a JSON sidecar file. Defaults to `false`. */
|
|
331
666
|
keyboard_events?: boolean
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
667
|
+
/** Output configuration for the mouse/keyboard input-event JSON sidecar files. */
|
|
668
|
+
inputEventsOutput?: JSONOutputOptions
|
|
669
|
+
/** Whether to also record the audio of the window's application. Defaults to `false`. */
|
|
670
|
+
include_audio?: boolean
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Creates a recorder item for recording the initial crop of a window on a display. Output is stored in a RecordKit bundle.
|
|
675
|
+
*
|
|
676
|
+
* @group Recording Schemas
|
|
677
|
+
*/
|
|
678
|
+
export type WindowBasedCropSchema =
|
|
679
|
+
| (WindowBasedCropSchemaBase & {
|
|
680
|
+
output?: 'singleFile'
|
|
681
|
+
filename?: string
|
|
682
|
+
})
|
|
683
|
+
| (WindowBasedCropSchemaBase & {
|
|
684
|
+
output: 'segmented'
|
|
685
|
+
filenamePrefix?: string
|
|
686
|
+
segmentCallback?: (url: string) => void
|
|
687
|
+
})
|
|
688
|
+
|
|
689
|
+
interface DesktopIndependentWindowSchemaBase {
|
|
690
|
+
type: 'desktopIndependentWindow'
|
|
336
691
|
window: Window | number // UInt32
|
|
337
692
|
/** Color space for the recording. Defaults to 'sRGB'. Note: 'displayP3' requires 'hevc' video codec. */
|
|
338
693
|
colorSpace?: ColorSpace
|
|
694
|
+
/** Minimum interval between frames, in seconds. Caps the frame rate (e.g. `1/30` for 30 fps). Defaults to uncapped. */
|
|
695
|
+
minimumFrameInterval?: number
|
|
696
|
+
/** Caps the output video to at most these dimensions (in pixels), preserving aspect ratio. */
|
|
697
|
+
maxVideoDimensions?: Size
|
|
339
698
|
/** Video codec for the recording. Defaults to 'h264'. */
|
|
340
699
|
videoCodec?: VideoCodec
|
|
341
700
|
shows_cursor?: boolean
|
|
342
701
|
mouse_events?: boolean
|
|
343
702
|
keyboard_events?: boolean
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
703
|
+
/** Output configuration for the mouse/keyboard input-event JSON sidecar files. */
|
|
704
|
+
inputEventsOutput?: JSONOutputOptions
|
|
705
|
+
/** Whether to also record the audio of the window's application. Defaults to `false`. */
|
|
706
|
+
include_audio?: boolean
|
|
347
707
|
}
|
|
348
708
|
|
|
709
|
+
/**
|
|
710
|
+
* Creates a recorder item that records a single window, following it across the desktop independently of
|
|
711
|
+
* what is drawn on screen (the window can be moved or partially off-screen and is still captured in full).
|
|
712
|
+
* Output is stored in a RecordKit bundle.
|
|
713
|
+
*
|
|
714
|
+
* @remarks Requires macOS 13.1 or later.
|
|
715
|
+
* @group Recording Schemas
|
|
716
|
+
*/
|
|
717
|
+
export type DesktopIndependentWindowSchema =
|
|
718
|
+
| (DesktopIndependentWindowSchemaBase & {
|
|
719
|
+
output?: 'singleFile'
|
|
720
|
+
filename?: string
|
|
721
|
+
})
|
|
722
|
+
| (DesktopIndependentWindowSchemaBase & {
|
|
723
|
+
output: 'segmented'
|
|
724
|
+
filenamePrefix?: string
|
|
725
|
+
segmentCallback?: (url: string) => void
|
|
726
|
+
})
|
|
727
|
+
|
|
349
728
|
/**
|
|
350
729
|
* Creates a recorder item for an Apple device screen recording, using the provided deviceID. Output is stored in a RecordKit bundle.
|
|
351
730
|
*
|
|
@@ -418,10 +797,14 @@ export type MicrophoneOutputOptionsType = 'singleFile' | 'segmented' | 'stream'
|
|
|
418
797
|
|
|
419
798
|
/**
|
|
420
799
|
* Creates a recorder item for recording system audio. By default current process audio is excluded. Output is stored in a RecordKit bundle.
|
|
421
|
-
*
|
|
800
|
+
*
|
|
422
801
|
* When using `mode: 'exclude'`, all system audio is recorded except for excluded applications.
|
|
423
802
|
* When using `mode: 'include'`, only audio from specified applications is recorded.
|
|
424
|
-
*
|
|
803
|
+
*
|
|
804
|
+
* @remarks The default `excludeOptions: ['currentProcess']` refers to the process hosting the
|
|
805
|
+
* recorder — from Electron that is the bundled `recordkit-rpc` helper, which plays no audio. To
|
|
806
|
+
* exclude your own app's audio, pass its process IDs via `excludedProcessIDs`.
|
|
807
|
+
*
|
|
425
808
|
* @group Recording Schemas
|
|
426
809
|
*/
|
|
427
810
|
export type SystemAudioSchema = {
|
|
@@ -502,33 +885,37 @@ export type ApplicationAudioSchema = {
|
|
|
502
885
|
streamCallback?: (audioBuffer: AudioStreamBuffer) => void
|
|
503
886
|
}
|
|
504
887
|
|
|
888
|
+
interface MicrophoneSchemaCommon {
|
|
889
|
+
type: 'microphone'
|
|
890
|
+
microphone: Microphone | string
|
|
891
|
+
/** Echo cancellation applied to the microphone audio. Defaults to `'off'`. */
|
|
892
|
+
echoCancellation?: EchoCancellation
|
|
893
|
+
}
|
|
894
|
+
|
|
505
895
|
/**
|
|
506
896
|
* Creates a recorder item for an audio file, using the provided microphone. Output is stored in a RecordKit bundle.
|
|
507
|
-
*
|
|
897
|
+
*
|
|
508
898
|
* @group Recording Schemas
|
|
509
899
|
*/
|
|
510
|
-
export type MicrophoneSchema =
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
/** Called with real-time audio buffer data compatible with Web Audio API */
|
|
530
|
-
streamCallback?: (audioBuffer: AudioStreamBuffer) => void
|
|
531
|
-
}
|
|
900
|
+
export type MicrophoneSchema =
|
|
901
|
+
| (MicrophoneSchemaCommon & {
|
|
902
|
+
leftChannelOnly?: boolean
|
|
903
|
+
audioDelay?: number
|
|
904
|
+
output?: 'singleFile'
|
|
905
|
+
filename?: string
|
|
906
|
+
})
|
|
907
|
+
| (MicrophoneSchemaCommon & {
|
|
908
|
+
leftChannelOnly?: boolean
|
|
909
|
+
audioDelay?: number
|
|
910
|
+
output: 'segmented'
|
|
911
|
+
filenamePrefix?: string
|
|
912
|
+
segmentCallback?: (url: string) => void
|
|
913
|
+
})
|
|
914
|
+
| (MicrophoneSchemaCommon & {
|
|
915
|
+
output: 'stream'
|
|
916
|
+
/** Called with real-time audio buffer data compatible with Web Audio API */
|
|
917
|
+
streamCallback?: (audioBuffer: AudioStreamBuffer) => void
|
|
918
|
+
})
|
|
532
919
|
|
|
533
920
|
/**
|
|
534
921
|
* Audio buffer compatible with Web Audio API
|
|
@@ -547,13 +934,54 @@ export interface AudioStreamBuffer {
|
|
|
547
934
|
}
|
|
548
935
|
|
|
549
936
|
|
|
937
|
+
/**
|
|
938
|
+
* A condition detected during a recording that might need the user's attention.
|
|
939
|
+
*
|
|
940
|
+
* Unlike an {@link AbortReason} a signal never ends the recording, it reports something being off
|
|
941
|
+
* while recording continues, so your app can warn the user and let them fix it. A signal stays in
|
|
942
|
+
* the list emitted on the `signals` event for as long as the condition holds.
|
|
943
|
+
*
|
|
944
|
+
* @group Recording
|
|
945
|
+
*/
|
|
946
|
+
export interface Signal {
|
|
947
|
+
/** The kind of condition that was detected. */
|
|
948
|
+
kind: SignalKind
|
|
949
|
+
// The only signal reported today concerns the recording as a whole, so no source is ever sent.
|
|
950
|
+
// The audio signals are what will populate this, along with the SignalSource type below:
|
|
951
|
+
// /** What the signal is about, omitted when it concerns the recording as a whole. */
|
|
952
|
+
// source?: SignalSource
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* The kind of condition a {@link Signal} reports.
|
|
957
|
+
*
|
|
958
|
+
* @group Recording
|
|
959
|
+
*/
|
|
960
|
+
export type SignalKind =
|
|
961
|
+
// Waiting on the audio signals, kept here so the shape is settled:
|
|
962
|
+
// /** The recorded audio is silent, or so quiet it is very likely unusable. */
|
|
963
|
+
// | 'audioSilence'
|
|
964
|
+
/**
|
|
965
|
+
* Free space on the recording volume dropped below
|
|
966
|
+
* {@link RecorderSettings.diskSpaceWarningLevel}. The recording continues, but keeps eating into
|
|
967
|
+
* the space that is left; below {@link RecorderSettings.diskSpaceAbortLevel} it is aborted with
|
|
968
|
+
* an `insufficientDiskSpace` error instead. A paused recording is never aborted, since nothing is
|
|
969
|
+
* being written; it is reported on and aborts after resuming.
|
|
970
|
+
*/
|
|
971
|
+
| 'lowDiskSpace'
|
|
972
|
+
|
|
973
|
+
// The part of the recording a Signal originated from. No cases yet, and TypeScript has no empty
|
|
974
|
+
// union, so it stays commented out until the audio signals land:
|
|
975
|
+
// export type SignalSource =
|
|
976
|
+
// | { type: 'microphone'; id: string; }
|
|
977
|
+
|
|
550
978
|
/**
|
|
551
979
|
* @group Recording
|
|
552
980
|
*/
|
|
553
981
|
export type AbortReason =
|
|
554
982
|
| { reason: 'userStopped'; result: RecordingResult; }
|
|
555
|
-
| { reason: 'interrupted'; result: RecordingResult; error:
|
|
556
|
-
| { reason: 'failed'; error:
|
|
983
|
+
| { reason: 'interrupted'; result: RecordingResult; error: RecordKitError | NSErrorPayload; }
|
|
984
|
+
| { reason: 'failed'; result: RecordingResult; error: RecordKitError | NSErrorPayload; }
|
|
557
985
|
|
|
558
986
|
/**
|
|
559
987
|
* @group Recording
|
|
@@ -570,9 +998,9 @@ export interface RecordingResult {
|
|
|
570
998
|
*/
|
|
571
999
|
export interface RecordKitError {
|
|
572
1000
|
name: "RecordKitError"
|
|
573
|
-
/** Error code, used for grouping related errors */
|
|
574
|
-
code:
|
|
575
|
-
/** Error code number */
|
|
1001
|
+
/** Error code, used for grouping related errors. See {@link RecordKitErrorCode} for the full list of codes. */
|
|
1002
|
+
code: RecordKitErrorCode
|
|
1003
|
+
/** Error code number. See {@link RECORDKIT_ERROR_CODE_NUMBERS}. */
|
|
576
1004
|
codeNumber: number
|
|
577
1005
|
/** Message describing the problem and possible recovery options, intended to be shown directly to the end-user. */
|
|
578
1006
|
message: string
|
|
@@ -581,12 +1009,62 @@ export interface RecordKitError {
|
|
|
581
1009
|
}
|
|
582
1010
|
|
|
583
1011
|
/**
|
|
1012
|
+
* An error produced outside RecordKit's own error domain — a raw `NSError` surfaced over the bridge.
|
|
1013
|
+
*
|
|
1014
|
+
* Distinguished from {@link RecordKitError} by its `name` discriminator. See the
|
|
1015
|
+
* [Logging and Error Handling guide](https://recordkit.dev/guides/logging-and-errors#error-handling).
|
|
1016
|
+
*
|
|
1017
|
+
* @group Recording
|
|
1018
|
+
*/
|
|
1019
|
+
export interface NSErrorPayload {
|
|
1020
|
+
name: "NSError"
|
|
1021
|
+
/** The `NSError` domain (e.g. `"NSOSStatusErrorDomain"`). */
|
|
1022
|
+
errorDomain: string
|
|
1023
|
+
/** The `NSError` code within {@link NSErrorPayload.errorDomain}. */
|
|
1024
|
+
errorCode: number
|
|
1025
|
+
/** Localized, user-facing description of the error. */
|
|
1026
|
+
message: string
|
|
1027
|
+
/** Detailed technical description of this error, used in debugging. */
|
|
1028
|
+
debugDescription: string
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/**
|
|
1032
|
+
* An error raised by the RPC bridge itself rather than by a RecordKit recording — for example
|
|
1033
|
+
* calling a method on a recorder that was already cancelled, requesting a feature that needs a
|
|
1034
|
+
* newer macOS version, or referencing a window or camera that cannot be found.
|
|
1035
|
+
*
|
|
1036
|
+
* Distinguished from {@link RecordKitError} and {@link NSErrorPayload} by its `name` discriminator.
|
|
1037
|
+
*
|
|
1038
|
+
* @group Recording
|
|
1039
|
+
*/
|
|
1040
|
+
export interface RPCErrorPayload {
|
|
1041
|
+
name: "RPCError"
|
|
1042
|
+
/** Message describing the problem, intended to be shown directly to the end-user. */
|
|
1043
|
+
message: string
|
|
1044
|
+
/** The same message as {@link RPCErrorPayload.message}, kept under its legacy field name. */
|
|
1045
|
+
userMessage: string
|
|
1046
|
+
/** Detailed technical description of this error, used in debugging. */
|
|
1047
|
+
debugDescription: string
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Describes a recording bundle's contents (the parsed `recordkit.json`). Mirrors the Swift
|
|
1052
|
+
* `RKBundleInfo`; the per-event sidecar types live in `RecordingMetadata.ts`.
|
|
1053
|
+
*
|
|
584
1054
|
* @group Recording
|
|
585
1055
|
*/
|
|
586
1056
|
export interface BundleInfo {
|
|
587
1057
|
version: 1,
|
|
1058
|
+
/** Total duration of the recording, in seconds. */
|
|
1059
|
+
duration: number,
|
|
588
1060
|
files: {
|
|
589
1061
|
type: 'screen' | 'webcam' | 'audio' | 'mouse' | 'systemAudio' | 'appleDevice' | 'topWindow'
|
|
590
1062
|
filename: string
|
|
1063
|
+
/** Filenames of related sidecar files for this asset (e.g. input-event JSON), relative to the bundle. */
|
|
1064
|
+
related?: string[]
|
|
1065
|
+
/** Logical size of the recorded area, in points (e.g. `2560x1440` for a Retina 5K display). */
|
|
1066
|
+
recordingSize?: { width: number, height: number }
|
|
1067
|
+
/** Dimensions of the output video, in pixels. */
|
|
1068
|
+
videoDimensions?: { width: number, height: number }
|
|
591
1069
|
}[]
|
|
592
1070
|
}
|