@picovoice/eagle-web 0.1.1 → 0.2.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/src/eagle.ts CHANGED
@@ -25,7 +25,15 @@ import {
25
25
 
26
26
  import { simd } from 'wasm-feature-detect';
27
27
 
28
- import { EagleModel, EagleProfile, EagleProfilerEnrollResult } from './types';
28
+ import {
29
+ EagleModel,
30
+ EagleProfile,
31
+ EagleProfilerEnrollResult,
32
+ PvStatus
33
+ } from './types';
34
+
35
+ import * as EagleErrors from './eagle_errors';
36
+ import { pvStatusToException } from './eagle_errors';
29
37
 
30
38
  /**
31
39
  * WebAssembly function types
@@ -74,6 +82,12 @@ type pv_eagle_frame_length_type = () => Promise<number>;
74
82
  type pv_eagle_version_type = () => Promise<number>;
75
83
  type pv_sample_rate_type = () => Promise<number>;
76
84
  type pv_status_to_string_type = (status: number) => Promise<number>;
85
+ type pv_set_sdk_type = (sdk: number) => Promise<void>;
86
+ type pv_get_error_stack_type = (
87
+ messageStack: number,
88
+ messageStackDepth: number
89
+ ) => Promise<number>;
90
+ type pv_free_error_stack_type = (messageStack: number) => Promise<void>;
77
91
 
78
92
  type EagleBaseWasmOutput = {
79
93
  memory: WebAssembly.Memory;
@@ -84,7 +98,13 @@ type EagleBaseWasmOutput = {
84
98
  sampleRate: number;
85
99
  version: string;
86
100
 
101
+ messageStackAddressAddressAddress: number;
102
+ messageStackDepthAddress: number;
103
+
87
104
  pvStatusToString: pv_status_to_string_type;
105
+ pvGetErrorStack: pv_get_error_stack_type;
106
+ pvFreeErrorStack: pv_free_error_stack_type;
107
+
88
108
  exports: any;
89
109
  };
90
110
 
@@ -120,16 +140,20 @@ class EagleBase {
120
140
  protected _wasmMemory: WebAssembly.Memory | undefined;
121
141
  protected readonly _alignedAlloc: CallableFunction;
122
142
  protected readonly _pvFree: pv_free_type;
123
- protected readonly _memoryBuffer: Int16Array;
124
- protected readonly _memoryBufferUint8: Uint8Array;
125
- protected readonly _memoryBufferView: DataView;
126
143
  protected readonly _functionMutex: Mutex;
127
144
 
145
+ protected readonly _pvGetErrorStack: pv_get_error_stack_type;
146
+ protected readonly _pvFreeErrorStack: pv_free_error_stack_type;
147
+
148
+ protected readonly _messageStackAddressAddressAddress: number;
149
+ protected readonly _messageStackDepthAddress: number;
150
+
128
151
  protected static _sampleRate: number;
129
152
  protected static _version: string;
130
153
 
131
154
  protected static _wasm: string;
132
155
  protected static _wasmSimd: string;
156
+ protected static _sdk: string = 'web';
133
157
 
134
158
  protected static _eagleMutex = new Mutex();
135
159
 
@@ -146,9 +170,11 @@ class EagleBase {
146
170
  this._pvFree = handleWasm.pvFree;
147
171
  this._pvError = handleWasm.pvError;
148
172
 
149
- this._memoryBuffer = new Int16Array(handleWasm.memory.buffer);
150
- this._memoryBufferUint8 = new Uint8Array(handleWasm.memory.buffer);
151
- this._memoryBufferView = new DataView(handleWasm.memory.buffer);
173
+ this._pvGetErrorStack = handleWasm.pvGetErrorStack;
174
+ this._pvFreeErrorStack = handleWasm.pvFreeErrorStack;
175
+
176
+ this._messageStackAddressAddressAddress = handleWasm.messageStackAddressAddressAddress;
177
+ this._messageStackDepthAddress = handleWasm.messageStackDepthAddress;
152
178
 
153
179
  this._functionMutex = new Mutex();
154
180
  }
@@ -187,6 +213,10 @@ class EagleBase {
187
213
  }
188
214
  }
189
215
 
216
+ public static setSdk(sdk: string): void {
217
+ EagleBase._sdk = sdk;
218
+ }
219
+
190
220
  protected static async _initBaseWasm(
191
221
  wasmBase64: string,
192
222
  wasmMemorySize: number
@@ -203,6 +233,11 @@ class EagleBase {
203
233
  const pv_sample_rate = exports.pv_sample_rate as pv_sample_rate_type;
204
234
  const pv_status_to_string =
205
235
  exports.pv_status_to_string as pv_status_to_string_type;
236
+ const pv_set_sdk = exports.pv_set_sdk as pv_set_sdk_type;
237
+ const pv_get_error_stack =
238
+ exports.pv_get_error_stack as pv_get_error_stack_type;
239
+ const pv_free_error_stack =
240
+ exports.pv_free_error_stack as pv_free_error_stack_type;
206
241
 
207
242
  const sampleRate = await pv_sample_rate();
208
243
  const versionAddress = await pv_eagle_version();
@@ -211,6 +246,40 @@ class EagleBase {
211
246
  versionAddress
212
247
  );
213
248
 
249
+ const sdkEncoded = new TextEncoder().encode(this._sdk);
250
+ const sdkAddress = await aligned_alloc(
251
+ Uint8Array.BYTES_PER_ELEMENT,
252
+ (sdkEncoded.length + 1) * Uint8Array.BYTES_PER_ELEMENT
253
+ );
254
+ if (!sdkAddress) {
255
+ throw new EagleErrors.EagleOutOfMemoryError(
256
+ 'malloc failed: Cannot allocate memory'
257
+ );
258
+ }
259
+ memoryBufferUint8.set(sdkEncoded, sdkAddress);
260
+ memoryBufferUint8[sdkAddress + sdkEncoded.length] = 0;
261
+ await pv_set_sdk(sdkAddress);
262
+
263
+ const messageStackDepthAddress = await aligned_alloc(
264
+ Int32Array.BYTES_PER_ELEMENT,
265
+ Int32Array.BYTES_PER_ELEMENT
266
+ );
267
+ if (!messageStackDepthAddress) {
268
+ throw new EagleErrors.EagleOutOfMemoryError(
269
+ 'malloc failed: Cannot allocate memory'
270
+ );
271
+ }
272
+
273
+ const messageStackAddressAddressAddress = await aligned_alloc(
274
+ Int32Array.BYTES_PER_ELEMENT,
275
+ Int32Array.BYTES_PER_ELEMENT
276
+ );
277
+ if (!messageStackAddressAddressAddress) {
278
+ throw new EagleErrors.EagleOutOfMemoryError(
279
+ 'malloc failed: Cannot allocate memory'
280
+ );
281
+ }
282
+
214
283
  return {
215
284
  memory: memory,
216
285
  alignedAlloc: aligned_alloc,
@@ -220,10 +289,67 @@ class EagleBase {
220
289
  sampleRate: sampleRate,
221
290
  version: version,
222
291
 
292
+ messageStackAddressAddressAddress: messageStackAddressAddressAddress,
293
+ messageStackDepthAddress: messageStackDepthAddress,
294
+
223
295
  pvStatusToString: pv_status_to_string,
296
+ pvGetErrorStack: pv_get_error_stack,
297
+ pvFreeErrorStack: pv_free_error_stack,
298
+
224
299
  exports: exports,
225
300
  };
226
301
  }
302
+
303
+ /**
304
+ * Releases resources acquired by Eagle
305
+ */
306
+ public async release(): Promise<void> {
307
+ await this._pvFree(this._messageStackAddressAddressAddress);
308
+ await this._pvFree(this._messageStackDepthAddress);
309
+ }
310
+
311
+ protected static async getMessageStack(
312
+ pv_get_error_stack: pv_get_error_stack_type,
313
+ pv_free_error_stack: pv_free_error_stack_type,
314
+ messageStackAddressAddressAddress: number,
315
+ messageStackDepthAddress: number,
316
+ memoryBufferView: DataView,
317
+ memoryBufferUint8: Uint8Array
318
+ ): Promise<string[]> {
319
+ const status = await pv_get_error_stack(
320
+ messageStackAddressAddressAddress,
321
+ messageStackDepthAddress
322
+ );
323
+ if (status !== PvStatus.SUCCESS) {
324
+ throw pvStatusToException(status, 'Unable to get Eagle error state');
325
+ }
326
+
327
+ const messageStackAddressAddress = memoryBufferView.getInt32(
328
+ messageStackAddressAddressAddress,
329
+ true
330
+ );
331
+
332
+ const messageStackDepth = memoryBufferView.getInt32(
333
+ messageStackDepthAddress,
334
+ true
335
+ );
336
+ const messageStack: string[] = [];
337
+ for (let i = 0; i < messageStackDepth; i++) {
338
+ const messageStackAddress = memoryBufferView.getInt32(
339
+ messageStackAddressAddress + i * Int32Array.BYTES_PER_ELEMENT,
340
+ true
341
+ );
342
+ const message = arrayBufferToStringAtIndex(
343
+ memoryBufferUint8,
344
+ messageStackAddress
345
+ );
346
+ messageStack.push(message);
347
+ }
348
+
349
+ await pv_free_error_stack(messageStackAddressAddress);
350
+
351
+ return messageStack;
352
+ }
227
353
  }
228
354
 
229
355
  /**
@@ -296,7 +422,7 @@ export class EagleProfiler extends EagleBase {
296
422
  modelPath: string
297
423
  ): Promise<EagleProfiler> {
298
424
  if (!isAccessKeyValid(accessKey)) {
299
- throw new Error('Invalid AccessKey');
425
+ throw new EagleErrors.EagleInvalidArgumentError('Invalid AccessKey');
300
426
  }
301
427
 
302
428
  return new Promise<EagleProfiler>((resolve, reject) => {
@@ -346,11 +472,11 @@ export class EagleProfiler extends EagleBase {
346
472
  */
347
473
  public async enroll(pcm: Int16Array): Promise<EagleProfilerEnrollResult> {
348
474
  if (!(pcm instanceof Int16Array)) {
349
- throw new Error("The argument 'pcm' must be provided as an Int16Array");
475
+ throw new EagleErrors.EagleInvalidArgumentError("The argument 'pcm' must be provided as an Int16Array");
350
476
  }
351
477
 
352
478
  if (pcm.length > EagleProfiler._maxEnrollSamples) {
353
- throw new Error(
479
+ throw new EagleErrors.EagleInvalidArgumentError(
354
480
  `'pcm' size must be smaller than ${EagleProfiler._maxEnrollSamples}`
355
481
  );
356
482
  }
@@ -359,7 +485,7 @@ export class EagleProfiler extends EagleBase {
359
485
  this._functionMutex
360
486
  .runExclusive(async () => {
361
487
  if (this._wasmMemory === undefined) {
362
- throw new Error('Attempted to call `.enroll()` after release');
488
+ throw new EagleErrors.EagleInvalidStateError('Attempted to call `.enroll()` after release');
363
489
  }
364
490
 
365
491
  const pcmAddress = await this._alignedAlloc(
@@ -367,24 +493,24 @@ export class EagleProfiler extends EagleBase {
367
493
  pcm.length * Int16Array.BYTES_PER_ELEMENT
368
494
  );
369
495
 
370
- const memoryBufferInt16 = new Int16Array(this._wasmMemory.buffer);
371
- memoryBufferInt16.set(pcm, pcmAddress / Int16Array.BYTES_PER_ELEMENT);
372
-
373
496
  const feedbackAddress = await this._alignedAlloc(
374
497
  Int32Array.BYTES_PER_ELEMENT,
375
498
  Int32Array.BYTES_PER_ELEMENT
376
499
  );
377
500
  if (feedbackAddress === 0) {
378
- throw new Error('malloc failed: Cannot allocate memory');
501
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
379
502
  }
380
503
  const percentageAddress = await this._alignedAlloc(
381
504
  Int32Array.BYTES_PER_ELEMENT,
382
505
  Int32Array.BYTES_PER_ELEMENT
383
506
  );
384
507
  if (percentageAddress === 0) {
385
- throw new Error('malloc failed: Cannot allocate memory');
508
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
386
509
  }
387
510
 
511
+ const memoryBufferInt16 = new Int16Array(this._wasmMemory.buffer);
512
+ memoryBufferInt16.set(pcm, pcmAddress / Int16Array.BYTES_PER_ELEMENT);
513
+
388
514
  const status = await this._pvEagleProfilerEnroll(
389
515
  this._objectAddress,
390
516
  pcmAddress,
@@ -397,24 +523,34 @@ export class EagleProfiler extends EagleBase {
397
523
  await this._pvFree(feedbackAddress);
398
524
  await this._pvFree(percentageAddress);
399
525
 
400
- throw new Error(
401
- `enroll failed with status ${arrayBufferToStringAtIndex(
402
- this._memoryBufferUint8,
403
- await this._pvStatusToString(status)
404
- )}`
526
+ const memoryBufferView = new DataView(this._wasmMemory.buffer);
527
+ const memoryBufferUint8 = new Uint8Array(this._wasmMemory.buffer);
528
+
529
+ const messageStack = await EagleProfiler.getMessageStack(
530
+ this._pvGetErrorStack,
531
+ this._pvFreeErrorStack,
532
+ this._messageStackAddressAddressAddress,
533
+ this._messageStackDepthAddress,
534
+ memoryBufferView,
535
+ memoryBufferUint8
405
536
  );
537
+
538
+ throw pvStatusToException(status, "EagleProfiler enroll failed", messageStack);
406
539
  }
407
540
 
408
- const feedback = this._memoryBufferView.getInt32(
541
+ const memoryBufferView = new DataView(this._wasmMemory.buffer);
542
+
543
+ const feedback = memoryBufferView.getInt32(
409
544
  feedbackAddress,
410
545
  true
411
546
  );
412
- await this._pvFree(feedbackAddress);
413
547
 
414
- const percentage = this._memoryBufferView.getFloat32(
548
+ const percentage = memoryBufferView.getFloat32(
415
549
  percentageAddress,
416
550
  true
417
551
  );
552
+
553
+ await this._pvFree(feedbackAddress);
418
554
  await this._pvFree(percentageAddress);
419
555
 
420
556
  return { feedback, percentage };
@@ -439,7 +575,7 @@ export class EagleProfiler extends EagleBase {
439
575
  this._functionMutex
440
576
  .runExclusive(async () => {
441
577
  if (this._wasmMemory === undefined) {
442
- throw new Error('Attempted to call `.export()` after release');
578
+ throw new EagleErrors.EagleInvalidStateError('Attempted to call `.export()` after release');
443
579
  }
444
580
 
445
581
  const profileAddress = await this._alignedAlloc(
@@ -453,15 +589,25 @@ export class EagleProfiler extends EagleBase {
453
589
  );
454
590
  if (status !== PV_STATUS_SUCCESS) {
455
591
  await this._pvFree(profileAddress);
456
- throw new Error(
457
- `export failed with status ${arrayBufferToStringAtIndex(
458
- this._memoryBufferUint8,
459
- await this._pvStatusToString(status)
460
- )}`
592
+
593
+ const memoryBufferView = new DataView(this._wasmMemory.buffer);
594
+ const memoryBufferUint8 = new Uint8Array(this._wasmMemory.buffer);
595
+
596
+ const messageStack = await EagleProfiler.getMessageStack(
597
+ this._pvGetErrorStack,
598
+ this._pvFreeErrorStack,
599
+ this._messageStackAddressAddressAddress,
600
+ this._messageStackDepthAddress,
601
+ memoryBufferView,
602
+ memoryBufferUint8
461
603
  );
604
+
605
+ throw pvStatusToException(status, "EagleProfiler export failed", messageStack);
462
606
  }
463
607
 
464
- const profile = this._memoryBufferUint8.slice(
608
+ const memoryBufferUint8 = new Uint8Array(this._wasmMemory.buffer);
609
+
610
+ const profile = memoryBufferUint8.slice(
465
611
  profileAddress / Uint8Array.BYTES_PER_ELEMENT,
466
612
  profileAddress / Uint8Array.BYTES_PER_ELEMENT +
467
613
  EagleProfiler._profileSize
@@ -488,17 +634,24 @@ export class EagleProfiler extends EagleBase {
488
634
  this._functionMutex
489
635
  .runExclusive(async () => {
490
636
  if (this._wasmMemory === undefined) {
491
- throw new Error('Attempted to call `.reset()` after release');
637
+ throw new EagleErrors.EagleInvalidStateError('Attempted to call `.reset()` after release');
492
638
  }
493
639
 
494
640
  const status = await this._pvEagleProfilerReset(this._objectAddress);
495
641
  if (status !== PV_STATUS_SUCCESS) {
496
- throw new Error(
497
- `reset failed with status ${arrayBufferToStringAtIndex(
498
- this._memoryBufferUint8,
499
- await this._pvStatusToString(status)
500
- )}`
642
+ const memoryBufferView = new DataView(this._wasmMemory.buffer);
643
+ const memoryBufferUint8 = new Uint8Array(this._wasmMemory.buffer);
644
+
645
+ const messageStack = await EagleProfiler.getMessageStack(
646
+ this._pvGetErrorStack,
647
+ this._pvFreeErrorStack,
648
+ this._messageStackAddressAddressAddress,
649
+ this._messageStackDepthAddress,
650
+ memoryBufferView,
651
+ memoryBufferUint8
501
652
  );
653
+
654
+ throw pvStatusToException(status, "EagleProfiler reset failed", messageStack);
502
655
  }
503
656
  })
504
657
  .then(() => {
@@ -514,6 +667,7 @@ export class EagleProfiler extends EagleBase {
514
667
  * Releases resources acquired by Eagle Profiler
515
668
  */
516
669
  public async release(): Promise<void> {
670
+ await super.release();
517
671
  await this._pvEagleProfilerDelete(this._objectAddress);
518
672
  delete this._wasmMemory;
519
673
  this._wasmMemory = undefined;
@@ -548,7 +702,7 @@ export class EagleProfiler extends EagleBase {
548
702
  Int32Array.BYTES_PER_ELEMENT
549
703
  );
550
704
  if (objectAddressAddress === 0) {
551
- throw new Error('malloc failed: Cannot allocate memory');
705
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
552
706
  }
553
707
 
554
708
  const accessKeyAddress = await baseWasmOutput.alignedAlloc(
@@ -556,7 +710,7 @@ export class EagleProfiler extends EagleBase {
556
710
  (accessKey.length + 1) * Uint8Array.BYTES_PER_ELEMENT
557
711
  );
558
712
  if (accessKeyAddress === 0) {
559
- throw new Error('malloc failed: Cannot allocate memory');
713
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
560
714
  }
561
715
  for (let i = 0; i < accessKey.length; i++) {
562
716
  memoryBufferUint8[accessKeyAddress + i] = accessKey.charCodeAt(i);
@@ -569,7 +723,7 @@ export class EagleProfiler extends EagleBase {
569
723
  (modelPathEncoded.length + 1) * Uint8Array.BYTES_PER_ELEMENT
570
724
  );
571
725
  if (modelPathAddress === 0) {
572
- throw new Error('malloc failed: Cannot allocate memory');
726
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
573
727
  }
574
728
  memoryBufferUint8.set(modelPathEncoded, modelPathAddress);
575
729
  memoryBufferUint8[modelPathAddress + modelPathEncoded.length] = 0;
@@ -581,18 +735,22 @@ export class EagleProfiler extends EagleBase {
581
735
  );
582
736
  await baseWasmOutput.pvFree(accessKeyAddress);
583
737
  await baseWasmOutput.pvFree(modelPathAddress);
584
- if (status !== PV_STATUS_SUCCESS) {
585
- const msg = `'pv_eagle_profiler_init' failed with status ${arrayBufferToStringAtIndex(
586
- memoryBufferUint8,
587
- await baseWasmOutput.pvStatusToString(status)
588
- )}`;
589
738
 
590
- throw new Error(
591
- `${msg}\nDetails: ${baseWasmOutput.pvError.getErrorString()}`
739
+ const memoryBufferView = new DataView(baseWasmOutput.memory.buffer);
740
+
741
+ if (status !== PV_STATUS_SUCCESS) {
742
+ const messageStack = await EagleProfiler.getMessageStack(
743
+ baseWasmOutput.pvGetErrorStack,
744
+ baseWasmOutput.pvFreeErrorStack,
745
+ baseWasmOutput.messageStackAddressAddressAddress,
746
+ baseWasmOutput.messageStackDepthAddress,
747
+ memoryBufferView,
748
+ memoryBufferUint8
592
749
  );
750
+
751
+ throw pvStatusToException(status, "EagleProfiler init failed", messageStack, baseWasmOutput.pvError);
593
752
  }
594
753
 
595
- const memoryBufferView = new DataView(baseWasmOutput.memory.buffer);
596
754
  const objectAddress = memoryBufferView.getInt32(objectAddressAddress, true);
597
755
  await baseWasmOutput.pvFree(objectAddressAddress);
598
756
 
@@ -601,7 +759,7 @@ export class EagleProfiler extends EagleBase {
601
759
  Int32Array.BYTES_PER_ELEMENT
602
760
  );
603
761
  if (minEnrollSamplesAddress === 0) {
604
- throw new Error('malloc failed: Cannot allocate memory');
762
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
605
763
  }
606
764
 
607
765
  status = await pv_eagle_profiler_enroll_min_audio_length_samples(
@@ -609,14 +767,18 @@ export class EagleProfiler extends EagleBase {
609
767
  minEnrollSamplesAddress
610
768
  );
611
769
  if (status !== PV_STATUS_SUCCESS) {
612
- const msg = `'pv_eagle_profiler_enroll_min_audio_length_samples' failed with status ${arrayBufferToStringAtIndex(
613
- memoryBufferUint8,
614
- await baseWasmOutput.pvStatusToString(status)
615
- )}`;
616
- throw new Error(
617
- `${msg}\nDetails: ${baseWasmOutput.pvError.getErrorString()}`
770
+ const messageStack = await EagleProfiler.getMessageStack(
771
+ baseWasmOutput.pvGetErrorStack,
772
+ baseWasmOutput.pvFreeErrorStack,
773
+ baseWasmOutput.messageStackAddressAddressAddress,
774
+ baseWasmOutput.messageStackDepthAddress,
775
+ memoryBufferView,
776
+ memoryBufferUint8
618
777
  );
778
+
779
+ throw pvStatusToException(status, "EagleProfiler failed to get min enroll audio length", messageStack, baseWasmOutput.pvError);
619
780
  }
781
+
620
782
  const minEnrollSamples = memoryBufferView.getInt32(
621
783
  minEnrollSamplesAddress,
622
784
  true
@@ -628,7 +790,7 @@ export class EagleProfiler extends EagleBase {
628
790
  Int32Array.BYTES_PER_ELEMENT
629
791
  );
630
792
  if (profileSizeAddress === 0) {
631
- throw new Error('malloc failed: Cannot allocate memory');
793
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
632
794
  }
633
795
 
634
796
  status = await pv_eagle_profiler_export_size(
@@ -636,13 +798,16 @@ export class EagleProfiler extends EagleBase {
636
798
  profileSizeAddress
637
799
  );
638
800
  if (status !== PV_STATUS_SUCCESS) {
639
- const msg = `'pv_eagle_profiler_export_size' failed with status ${arrayBufferToStringAtIndex(
640
- memoryBufferUint8,
641
- await baseWasmOutput.pvStatusToString(status)
642
- )}`;
643
- throw new Error(
644
- `${msg}\nDetails: ${baseWasmOutput.pvError.getErrorString()}`
801
+ const messageStack = await EagleProfiler.getMessageStack(
802
+ baseWasmOutput.pvGetErrorStack,
803
+ baseWasmOutput.pvFreeErrorStack,
804
+ baseWasmOutput.messageStackAddressAddressAddress,
805
+ baseWasmOutput.messageStackDepthAddress,
806
+ memoryBufferView,
807
+ memoryBufferUint8
645
808
  );
809
+
810
+ throw pvStatusToException(status, "EagleProfiler failed to get export size", messageStack, baseWasmOutput.pvError);
646
811
  }
647
812
 
648
813
  const profileSize = memoryBufferView.getInt32(profileSizeAddress, true);
@@ -702,7 +867,7 @@ export class Eagle extends EagleBase {
702
867
  /**
703
868
  * Creates an instance of the Picovoice Eagle Speaker Recognition Engine.
704
869
  *
705
- * @param accessKey: AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)
870
+ * @param accessKey AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)
706
871
  * @param model Eagle model options.
707
872
  * @param model.base64 The model in base64 string to initialize Eagle.
708
873
  * @param model.publicPath The model path relative to the public directory.
@@ -737,11 +902,11 @@ export class Eagle extends EagleBase {
737
902
  speakerProfiles: EagleProfile[]
738
903
  ): Promise<Eagle> {
739
904
  if (!isAccessKeyValid(accessKey)) {
740
- throw new Error('Invalid AccessKey');
905
+ throw new EagleErrors.EagleInvalidArgumentError('Invalid AccessKey');
741
906
  }
742
907
 
743
908
  if (!speakerProfiles || speakerProfiles.length === 0) {
744
- throw new Error('No speaker profiles provided');
909
+ throw new EagleErrors.EagleInvalidArgumentError('No speaker profiles provided');
745
910
  }
746
911
 
747
912
  return new Promise<Eagle>((resolve, reject) => {
@@ -777,11 +942,11 @@ export class Eagle extends EagleBase {
777
942
  */
778
943
  public async process(pcm: Int16Array): Promise<number[]> {
779
944
  if (!(pcm instanceof Int16Array)) {
780
- throw new Error("The argument 'pcm' must be provided as an Int16Array");
945
+ throw new EagleErrors.EagleInvalidArgumentError("The argument 'pcm' must be provided as an Int16Array");
781
946
  }
782
947
 
783
948
  if (pcm.length !== Eagle._frameLength) {
784
- throw new Error(
949
+ throw new EagleErrors.EagleInvalidArgumentError(
785
950
  `Length of input frame (${pcm.length}) does not match required frame length (${Eagle._frameLength})`
786
951
  );
787
952
  }
@@ -790,7 +955,7 @@ export class Eagle extends EagleBase {
790
955
  this._functionMutex
791
956
  .runExclusive(async () => {
792
957
  if (this._wasmMemory === undefined) {
793
- throw new Error('Attempted to call `.process` after release');
958
+ throw new EagleErrors.EagleInvalidStateError('Attempted to call `.process` after release');
794
959
  }
795
960
 
796
961
  const pcmAddress = await this._alignedAlloc(
@@ -808,18 +973,27 @@ export class Eagle extends EagleBase {
808
973
  );
809
974
  await this._pvFree(pcmAddress);
810
975
  if (status !== PV_STATUS_SUCCESS) {
811
- throw new Error(
812
- `process failed with status ${arrayBufferToStringAtIndex(
813
- this._memoryBufferUint8,
814
- await this._pvStatusToString(status)
815
- )}`
976
+ const memoryBufferView = new DataView(this._wasmMemory.buffer);
977
+ const memoryBufferUint8 = new Uint8Array(this._wasmMemory.buffer);
978
+
979
+ const messageStack = await EagleProfiler.getMessageStack(
980
+ this._pvGetErrorStack,
981
+ this._pvFreeErrorStack,
982
+ this._messageStackAddressAddressAddress,
983
+ this._messageStackDepthAddress,
984
+ memoryBufferView,
985
+ memoryBufferUint8
816
986
  );
987
+
988
+ throw pvStatusToException(status, "Eagle process failed", messageStack);
817
989
  }
818
990
 
991
+ const memoryBufferView = new DataView(this._wasmMemory.buffer);
992
+
819
993
  const scores: number[] = [];
820
994
  for (let i = 0; i < this._numSpeakers; i++) {
821
995
  scores.push(
822
- this._memoryBufferView.getFloat32(
996
+ memoryBufferView.getFloat32(
823
997
  this._scoresAddress + i * Float32Array.BYTES_PER_ELEMENT,
824
998
  true
825
999
  )
@@ -847,17 +1021,24 @@ export class Eagle extends EagleBase {
847
1021
  this._functionMutex
848
1022
  .runExclusive(async () => {
849
1023
  if (this._wasmMemory === undefined) {
850
- throw new Error('Attempted to call `.reset` after release');
1024
+ throw new EagleErrors.EagleInvalidStateError('Attempted to call `.reset` after release');
851
1025
  }
852
1026
 
853
1027
  const status = await this._pvEagleReset(this._objectAddress);
854
1028
  if (status !== PV_STATUS_SUCCESS) {
855
- throw new Error(
856
- `reset failed with status ${arrayBufferToStringAtIndex(
857
- this._memoryBufferUint8,
858
- await this._pvStatusToString(status)
859
- )}`
1029
+ const memoryBufferView = new DataView(this._wasmMemory.buffer);
1030
+ const memoryBufferUint8 = new Uint8Array(this._wasmMemory.buffer);
1031
+
1032
+ const messageStack = await EagleProfiler.getMessageStack(
1033
+ this._pvGetErrorStack,
1034
+ this._pvFreeErrorStack,
1035
+ this._messageStackAddressAddressAddress,
1036
+ this._messageStackDepthAddress,
1037
+ memoryBufferView,
1038
+ memoryBufferUint8
860
1039
  );
1040
+
1041
+ throw pvStatusToException(status, "Eagle reset failed", messageStack);
861
1042
  }
862
1043
  })
863
1044
  .then(() => {
@@ -873,6 +1054,7 @@ export class Eagle extends EagleBase {
873
1054
  * Releases resources acquired by Eagle
874
1055
  */
875
1056
  public async release(): Promise<void> {
1057
+ await super.release();
876
1058
  await this._pvFree(this._scoresAddress);
877
1059
  await this._pvEagleDelete(this._objectAddress);
878
1060
  delete this._wasmMemory;
@@ -905,7 +1087,7 @@ export class Eagle extends EagleBase {
905
1087
  Int32Array.BYTES_PER_ELEMENT
906
1088
  );
907
1089
  if (objectAddressAddress === 0) {
908
- throw new Error('malloc failed: Cannot allocate memory');
1090
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
909
1091
  }
910
1092
 
911
1093
  const accessKeyAddress = await baseWasmOutput.alignedAlloc(
@@ -913,7 +1095,7 @@ export class Eagle extends EagleBase {
913
1095
  (accessKey.length + 1) * Uint8Array.BYTES_PER_ELEMENT
914
1096
  );
915
1097
  if (accessKeyAddress === 0) {
916
- throw new Error('malloc failed: Cannot allocate memory');
1098
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
917
1099
  }
918
1100
  for (let i = 0; i < accessKey.length; i++) {
919
1101
  memoryBufferUint8[accessKeyAddress + i] = accessKey.charCodeAt(i);
@@ -926,7 +1108,7 @@ export class Eagle extends EagleBase {
926
1108
  (modelPathEncoded.length + 1) * Uint8Array.BYTES_PER_ELEMENT
927
1109
  );
928
1110
  if (modelPathAddress === 0) {
929
- throw new Error('malloc failed: Cannot allocate memory');
1111
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
930
1112
  }
931
1113
  memoryBufferUint8.set(modelPathEncoded, modelPathAddress);
932
1114
  memoryBufferUint8[modelPathAddress + modelPathEncoded.length] = 0;
@@ -937,7 +1119,7 @@ export class Eagle extends EagleBase {
937
1119
  numSpeakers * Int32Array.BYTES_PER_ELEMENT
938
1120
  );
939
1121
  if (profilesAddressAddress === 0) {
940
- throw new Error('malloc failed: Cannot allocate memory');
1122
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
941
1123
  }
942
1124
  const profilesAddressList: number[] = [];
943
1125
  for (const profile of speakerProfiles) {
@@ -946,7 +1128,7 @@ export class Eagle extends EagleBase {
946
1128
  profile.bytes.length * Uint8Array.BYTES_PER_ELEMENT
947
1129
  );
948
1130
  if (profileAddress === 0) {
949
- throw new Error('malloc failed: Cannot allocate memory');
1131
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
950
1132
  }
951
1133
  memoryBufferUint8.set(profile.bytes, profileAddress);
952
1134
  profilesAddressList.push(profileAddress);
@@ -965,18 +1147,22 @@ export class Eagle extends EagleBase {
965
1147
  await baseWasmOutput.pvFree(accessKeyAddress);
966
1148
  await baseWasmOutput.pvFree(modelPathAddress);
967
1149
  await baseWasmOutput.pvFree(profilesAddressAddress);
968
- if (status !== PV_STATUS_SUCCESS) {
969
- const msg = `'pv_eagle_init' failed with status ${arrayBufferToStringAtIndex(
970
- memoryBufferUint8,
971
- await baseWasmOutput.pvStatusToString(status)
972
- )}`;
973
1150
 
974
- throw new Error(
975
- `${msg}\nDetails: ${baseWasmOutput.pvError.getErrorString()}`
1151
+ const memoryBufferView = new DataView(baseWasmOutput.memory.buffer);
1152
+
1153
+ if (status !== PV_STATUS_SUCCESS) {
1154
+ const messageStack = await EagleProfiler.getMessageStack(
1155
+ baseWasmOutput.pvGetErrorStack,
1156
+ baseWasmOutput.pvFreeErrorStack,
1157
+ baseWasmOutput.messageStackAddressAddressAddress,
1158
+ baseWasmOutput.messageStackDepthAddress,
1159
+ memoryBufferView,
1160
+ memoryBufferUint8
976
1161
  );
1162
+
1163
+ throw pvStatusToException(status, "Eagle init failed", messageStack, baseWasmOutput.pvError);
977
1164
  }
978
1165
 
979
- const memoryBufferView = new DataView(baseWasmOutput.memory.buffer);
980
1166
  const objectAddress = memoryBufferView.getInt32(objectAddressAddress, true);
981
1167
  await baseWasmOutput.pvFree(objectAddressAddress);
982
1168
 
@@ -985,7 +1171,7 @@ export class Eagle extends EagleBase {
985
1171
  numSpeakers * Float32Array.BYTES_PER_ELEMENT
986
1172
  );
987
1173
  if (scoresAddress === 0) {
988
- throw new Error('malloc failed: Cannot allocate memory');
1174
+ throw new EagleErrors.EagleOutOfMemoryError('malloc failed: Cannot allocate memory');
989
1175
  }
990
1176
 
991
1177
  const frameLength = await pv_eagle_frame_length();