speechrecorderng 3.4.4 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +1 -1
  2. package/esm2020/lib/action/action.mjs +3 -3
  3. package/esm2020/lib/audio/audio_display.mjs +7 -9
  4. package/esm2020/lib/audio/audio_player.mjs +13 -26
  5. package/esm2020/lib/audio/capture/capture.mjs +244 -207
  6. package/esm2020/lib/audio/context.mjs +64 -2
  7. package/esm2020/lib/audio/io/stream.mjs +1 -1
  8. package/esm2020/lib/audio/net_audio_buffer.mjs +5 -9
  9. package/esm2020/lib/audio/playback/array_audio_buffer_source_node.mjs +2 -2
  10. package/esm2020/lib/audio/playback/audio_source_worklet_module_loader.mjs +2 -2
  11. package/esm2020/lib/audio/playback/inddb_audio_buffer_source_node.mjs +1 -1
  12. package/esm2020/lib/audio/playback/player.mjs +137 -96
  13. package/esm2020/lib/audio/ui/audio_display_control.mjs +1 -1
  14. package/esm2020/lib/audio/ui/container.mjs +3 -3
  15. package/esm2020/lib/db/inddb.mjs +1 -1
  16. package/esm2020/lib/net/uploader.mjs +31 -28
  17. package/esm2020/lib/speechrecorder/project/project.mjs +1 -1
  18. package/esm2020/lib/speechrecorder/project/project.service.mjs +4 -4
  19. package/esm2020/lib/speechrecorder/recordings/basic_recording.service.mjs +59 -56
  20. package/esm2020/lib/speechrecorder/recordings/recordings.service.mjs +151 -142
  21. package/esm2020/lib/speechrecorder/script/script.service.mjs +1 -1
  22. package/esm2020/lib/speechrecorder/session/audiorecorder.mjs +49 -99
  23. package/esm2020/lib/speechrecorder/session/basicrecorder.mjs +9 -2
  24. package/esm2020/lib/speechrecorder/session/controlpanel.mjs +13 -11
  25. package/esm2020/lib/speechrecorder/session/progress.mjs +1 -1
  26. package/esm2020/lib/speechrecorder/session/prompting.mjs +1 -1
  27. package/esm2020/lib/speechrecorder/session/recorder_combi_pane.mjs +1 -1
  28. package/esm2020/lib/speechrecorder/session/recording_list.mjs +1 -1
  29. package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-meta.component.mjs +3 -3
  30. package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-navi.component.mjs +3 -3
  31. package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-u-i.component.mjs +17 -16
  32. package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-view.component.mjs +13 -14
  33. package/esm2020/lib/speechrecorder/session/recordingfile/recordingfile-service.mjs +145 -135
  34. package/esm2020/lib/speechrecorder/session/session.service.mjs +12 -9
  35. package/esm2020/lib/speechrecorder/session/sessionmanager.mjs +66 -70
  36. package/esm2020/lib/speechrecorder/startstopsignal/startstopsignal.mjs +1 -2
  37. package/esm2020/lib/speechrecorderng.component.mjs +10 -16
  38. package/esm2020/lib/speechrecorderng.module.mjs +1 -1
  39. package/esm2020/lib/spr.module.version.mjs +2 -2
  40. package/esm2020/lib/ui/recordingitem_display.mjs +2 -2
  41. package/fesm2015/speechrecorderng.mjs +1077 -976
  42. package/fesm2015/speechrecorderng.mjs.map +1 -1
  43. package/fesm2020/speechrecorderng.mjs +1074 -976
  44. package/fesm2020/speechrecorderng.mjs.map +1 -1
  45. package/lib/action/action.d.ts +1 -1
  46. package/lib/audio/audio_display.d.ts +1 -3
  47. package/lib/audio/audio_player.d.ts +0 -1
  48. package/lib/audio/capture/capture.d.ts +5 -4
  49. package/lib/audio/context.d.ts +2 -0
  50. package/lib/audio/io/stream.d.ts +1 -1
  51. package/lib/audio/net_audio_buffer.d.ts +2 -4
  52. package/lib/audio/playback/player.d.ts +3 -2
  53. package/lib/net/uploader.d.ts +6 -6
  54. package/lib/speechrecorder/project/project.d.ts +1 -0
  55. package/lib/speechrecorder/project/project.service.d.ts +4 -4
  56. package/lib/speechrecorder/recordings/basic_recording.service.d.ts +2 -2
  57. package/lib/speechrecorder/recordings/recordings.service.d.ts +8 -8
  58. package/lib/speechrecorder/script/script.service.d.ts +2 -2
  59. package/lib/speechrecorder/session/audiorecorder.d.ts +1 -2
  60. package/lib/speechrecorder/session/basicrecorder.d.ts +4 -1
  61. package/lib/speechrecorder/session/controlpanel.d.ts +1 -1
  62. package/lib/speechrecorder/session/recordingfile/recording-file-meta.component.d.ts +1 -0
  63. package/lib/speechrecorder/session/recordingfile/recordingfile-service.d.ts +2 -2
  64. package/lib/speechrecorder/session/session.service.d.ts +2 -2
  65. package/lib/speechrecorder/session/sessionmanager.d.ts +1 -0
  66. package/lib/spr.module.version.d.ts +1 -1
  67. package/package.json +1 -1
@@ -6,17 +6,15 @@ import { HttpErrorResponse, HttpHeaders, HttpClientModule } from '@angular/commo
6
6
  import { timeout } from 'rxjs/operators';
7
7
  import * as i1$1 from '@angular/common';
8
8
  import { CommonModule } from '@angular/common';
9
- import * as i1$2 from '@angular/router';
10
- import { RouterModule } from '@angular/router';
11
9
  import * as i4$1 from '@angular/material/checkbox';
12
10
  import { MatCheckbox, MatCheckboxModule } from '@angular/material/checkbox';
13
11
  import * as i2 from '@angular/material/icon';
14
12
  import { MatIconModule } from '@angular/material/icon';
15
13
  import * as i4 from '@angular/material/tooltip';
16
14
  import { MatTooltipModule } from '@angular/material/tooltip';
17
- import * as i1$3 from '@angular/cdk/layout';
15
+ import * as i1$2 from '@angular/cdk/layout';
18
16
  import { Breakpoints } from '@angular/cdk/layout';
19
- import * as i1$4 from '@angular/material/dialog';
17
+ import * as i1$3 from '@angular/material/dialog';
20
18
  import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
21
19
  import * as i3 from '@angular/material/button';
22
20
  import { MatButtonModule } from '@angular/material/button';
@@ -25,13 +23,15 @@ import * as i3$1 from '@angular/material/progress-spinner';
25
23
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
26
24
  import * as i7 from '@angular/material/progress-bar';
27
25
  import { MatProgressBarModule } from '@angular/material/progress-bar';
26
+ import * as i4$2 from '@angular/router';
27
+ import { RouterModule } from '@angular/router';
28
28
  import * as i3$2 from '@angular/material/card';
29
29
  import { MatCardModule } from '@angular/material/card';
30
30
  import { MatDividerModule } from '@angular/material/divider';
31
31
  import { MatGridListModule } from '@angular/material/grid-list';
32
32
  import * as i6 from '@angular/material/snack-bar';
33
33
  import { MatSnackBarModule } from '@angular/material/snack-bar';
34
- import * as i4$2 from '@angular/material/table';
34
+ import * as i4$3 from '@angular/material/table';
35
35
  import { MatTableDataSource, MatTableModule } from '@angular/material/table';
36
36
  import { MatSelectModule } from '@angular/material/select';
37
37
  import { MatInputModule } from '@angular/material/input';
@@ -95,7 +95,7 @@ class Action {
95
95
  ctrl.disabled = this.disabled;
96
96
  this.controls.push(ctrl);
97
97
  if (actionEventName) {
98
- ctrl.addEventListener(actionEventName, (e) => {
98
+ ctrl.addEventListener(actionEventName, () => {
99
99
  this.perform();
100
100
  });
101
101
  }
@@ -103,7 +103,7 @@ class Action {
103
103
  }
104
104
  }
105
105
  removeControl(ctrl) {
106
- var i = this.controls.indexOf(ctrl);
106
+ const i = this.controls.indexOf(ctrl);
107
107
  if (i >= 0) {
108
108
  this.controls = this.controls.splice(i, 1);
109
109
  }
@@ -944,7 +944,7 @@ class ArrayAudioBufferSourceNode extends AudioSourceNode {
944
944
  }
945
945
  };
946
946
  }
947
- fillBuffer(frameOffset) {
947
+ fillBuffer() {
948
948
  if (this._arrayAudioBuffer && this._audioInputStream && this._aisBufs) {
949
949
  let filled = this.filledFrames;
950
950
  let bufLen = 0;
@@ -1741,7 +1741,7 @@ const aswpStr = "\n" +
1741
1741
  "\n" +
1742
1742
  " let copied=0;\n" +
1743
1743
  " do{\n" +
1744
- " if(this.currentAudioBufferAvail==0){\n" +
1744
+ " if(this.currentAudioBufferAvail===0){\n" +
1745
1745
  " let nxtBuff=this.audioBuffers.shift();\n" +
1746
1746
  " if(nxtBuff){\n" +
1747
1747
  " this.currentAudioBuffer=nxtBuff;\n" +
@@ -1973,9 +1973,8 @@ class IndexedDbAudioBufferSourceNode extends AudioSourceNode {
1973
1973
  }
1974
1974
 
1975
1975
  class NetAudioBuffer extends BasicAudioSource {
1976
- constructor(_audioContext, _recFileService, _baseUrl, _channelCount, _sampleRate, _chunkFrameLen, _frameLen, _uuid = null, _orgFetchChunkFrameLen = _chunkFrameLen) {
1976
+ constructor(_recFileService, _baseUrl, _channelCount, _sampleRate, _chunkFrameLen, _frameLen, _uuid = null, _orgFetchChunkFrameLen = _chunkFrameLen) {
1977
1977
  super();
1978
- this._audioContext = _audioContext;
1979
1978
  this._recFileService = _recFileService;
1980
1979
  this._baseUrl = _baseUrl;
1981
1980
  this._channelCount = _channelCount;
@@ -1993,9 +1992,6 @@ class NetAudioBuffer extends BasicAudioSource {
1993
1992
  get recFileService() {
1994
1993
  return this._recFileService;
1995
1994
  }
1996
- get audioContext() {
1997
- return this._audioContext;
1998
- }
1999
1995
  get baseUrl() {
2000
1996
  return this._baseUrl;
2001
1997
  }
@@ -2033,8 +2029,8 @@ class NetAudioBuffer extends BasicAudioSource {
2033
2029
  toString() {
2034
2030
  return "Indexed db audio buffer. Channels: " + this.channelCount + ", sample rate: " + this.sampleRate + ", chunk frame length: " + this._chunkFrameLen + ", number of chunks: " + this.chunkCount + ", frame length: " + this.frameLen + ", sealed: " + this.sealed();
2035
2031
  }
2036
- static fromChunkAudioBuffer(aCtx, recordingsService, baseUrl, ab, frameLen, orgFetchChunkFrameLen = ab.length) {
2037
- let nab = new NetAudioBuffer(aCtx, recordingsService, baseUrl, ab.numberOfChannels, ab.sampleRate, ab.length, frameLen, null, orgFetchChunkFrameLen);
2032
+ static fromChunkAudioBuffer(recordingsService, baseUrl, ab, frameLen, orgFetchChunkFrameLen = ab.length) {
2033
+ let nab = new NetAudioBuffer(recordingsService, baseUrl, ab.numberOfChannels, ab.sampleRate, ab.length, frameLen, null, orgFetchChunkFrameLen);
2038
2034
  nab.ready();
2039
2035
  return nab;
2040
2036
  }
@@ -2077,7 +2073,7 @@ class NetRandomAccessAudioStream {
2077
2073
  }
2078
2074
  chunk(baseUrl, ci, cb, errCb) {
2079
2075
  let startFrame = ci * this._netAb.orgFetchChunkFrameLen;
2080
- this._netAb.recFileService.chunkAudioRequest(this._netAb.audioContext, baseUrl, startFrame, this._netAb.orgFetchChunkFrameLen).subscribe({
2076
+ this._netAb.recFileService.chunkAudioRequest(baseUrl, startFrame, this._netAb.orgFetchChunkFrameLen).subscribe({
2081
2077
  next: (chDl) => {
2082
2078
  if (chDl) {
2083
2079
  const ab = chDl.decodedAudioBuffer;
@@ -2479,6 +2475,85 @@ class NetAudioBufferSourceNode extends AudioSourceNode {
2479
2475
  }
2480
2476
  }
2481
2477
 
2478
+ class AudioContextProvider {
2479
+ static audioContextInstance() {
2480
+ if (!this._audioContext) {
2481
+ let debugFail = false;
2482
+ if (!window.AudioContext || typeof window.AudioContext !== 'function' || debugFail) {
2483
+ this._audioContext = null;
2484
+ throw new Error('Browser does not support Web Audio API!');
2485
+ }
2486
+ else {
2487
+ console.debug("Get new audio context...");
2488
+ this._audioContext = new window.AudioContext();
2489
+ console.debug("Created new audio context.");
2490
+ this._audioContext.addEventListener('statechange', () => {
2491
+ console.debug("Audio context state changed: " + this._audioContext?.state);
2492
+ });
2493
+ console.debug("Created new audio context with state: " + this._audioContext?.state);
2494
+ }
2495
+ }
2496
+ return this._audioContext;
2497
+ }
2498
+ // public static audioContextInstanceRunning(audioContext?:AudioContext):Promise<AudioContext>{
2499
+ //
2500
+ // return new Promise<AudioContext>((resolve,reject)=>{
2501
+ // let aCtx=audioContext?audioContext:AudioContextProvider.audioContextInstance();
2502
+ // if(aCtx) {
2503
+ // if(aCtx.state==='closed') {
2504
+ // reject(new Error('Audio context already closed.'));
2505
+ // }else if(aCtx.state==='running') {
2506
+ // resolve(aCtx);
2507
+ // }else{
2508
+ // aCtx.resume().then(() => {
2509
+ // if(aCtx) {
2510
+ // resolve(aCtx);
2511
+ // }else{
2512
+ // reject(new Error('Could not get audio context'));
2513
+ // }
2514
+ // }).catch(() => {
2515
+ // reject(new Error('Could not resume audio context'));
2516
+ // })
2517
+ // }
2518
+ // }else{
2519
+ // reject(new Error('Could not get audio context from browser'));
2520
+ // }
2521
+ // });
2522
+ // }
2523
+ // public static decodeAudioData(data:ArrayBuffer,audioContext?:AudioContext):Promise<AudioBuffer>{
2524
+ // return new Promise<AudioBuffer>((resolve,reject)=>{
2525
+ // // decodeAudioData requires an audio context in running state
2526
+ // AudioContextProvider.audioContextInstanceRunning(audioContext).then(
2527
+ // (aCtx)=>{
2528
+ // // Do not use Promise version, which does not work with Safari 13
2529
+ // aCtx.decodeAudioData(data,decodedData => {
2530
+ // resolve(decodedData);
2531
+ // },(reason) => {
2532
+ // reject(reason);
2533
+ // });
2534
+ // }
2535
+ // ).catch((reason)=>{
2536
+ // reject(reason);
2537
+ // })
2538
+ // })
2539
+ // }
2540
+ static decodeAudioData(data) {
2541
+ return new Promise((resolve, reject) => {
2542
+ if (!this._offlineAudioContext) {
2543
+ this._offlineAudioContext = new OfflineAudioContext(1, 44100, 44100);
2544
+ }
2545
+ // Do not use Promise version, which does not work with Safari 13
2546
+ this._offlineAudioContext.decodeAudioData(data, decodedData => {
2547
+ resolve(decodedData);
2548
+ }, (reason) => {
2549
+ reject(reason);
2550
+ });
2551
+ });
2552
+ }
2553
+ }
2554
+ AudioContextProvider._audioContext = null;
2555
+ AudioContextProvider._offlineAudioContext = null;
2556
+
2482
2557
  var EventType;
2483
2558
  (function (EventType) {
2484
2559
  EventType[EventType["CLOSED"] = 0] = "CLOSED";
@@ -2502,8 +2577,9 @@ class AudioPlayerEvent {
2502
2577
  }
2503
2578
  }
2504
2579
  class AudioPlayer {
2505
- constructor(context, listener) {
2580
+ constructor(listener) {
2506
2581
  this.running = false;
2582
+ this.context = null;
2507
2583
  this.ready = false;
2508
2584
  this._audioClip = null;
2509
2585
  this._audioSource = null;
@@ -2511,7 +2587,6 @@ class AudioPlayer {
2511
2587
  this.sourceAudioWorkletNode = null;
2512
2588
  this.playStartTime = null;
2513
2589
  this.timerVar = null;
2514
- this.context = context;
2515
2590
  this.listener = listener;
2516
2591
  this.bufSize = AudioPlayer.DEFAULT_BUFSIZE;
2517
2592
  this.n = navigator;
@@ -2528,15 +2603,23 @@ class AudioPlayer {
2528
2603
  this._stopAction = new Action('Stop');
2529
2604
  this._stopAction.disabled = true;
2530
2605
  this._stopAction.onAction = () => this.stop();
2531
- this.context.addEventListener('statechange', (ev) => {
2532
- if (this.context.state !== 'running') {
2533
- this.stop();
2534
- }
2535
- });
2536
2606
  }
2537
2607
  get autoPlayOnSelectToggleAction() {
2538
2608
  return this._autoPlayOnSelectToggleAction;
2539
2609
  }
2610
+ _audioContext() {
2611
+ if (!this.context) {
2612
+ this.context = AudioContextProvider.audioContextInstance();
2613
+ if (this.context) {
2614
+ this.context.addEventListener('statechange', (ev) => {
2615
+ if (this.context && this.context.state !== 'running') {
2616
+ this.stop();
2617
+ }
2618
+ });
2619
+ }
2620
+ }
2621
+ return this.context;
2622
+ }
2540
2623
  get startAction() {
2541
2624
  return this._startAction;
2542
2625
  }
@@ -2555,9 +2638,9 @@ class AudioPlayer {
2555
2638
  chs = audioDataHolder.numberOfChannels;
2556
2639
  if (chs > 0) {
2557
2640
  length = audioDataHolder.frameLen;
2558
- if (chs > this.context.destination.maxChannelCount) {
2559
- // TODO exception
2560
- }
2641
+ //if (chs > this.context.destination.maxChannelCount) {
2642
+ // // TODO exception
2643
+ //}
2561
2644
  }
2562
2645
  this.audioSource = audioDataHolder.audioSource;
2563
2646
  audioClip.addSelectionObserver((ac) => {
@@ -2577,16 +2660,11 @@ class AudioPlayer {
2577
2660
  set audioSource(value) {
2578
2661
  this.stop();
2579
2662
  this._audioSource = value;
2580
- if (this._audioSource && this.context) {
2581
- if (this._audioSource instanceof AudioBufferSource) {
2582
- this.ready = true;
2583
- this.updateStartActions();
2584
- if (this.listener) {
2585
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
2586
- }
2587
- }
2588
- else {
2589
- this._loadSourceWorkletAndInitStart();
2663
+ if (this._audioSource) {
2664
+ this.ready = true;
2665
+ this.updateStartActions();
2666
+ if (this.listener) {
2667
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
2590
2668
  }
2591
2669
  }
2592
2670
  else {
@@ -2598,24 +2676,27 @@ class AudioPlayer {
2598
2676
  }
2599
2677
  }
2600
2678
  _loadSourceWorkletAndInitStart() {
2601
- AudioSourceWorkletModuleLoader.loadModule(this.context).then(() => {
2602
- //console.debug("Player ready. ( by Player::_loadSourceWorkletAndInitStart()");
2603
- this.ready = true;
2604
- this.updateStartActions();
2605
- if (this.listener) {
2606
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
2607
- }
2608
- }).catch((error) => {
2609
- this.ready = false;
2610
- this.updateStartActions();
2611
- if (this.listener) {
2612
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
2613
- }
2614
- console.error('Could not add module ' + error);
2615
- });
2679
+ if (this.context) {
2680
+ AudioSourceWorkletModuleLoader.loadModule(this.context).then(() => {
2681
+ //console.debug("Player ready. ( by Player::_loadSourceWorkletAndInitStart()");
2682
+ this.ready = true;
2683
+ this.updateStartActions();
2684
+ if (this.listener) {
2685
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
2686
+ }
2687
+ }).catch((error) => {
2688
+ this.ready = false;
2689
+ this.updateStartActions();
2690
+ if (this.listener) {
2691
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
2692
+ }
2693
+ console.error('Could not add module ' + error);
2694
+ });
2695
+ }
2616
2696
  }
2617
2697
  _startAudioSourceWorkletNode() {
2618
- if (this.sourceAudioWorkletNode) {
2698
+ this._loadSourceWorkletAndInitStart();
2699
+ if (this.context && this.sourceAudioWorkletNode) {
2619
2700
  this.sourceAudioWorkletNode.onprocessorerror = (ev) => {
2620
2701
  let msg = 'Unknwon error';
2621
2702
  if (ev instanceof ErrorEvent) {
@@ -2642,16 +2723,25 @@ class AudioPlayer {
2642
2723
  }
2643
2724
  }
2644
2725
  start() {
2645
- if (!this._startAction.disabled && !this.running) {
2646
- if (this.context.state !== 'running') {
2647
- this.context.resume().then(() => {
2726
+ this._audioContext();
2727
+ if (this.context) {
2728
+ if (!this._startAction.disabled && !this.running) {
2729
+ if (this.context.state === 'suspended') {
2730
+ this.context.resume().then(() => {
2731
+ this._start();
2732
+ }).catch((reason) => {
2733
+ console.error(reason.message());
2734
+ throw reason;
2735
+ });
2736
+ }
2737
+ else if (this.context.state === 'closed') {
2738
+ const msg = 'Error: Cannot start playback. Audio context is already closed!';
2739
+ console.error(msg);
2740
+ throw new Error(msg);
2741
+ }
2742
+ else {
2648
2743
  this._start();
2649
- }).catch((reason) => {
2650
- console.error('Could not resume audio context: ' + reason);
2651
- });
2652
- }
2653
- else {
2654
- this._start();
2744
+ }
2655
2745
  }
2656
2746
  }
2657
2747
  }
@@ -2676,9 +2766,12 @@ class AudioPlayer {
2676
2766
  }
2677
2767
  }
2678
2768
  startSelectionDisabled() {
2679
- return !(this._audioClip && this.context && !this.startAction.disabled && this._audioClip.selection);
2769
+ return !(this._audioClip && !this.startAction.disabled && this._audioClip.selection);
2680
2770
  }
2681
2771
  _start(playSelection = false) {
2772
+ if (!this.context) {
2773
+ throw new Error("Could not get audio context!");
2774
+ }
2682
2775
  if (this._audioSource instanceof AudioBufferSource) {
2683
2776
  this.sourceBufferNode = this.context.createBufferSource();
2684
2777
  this.sourceBufferNode.buffer = this._audioSource.audioBuffer;
@@ -2709,68 +2802,90 @@ class AudioPlayer {
2709
2802
  }
2710
2803
  }
2711
2804
  else if (this._audioSource instanceof ArrayAudioBuffer || this._audioSource instanceof IndexedDbAudioBuffer || this._audioSource instanceof NetAudioBuffer) {
2712
- this.playStartTime = null;
2713
- if (this._audioSource instanceof ArrayAudioBuffer) {
2714
- const aabsn = new ArrayAudioBufferSourceNode(this.context);
2715
- aabsn.arrayAudioBuffer = this._audioSource;
2716
- this.sourceAudioWorkletNode = aabsn;
2717
- }
2718
- else if (this._audioSource instanceof IndexedDbAudioBuffer) {
2719
- const iasn = new IndexedDbAudioBufferSourceNode(this.context);
2720
- iasn.inddbAudioBuffer = this._audioSource;
2721
- this.sourceAudioWorkletNode = iasn;
2722
- }
2723
- else if (this._audioSource instanceof NetAudioBuffer) {
2724
- const nabsn = new NetAudioBufferSourceNode(this.context);
2725
- nabsn.netAudioBuffer = this._audioSource;
2726
- this.sourceAudioWorkletNode = nabsn;
2727
- }
2728
- if (this.sourceAudioWorkletNode) {
2729
- this.sourceAudioWorkletNode.onprocessorerror = (ev) => {
2730
- let msg = 'Unknwon error';
2731
- if (ev instanceof ErrorEvent) {
2732
- msg = ev.message;
2805
+ AudioSourceWorkletModuleLoader.loadModule(this.context).then(() => {
2806
+ this.playStartTime = null;
2807
+ if (this.context) {
2808
+ if (this._audioSource instanceof ArrayAudioBuffer) {
2809
+ const aabsn = new ArrayAudioBufferSourceNode(this.context);
2810
+ aabsn.arrayAudioBuffer = this._audioSource;
2811
+ this.sourceAudioWorkletNode = aabsn;
2733
2812
  }
2734
- console.error("Audio source worklet error: " + msg);
2735
- if (this.listener) {
2736
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.ERROR));
2813
+ else if (this._audioSource instanceof IndexedDbAudioBuffer) {
2814
+ const iasn = new IndexedDbAudioBufferSourceNode(this.context);
2815
+ iasn.inddbAudioBuffer = this._audioSource;
2816
+ this.sourceAudioWorkletNode = iasn;
2817
+ }
2818
+ else if (this._audioSource instanceof NetAudioBuffer) {
2819
+ const nabsn = new NetAudioBufferSourceNode(this.context);
2820
+ nabsn.netAudioBuffer = this._audioSource;
2821
+ this.sourceAudioWorkletNode = nabsn;
2822
+ }
2823
+ if (this.sourceAudioWorkletNode) {
2824
+ this.sourceAudioWorkletNode.onprocessorerror = (ev) => {
2825
+ let msg = 'Unknwon error';
2826
+ if (ev instanceof ErrorEvent) {
2827
+ msg = ev.message;
2828
+ }
2829
+ console.error("Audio source worklet error: " + msg);
2830
+ if (this.listener) {
2831
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.ERROR));
2832
+ }
2833
+ };
2834
+ this.sourceAudioWorkletNode.connect(this.context.destination); // this already starts playing
2835
+ this.sourceAudioWorkletNode.onended = () => this.onended();
2836
+ this.running = true;
2837
+ const ac = this._audioClip;
2838
+ let offset = 0;
2839
+ if (playSelection && ac && ac.selection) {
2840
+ const s = ac.selection;
2841
+ const sr = ac.audioDataHolder.sampleRate;
2842
+ offset = s.leftFrame / sr;
2843
+ const stopPosInsecs = s.rightFrame / sr;
2844
+ const dur = stopPosInsecs - offset;
2845
+ this.sourceAudioWorkletNode.start(0, offset, dur);
2846
+ }
2847
+ else {
2848
+ this.sourceAudioWorkletNode.start();
2849
+ }
2850
+ //this.playStartTime = this.context.currentTime - offset;
2851
+ this._startAction.disabled = true;
2852
+ this._startSelectionAction.disabled = true;
2853
+ this._stopAction.disabled = false;
2854
+ if (this.listener) {
2855
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
2856
+ }
2737
2857
  }
2738
- };
2739
- this.sourceAudioWorkletNode.connect(this.context.destination); // this already starts playing
2740
- this.sourceAudioWorkletNode.onended = () => this.onended();
2741
- this.running = true;
2742
- const ac = this._audioClip;
2743
- let offset = 0;
2744
- if (playSelection && ac && ac.selection) {
2745
- const s = ac.selection;
2746
- const sr = ac.audioDataHolder.sampleRate;
2747
- offset = s.leftFrame / sr;
2748
- const stopPosInsecs = s.rightFrame / sr;
2749
- const dur = stopPosInsecs - offset;
2750
- this.sourceAudioWorkletNode.start(0, offset, dur);
2751
- }
2752
- else {
2753
- this.sourceAudioWorkletNode.start();
2754
2858
  }
2755
- //this.playStartTime = this.context.currentTime - offset;
2756
- this._startAction.disabled = true;
2757
- this._startSelectionAction.disabled = true;
2758
- this._stopAction.disabled = false;
2859
+ }).catch((error) => {
2860
+ console.error(error.message);
2861
+ this.ready = false;
2862
+ this.updateStartActions();
2759
2863
  if (this.listener) {
2760
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
2864
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
2761
2865
  }
2762
- }
2866
+ throw error;
2867
+ });
2763
2868
  }
2764
2869
  }
2765
2870
  startSelected() {
2871
+ this._audioContext();
2872
+ if (!this.context) {
2873
+ throw new Error("Could not get audio context!");
2874
+ }
2766
2875
  if (!this._startAction.disabled && !this.running) {
2767
- if (this.context.state !== 'running') {
2876
+ if (this.context.state === 'suspended') {
2768
2877
  this.context.resume().then(() => {
2769
2878
  this._start(true);
2770
2879
  }).catch((reason) => {
2771
- console.error('Could not resume audio context: ' + reason);
2880
+ console.error(reason.message);
2881
+ throw reason;
2772
2882
  });
2773
2883
  }
2884
+ else if (this.context.state === 'closed') {
2885
+ const msg = 'Error: Cannot start playback of selection. Audio context is already closed!';
2886
+ console.error(msg);
2887
+ throw new Error(msg);
2888
+ }
2774
2889
  else {
2775
2890
  this._start(true);
2776
2891
  }
@@ -2807,7 +2922,7 @@ class AudioPlayer {
2807
2922
  }
2808
2923
  get playPositionTime() {
2809
2924
  let ppt = null;
2810
- if (this.playStartTime !== null) {
2925
+ if (this.context && this.playStartTime !== null) {
2811
2926
  ppt = this.context.currentTime - this.playStartTime;
2812
2927
  }
2813
2928
  else if (this.sourceAudioWorkletNode) {
@@ -3149,8 +3264,10 @@ const awpStr = "class AudioCaptureInterceptorProcessor extends AudioWorkletProce
3149
3264
  "\n" +
3150
3265
  "registerProcessor('capture-interceptor',AudioCaptureInterceptorProcessor);\n";
3151
3266
  class AudioCapture {
3152
- constructor(context) {
3267
+ //private context:AudioContext|null=null;
3268
+ constructor() {
3153
3269
  this._maxAutoNetMemStoreSamples = AudioCapture.DEFAULT_MAX_NET_AUTO_MEM_STORE_SAMPLES;
3270
+ this.context = null;
3154
3271
  this._recUUID = null;
3155
3272
  this.agcStatus = null;
3156
3273
  this.bufferingNode = null;
@@ -3165,13 +3282,7 @@ class AudioCapture {
3165
3282
  this.persisted = true;
3166
3283
  this.persistError = null;
3167
3284
  this.inddbAudioBuffer = null;
3168
- this.context = context;
3169
3285
  this.n = navigator;
3170
- this.context.addEventListener('statechange', (ev) => {
3171
- if (this.context.state !== 'running') {
3172
- this.close();
3173
- }
3174
- });
3175
3286
  }
3176
3287
  get maxAutoNetMemStoreSamples() {
3177
3288
  return this._maxAutoNetMemStoreSamples;
@@ -3200,6 +3311,19 @@ class AudioCapture {
3200
3311
  get opened() {
3201
3312
  return this._opened;
3202
3313
  }
3314
+ _audioContext() {
3315
+ if (!this.context) {
3316
+ this.context = AudioContextProvider.audioContextInstance();
3317
+ if (this.context) {
3318
+ this.context.addEventListener('statechange', () => {
3319
+ if (this.context && this.context.state !== 'running') {
3320
+ this.close();
3321
+ }
3322
+ });
3323
+ }
3324
+ }
3325
+ return this.context;
3326
+ }
3203
3327
  initData() {
3204
3328
  if (!this._recUUID) {
3205
3329
  this._recUUID = UUID.generate();
@@ -3314,119 +3438,137 @@ class AudioCapture {
3314
3438
  }
3315
3439
  }
3316
3440
  addCaptureInterceptor() {
3317
- const awn = new AudioWorkletNode(this.context, 'capture-interceptor');
3318
- awn.onprocessorerror = (ev) => {
3319
- let msg = 'Unknwon error';
3320
- if (ev instanceof ErrorEvent) {
3321
- msg = ev.message;
3322
- }
3323
- console.error("Capture audio worklet error: " + msg);
3324
- if (this.listener) {
3325
- this.listener.error(msg);
3326
- }
3327
- };
3328
- let awnPt = awn.port;
3329
- if (awnPt) {
3330
- awnPt.onmessage = (ev) => {
3331
- if (this.capturing) {
3332
- let dt = ev.data;
3333
- let chs = dt.chs;
3334
- let adaLen = dt.data.length;
3335
- if (DEBUG_TRACE_LEVEL > 8) {
3336
- console.debug('Received data from worklet: ' + chs + ' ' + dt.len + ' Data chs: ' + adaLen);
3337
- }
3338
- let chunk = new Array(chs);
3339
- const samples = this.framesRecorded * chs;
3340
- if ((AudioStorageType.MEM_ENTIRE_AUTO_NET_CHUNKED === this.audioStorageType || AudioStorageType.MEM_CHUNKED_AUTO_NET_CHUNKED === this.audioStorageType) && this.data && samples > this._maxAutoNetMemStoreSamples) {
3341
- this.data = null;
3342
- }
3343
- //console.debug("Data initialized: "+(this.data!=null));
3344
- for (let ch = 0; ch < chs; ch++) {
3345
- //console.debug("Data ch initialized: "+(this.data !=null && this.data[ch] !=null));
3346
- if (ch < this.channelCount) {
3347
- if (dt.data[ch]) {
3348
- let fa = new Float32Array(dt.data[ch]);
3349
- if (this.data && this.data[ch]) {
3350
- this.data[ch].push(fa);
3351
- }
3352
- chunk[ch] = fa;
3353
- // Use samples of channel 0 to count frames (samples)
3354
- if (ch == 0) {
3355
- this.framesRecorded += fa.length;
3356
- }
3357
- }
3441
+ if (this.context) {
3442
+ const awn = new AudioWorkletNode(this.context, 'capture-interceptor');
3443
+ awn.onprocessorerror = (ev) => {
3444
+ let msg = 'Unknwon error';
3445
+ if (ev instanceof ErrorEvent) {
3446
+ msg = ev.message;
3447
+ }
3448
+ console.error("Capture audio worklet error: " + msg);
3449
+ if (this.listener) {
3450
+ this.listener.error(msg);
3451
+ }
3452
+ };
3453
+ let awnPt = awn.port;
3454
+ if (awnPt) {
3455
+ awnPt.onmessage = (ev) => {
3456
+ if (this.capturing) {
3457
+ let dt = ev.data;
3458
+ let chs = dt.chs;
3459
+ let adaLen = dt.data.length;
3460
+ if (DEBUG_TRACE_LEVEL > 8) {
3461
+ console.debug('Received data from worklet: ' + chs + ' ' + dt.len + ' Data chs: ' + adaLen);
3358
3462
  }
3359
- }
3360
- if (this.audioOutStream) {
3361
- try {
3362
- this.audioOutStream.write(chunk);
3363
- // // Random test error:
3364
- // if(Math.random()>0.98) {
3365
- // throw new Error('Test');
3366
- // }
3463
+ let chunk = new Array(chs);
3464
+ const samples = this.framesRecorded * chs;
3465
+ if ((AudioStorageType.MEM_ENTIRE_AUTO_NET_CHUNKED === this.audioStorageType || AudioStorageType.MEM_CHUNKED_AUTO_NET_CHUNKED === this.audioStorageType) && this.data && samples > this._maxAutoNetMemStoreSamples) {
3466
+ this.data = null;
3367
3467
  }
3368
- catch (err) {
3369
- if (err instanceof Error) {
3370
- this.persistError = err;
3371
- }
3372
- else {
3373
- this.persistError = new Error('Error handling recorded audio data');
3468
+ //console.debug("Data initialized: "+(this.data!=null));
3469
+ for (let ch = 0; ch < chs; ch++) {
3470
+ //console.debug("Data ch initialized: "+(this.data !=null && this.data[ch] !=null));
3471
+ if (ch < this.channelCount) {
3472
+ if (dt.data[ch]) {
3473
+ let fa = new Float32Array(dt.data[ch]);
3474
+ if (this.data && this.data[ch]) {
3475
+ this.data[ch].push(fa);
3476
+ }
3477
+ chunk[ch] = fa;
3478
+ // Use samples of channel 0 to count frames (samples)
3479
+ if (ch == 0) {
3480
+ this.framesRecorded += fa.length;
3481
+ }
3482
+ }
3374
3483
  }
3375
- console.error("Capture error: " + err);
3484
+ }
3485
+ if (this.audioOutStream) {
3376
3486
  try {
3377
- this.stop();
3378
- }
3379
- catch (err2) {
3380
- console.error("Capture next error (ignored): " + err2);
3487
+ this.audioOutStream.write(chunk);
3488
+ // // Random test error:
3489
+ // if(Math.random()>0.98) {
3490
+ // throw new Error('Test');
3491
+ // }
3381
3492
  }
3382
- finally {
3383
- if (this.listener) {
3384
- let errExpl = '';
3385
- if (err instanceof DOMException) {
3386
- errExpl = ': ' + err.name + ': ' + err.message;
3387
- }
3388
- this.listener.error("Could not handle recorded audio data" + errExpl, "Please try to record again.");
3493
+ catch (err) {
3494
+ if (err instanceof Error) {
3495
+ this.persistError = err;
3389
3496
  }
3390
3497
  else {
3391
- this.close();
3498
+ this.persistError = new Error('Error handling recorded audio data');
3499
+ }
3500
+ console.error("Capture error: " + err);
3501
+ try {
3502
+ this.stop();
3503
+ }
3504
+ catch (err2) {
3505
+ console.error("Capture next error (ignored): " + err2);
3506
+ }
3507
+ finally {
3508
+ if (this.listener) {
3509
+ let errExpl = '';
3510
+ if (err instanceof DOMException) {
3511
+ errExpl = ': ' + err.name + ': ' + err.message;
3512
+ }
3513
+ this.listener.error("Could not handle recorded audio data" + errExpl, "Please try to record again.");
3514
+ }
3515
+ else {
3516
+ this.close();
3517
+ }
3392
3518
  }
3393
3519
  }
3394
3520
  }
3521
+ if (AudioStorageType.DB_CHUNKED === this._audioStorageType && this._persistentAudioStorageTarget) {
3522
+ this.store();
3523
+ }
3395
3524
  }
3396
- if (AudioStorageType.DB_CHUNKED === this._audioStorageType && this._persistentAudioStorageTarget) {
3397
- this.store();
3398
- }
3399
- }
3400
- };
3401
- }
3402
- // Tried to fix that Safari does not record the second channel
3403
- // Does not help
3404
- //awn.channelCount=this.channelCount;
3405
- //awn.channelCountMode='explicit';
3406
- //console.debug('Channel count explicitly set to '+this.channelCount);
3407
- this.bufferingNode = awn;
3408
- //this.bufferingNode.channelCount=this.channelCount;
3409
- this._opened = true;
3410
- if (this.listener) {
3411
- this.listener.opened();
3525
+ };
3526
+ }
3527
+ // Tried to fix that Safari does not record the second channel
3528
+ // Does not help
3529
+ //awn.channelCount=this.channelCount;
3530
+ //awn.channelCountMode='explicit';
3531
+ //console.debug('Channel count explicitly set to '+this.channelCount);
3532
+ this.bufferingNode = awn;
3533
+ //this.bufferingNode.channelCount=this.channelCount;
3534
+ this._opened = true;
3535
+ if (this.listener) {
3536
+ this.listener.opened();
3537
+ }
3412
3538
  }
3413
3539
  }
3414
- open(channelCount, selDeviceId, autoGainControlConfigs) {
3540
+ open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation) {
3415
3541
  //console.debug("Capture open: ctx state: "+this.context.state);
3416
- if (this.context.state !== 'running') {
3542
+ this.context = this._audioContext();
3543
+ if (!this.context) {
3544
+ throw new Error("Could not get audio context!");
3545
+ }
3546
+ if (this.context.state === 'suspended') {
3417
3547
  //console.debug("Capture open: Resume context");
3418
3548
  this.context.resume().then(() => {
3419
3549
  //console.debug("Capture open (ctx resumed): ctx state: "+this.context.state);
3420
- this._open(channelCount, selDeviceId, autoGainControlConfigs);
3550
+ this._open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation);
3551
+ }).catch((err) => {
3552
+ console.error(err.message);
3553
+ throw err;
3421
3554
  });
3422
3555
  }
3556
+ else if (this.context.state === 'closed') {
3557
+ const msg = 'Error on start capture: The audio context is already closed.';
3558
+ console.error(msg);
3559
+ throw new Error(msg);
3560
+ }
3423
3561
  else {
3424
- this._open(channelCount, selDeviceId, autoGainControlConfigs);
3562
+ this._open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation);
3425
3563
  }
3426
3564
  }
3427
- _open(channelCount, selDeviceId, autoGainControlConfigs) {
3565
+ _open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation) {
3428
3566
  this.channelCount = channelCount;
3429
3567
  this.framesRecorded = 0;
3568
+ this.context = this._audioContext();
3569
+ if (!this.context) {
3570
+ throw new Error("Could not get audio context!");
3571
+ }
3430
3572
  //var msc = new AudioStreamConstr();
3431
3573
  // var msc={};
3432
3574
  //msc.video = false;
@@ -3534,7 +3676,7 @@ class AudioCapture {
3534
3676
  audio: {
3535
3677
  deviceId: selDeviceId,
3536
3678
  channelCount: channelCount,
3537
- //echoCancellation: false
3679
+ echoCancellation: allowEchoCancellation ? undefined : false
3538
3680
  },
3539
3681
  video: false,
3540
3682
  };
@@ -3545,106 +3687,109 @@ class AudioCapture {
3545
3687
  console.debug("Audio capture, AGC: " + this.agcStatus);
3546
3688
  let ump = navigator.mediaDevices.getUserMedia(msc);
3547
3689
  ump.then((s) => {
3548
- this.stream = s;
3549
- let aTracks = s.getAudioTracks();
3550
- for (let i = 0; i < aTracks.length; i++) {
3551
- let aTrack = aTracks[i];
3552
- console.info("Track audio info: id: " + aTrack.id + " kind: " + aTrack.kind + " label: \"" + aTrack.label + "\"");
3553
- let mtrSts = aTrack.getSettings();
3554
- // Typescript lib.dom.ts MediaTrackSettings.channelCount is missing
3555
- // https://github.com/mdn/browser-compat-data/blob/5493d8f937e05b2ddbd41b99f5bdfad4a1f2ed85/api/MediaTrackSettings.json
3556
- //@ts-ignore
3557
- console.info("Track audio settings: Ch cnt: " + mtrSts.channelCount + ", AGC: " + mtrSts.autoGainControl + ", Echo cancell.: " + mtrSts.echoCancellation);
3558
- if (mtrSts.autoGainControl) {
3559
- this.agcStatus = mtrSts.autoGainControl;
3560
- }
3561
- }
3562
- let vTracks = s.getVideoTracks();
3563
- for (let i = 0; i < vTracks.length; i++) {
3564
- let vTrack = vTracks[i];
3565
- console.info("Track video info: id: " + vTrack.id + " kind: " + vTrack.kind + " label: " + vTrack.label);
3566
- }
3567
- this.mediaStream = this.context.createMediaStreamSource(s);
3568
- // stream channel count ( is always 2 !)
3569
- let streamChannelCount = this.mediaStream.channelCount;
3570
- console.info("Stream channel count: " + streamChannelCount);
3571
- // is not set!!
3572
- //this.currentSampleRate = this.mediaStream.sampleRate;
3573
- this.currentSampleRate = this.context.sampleRate;
3574
- console.info("Source audio node: channels: " + streamChannelCount + " samplerate: " + this.currentSampleRate);
3575
- if (this.audioOutStream) {
3576
- this.audioOutStream.setFormat(this.channelCount, this.currentSampleRate);
3577
- }
3578
- // W3C -> new name is createScriptProcessor
3579
- //
3580
- // Again deprecated, but AudioWorker not yet implemented in stable releases (June 2016)
3581
- // AudioWorker is now AudioWorkletProcessor ... (May 2017)
3582
- // Update 12-2020:
3583
- // The ScriptProcessorNode Interface - DEPRECATED
3584
- // Update 06-2021
3585
- // AudioWorkletProcessor is here to stay. Web Audio API has now Recommendation status !
3586
- if (this.context.audioWorklet) {
3587
- //const workletFileName = ('file-loader!./interceptor_worklet.js');
3588
- //const workletFileName = 'http://localhost:4200/assets/interceptor_worklet.js';
3589
- //console.log(awpStr);
3590
- if (AudioCapture.captureInterceptorModuleRegistered) {
3591
- // Required capture interceptor module already registered
3592
- this.addCaptureInterceptor();
3593
- }
3594
- else {
3595
- // Register capture interceptor module
3596
- let audioWorkletModuleBlob = new Blob([awpStr], { type: 'text/javascript' });
3597
- let audioWorkletModuleBlobUrl = window.URL.createObjectURL(audioWorkletModuleBlob);
3598
- this.context.audioWorklet.addModule(audioWorkletModuleBlobUrl).then(() => {
3599
- AudioCapture.captureInterceptorModuleRegistered = true;
3690
+ if (this.context) {
3691
+ this.stream = s;
3692
+ let aTracks = s.getAudioTracks();
3693
+ for (let i = 0; i < aTracks.length; i++) {
3694
+ let aTrack = aTracks[i];
3695
+ console.info("Track audio info: id: " + aTrack.id + " kind: " + aTrack.kind + " label: \"" + aTrack.label + "\"");
3696
+ let mtrSts = aTrack.getSettings();
3697
+ // Typescript lib.dom.ts MediaTrackSettings.channelCount is missing
3698
+ // https://github.com/mdn/browser-compat-data/blob/5493d8f937e05b2ddbd41b99f5bdfad4a1f2ed85/api/MediaTrackSettings.json
3699
+ //@ts-ignore
3700
+ console.info("Track audio settings: Ch cnt: " + mtrSts.channelCount + ", AGC: " + mtrSts.autoGainControl + ", Echo cancell.: " + mtrSts.echoCancellation);
3701
+ if (mtrSts.autoGainControl) {
3702
+ this.agcStatus = mtrSts.autoGainControl;
3703
+ }
3704
+ console.debug("Echo cancellation: " + mtrSts.echoCancellation);
3705
+ }
3706
+ let vTracks = s.getVideoTracks();
3707
+ for (let i = 0; i < vTracks.length; i++) {
3708
+ let vTrack = vTracks[i];
3709
+ console.info("Track video info: id: " + vTrack.id + " kind: " + vTrack.kind + " label: " + vTrack.label);
3710
+ }
3711
+ this.mediaStream = this.context.createMediaStreamSource(s);
3712
+ // stream channel count ( is always 2 !)
3713
+ let streamChannelCount = this.mediaStream.channelCount;
3714
+ console.info("Stream channel count: " + streamChannelCount);
3715
+ // is not set!!
3716
+ //this.currentSampleRate = this.mediaStream.sampleRate;
3717
+ this.currentSampleRate = this.context.sampleRate;
3718
+ console.info("Source audio node: channels: " + streamChannelCount + " samplerate: " + this.currentSampleRate);
3719
+ if (this.audioOutStream) {
3720
+ this.audioOutStream.setFormat(this.channelCount, this.currentSampleRate);
3721
+ }
3722
+ // W3C -> new name is createScriptProcessor
3723
+ //
3724
+ // Again deprecated, but AudioWorker not yet implemented in stable releases (June 2016)
3725
+ // AudioWorker is now AudioWorkletProcessor ... (May 2017)
3726
+ // Update 12-2020:
3727
+ // The ScriptProcessorNode Interface - DEPRECATED
3728
+ // Update 06-2021
3729
+ // AudioWorkletProcessor is here to stay. Web Audio API has now Recommendation status !
3730
+ if (this.context.audioWorklet) {
3731
+ //const workletFileName = ('file-loader!./interceptor_worklet.js');
3732
+ //const workletFileName = 'http://localhost:4200/assets/interceptor_worklet.js';
3733
+ //console.log(awpStr);
3734
+ if (AudioCapture.captureInterceptorModuleRegistered) {
3735
+ // Required capture interceptor module already registered
3600
3736
  this.addCaptureInterceptor();
3601
- }).catch((error) => {
3602
- console.log('Could not add module ' + error);
3603
- });
3737
+ }
3738
+ else {
3739
+ // Register capture interceptor module
3740
+ let audioWorkletModuleBlob = new Blob([awpStr], { type: 'text/javascript' });
3741
+ let audioWorkletModuleBlobUrl = window.URL.createObjectURL(audioWorkletModuleBlob);
3742
+ this.context.audioWorklet.addModule(audioWorkletModuleBlobUrl).then(() => {
3743
+ AudioCapture.captureInterceptorModuleRegistered = true;
3744
+ this.addCaptureInterceptor();
3745
+ }).catch((error) => {
3746
+ console.log('Could not add module ' + error);
3747
+ });
3748
+ }
3604
3749
  }
3605
- }
3606
- else if (this.context.createScriptProcessor) {
3607
- // The ScriptProcessorNode Interface - DEPRECATED Only as fallback
3608
- // TODO should we use streamChannelCount or channelCount here ?
3609
- let scriptProcessorNode = this.context.createScriptProcessor(AudioCapture.BUFFER_SIZE, streamChannelCount, streamChannelCount);
3610
- this.bufferingNode = scriptProcessorNode;
3611
- let c = 0;
3612
- if (scriptProcessorNode.onaudioprocess) {
3613
- scriptProcessorNode.onaudioprocess = (e) => {
3614
- if (this.capturing) {
3615
- let inBuffer = e.inputBuffer;
3616
- // only process requested count of channels
3617
- let currentBuffers = new Array(channelCount);
3618
- for (let ch = 0; ch < channelCount; ch++) {
3619
- let chSamples = inBuffer.getChannelData(ch);
3620
- let chSamplesCopy = chSamples.slice(0);
3621
- currentBuffers[ch] = chSamplesCopy.slice(0);
3622
- if (this.data) {
3623
- this.data[ch].push(chSamplesCopy);
3750
+ else if (this.context.createScriptProcessor) {
3751
+ // The ScriptProcessorNode Interface - DEPRECATED Only as fallback
3752
+ // TODO should we use streamChannelCount or channelCount here ?
3753
+ let scriptProcessorNode = this.context.createScriptProcessor(AudioCapture.BUFFER_SIZE, streamChannelCount, streamChannelCount);
3754
+ this.bufferingNode = scriptProcessorNode;
3755
+ let c = 0;
3756
+ if (scriptProcessorNode.onaudioprocess) {
3757
+ scriptProcessorNode.onaudioprocess = (e) => {
3758
+ if (this.capturing) {
3759
+ let inBuffer = e.inputBuffer;
3760
+ // only process requested count of channels
3761
+ let currentBuffers = new Array(channelCount);
3762
+ for (let ch = 0; ch < channelCount; ch++) {
3763
+ let chSamples = inBuffer.getChannelData(ch);
3764
+ let chSamplesCopy = chSamples.slice(0);
3765
+ currentBuffers[ch] = chSamplesCopy.slice(0);
3766
+ if (this.data) {
3767
+ this.data[ch].push(chSamplesCopy);
3768
+ }
3769
+ if (DEBUG_TRACE_LEVEL > 8) {
3770
+ console.debug("Process " + chSamplesCopy.length + " samples.");
3771
+ }
3772
+ this.framesRecorded += chSamplesCopy.length;
3624
3773
  }
3625
- if (DEBUG_TRACE_LEVEL > 8) {
3626
- console.debug("Process " + chSamplesCopy.length + " samples.");
3774
+ c++;
3775
+ if (this.audioOutStream) {
3776
+ this.audioOutStream.write(currentBuffers);
3627
3777
  }
3628
- this.framesRecorded += chSamplesCopy.length;
3629
- }
3630
- c++;
3631
- if (this.audioOutStream) {
3632
- this.audioOutStream.write(currentBuffers);
3633
3778
  }
3779
+ };
3780
+ this._opened = true;
3781
+ if (this.listener) {
3782
+ this.listener.opened();
3634
3783
  }
3635
- };
3636
- this._opened = true;
3637
- if (this.listener) {
3638
- this.listener.opened();
3784
+ }
3785
+ else {
3786
+ this.listener.error('Browser does not support audio processing (ScriptProcessor.onaudioprocess method not found)!');
3639
3787
  }
3640
3788
  }
3641
3789
  else {
3642
- this.listener.error('Browser does not support audio processing (ScriptProcessor.onaudioprocess method not found)!');
3790
+ this.listener.error('Browser does not support audio processing (neither AudioWorkletProcessor nor ScriptProcessor)!');
3643
3791
  }
3644
3792
  }
3645
- else {
3646
- this.listener.error('Browser does not support audio processing (neither AudioWorkletProcessor nor ScriptProcessor)!');
3647
- }
3648
3793
  }, (e) => {
3649
3794
  console.error(e + " Error name: " + e.name);
3650
3795
  if (this.listener) {
@@ -3665,36 +3810,42 @@ class AudioCapture {
3665
3810
  });
3666
3811
  }
3667
3812
  _start() {
3668
- this.initData();
3669
- if (this.audioOutStream) {
3670
- this.audioOutStream.nextStream();
3671
- }
3672
- this.capturing = true;
3673
- if (this.bufferingNode) {
3674
- this.mediaStream.connect(this.bufferingNode);
3675
- this.bufferingNode.connect(this.context.destination);
3676
- }
3677
- if (this.listener) {
3678
- this.listener.started();
3813
+ if (this.context) {
3814
+ this.initData();
3815
+ if (this.audioOutStream) {
3816
+ this.audioOutStream.nextStream();
3817
+ }
3818
+ this.capturing = true;
3819
+ if (this.bufferingNode) {
3820
+ this.mediaStream.connect(this.bufferingNode);
3821
+ this.bufferingNode.connect(this.context.destination);
3822
+ }
3823
+ if (this.listener) {
3824
+ this.listener.started();
3825
+ }
3679
3826
  }
3680
3827
  }
3681
3828
  start() {
3682
- const aSt = this.context.state;
3683
- if (aSt === 'running') {
3684
- this._start();
3685
- }
3686
- else {
3687
- console.debug("Capture start: audio context not running, state: " + aSt + ", resuming...");
3688
- this.context.resume().then(() => {
3689
- console.debug("Capture start: audio context resumed, starting...");
3829
+ if (this.context) {
3830
+ const aSt = this.context.state;
3831
+ if (aSt === 'running') {
3690
3832
  this._start();
3691
- });
3833
+ }
3834
+ else {
3835
+ console.debug("Capture start: audio context not running, state: " + aSt + ", resuming...");
3836
+ this.context.resume().then(() => {
3837
+ console.debug("Capture start: audio context resumed, starting...");
3838
+ this._start();
3839
+ });
3840
+ }
3692
3841
  }
3693
3842
  }
3694
3843
  stop() {
3695
3844
  if (this.disconnectStreams && this.bufferingNode) {
3696
3845
  this.mediaStream.disconnect(this.bufferingNode);
3697
- this.bufferingNode.disconnect(this.context.destination);
3846
+ if (this.context) {
3847
+ this.bufferingNode.disconnect(this.context.destination);
3848
+ }
3698
3849
  }
3699
3850
  try {
3700
3851
  if (this.audioOutStream) {
@@ -3817,7 +3968,7 @@ class AudioCapture {
3817
3968
  }
3818
3969
  audioBuffer() {
3819
3970
  let ab = null;
3820
- if (this.data) {
3971
+ if (this.context && this.data) {
3821
3972
  let frameLen = 0;
3822
3973
  let ch0Data = this.data[0];
3823
3974
  for (let ch0Chk of ch0Data) {
@@ -4519,7 +4670,7 @@ class Uploader {
4519
4670
  si += v.size;
4520
4671
  }
4521
4672
  else if (typeof v === 'string') {
4522
- // encode to UT-f8 to get upload size
4673
+ // encode to UTF-8 to get upload size
4523
4674
  si += this.te.encode().length;
4524
4675
  }
4525
4676
  });
@@ -4557,34 +4708,37 @@ class Uploader {
4557
4708
  // pipe(timeout()) is not the same as xhr.timeout
4558
4709
  let uploadedUpload = null;
4559
4710
  //console.debug("Post upload: "+ul)
4560
- this.http.post(ul.url, ul.data, { withCredentials: this.withCredentials }).pipe(timeout(timeoVal)).subscribe(data => {
4561
- uploadedUpload = ul;
4562
- //console.debug('Next method called for upload: '+uploadedUpload)
4563
- }, (err) => {
4564
- if (err.error instanceof Error) {
4565
- // A client-side or network error occurred. Handle it accordingly.
4566
- console.error('Upload error occurred:', err.error.message);
4567
- }
4568
- else {
4569
- // The backend returned an unsuccessful response code.
4570
- // The response body may contain clues as to what went wrong,
4571
- console.error(`Upload error: Server returned code ${err.status}`);
4572
- }
4573
- this.processError(ul);
4574
- }, () => {
4575
- //console.debug('Upload complete method called')
4576
- if (uploadedUpload) {
4577
- if (this.DEBUG_DELAY > 0) {
4578
- window.setTimeout(() => {
4579
- this.uploadDone(ul);
4580
- }, this.DEBUG_DELAY);
4711
+ this.http.post(ul.url, ul.data, { withCredentials: this.withCredentials }).pipe(timeout(timeoVal)).subscribe({
4712
+ next: (data) => {
4713
+ uploadedUpload = ul;
4714
+ //console.debug('Next method called for upload: '+uploadedUpload)
4715
+ },
4716
+ error: (err) => {
4717
+ if (err.error instanceof Error) {
4718
+ // A client-side or network error occurred. Handle it accordingly.
4719
+ console.error('Upload error occurred:', err.error.message);
4581
4720
  }
4582
4721
  else {
4583
- this.uploadDone(uploadedUpload);
4722
+ // The backend returned an unsuccessful response code.
4723
+ // The response body may contain clues as to what went wrong,
4724
+ console.error(`Upload error: Server returned code ${err.status}`);
4725
+ }
4726
+ this.processError(ul);
4727
+ }, complete: () => {
4728
+ //console.debug('Upload complete method called')
4729
+ if (uploadedUpload) {
4730
+ if (this.DEBUG_DELAY > 0) {
4731
+ window.setTimeout(() => {
4732
+ this.uploadDone(ul);
4733
+ }, this.DEBUG_DELAY);
4734
+ }
4735
+ else {
4736
+ this.uploadDone(uploadedUpload);
4737
+ }
4738
+ }
4739
+ else {
4740
+ console.error('Upload post complete, but upload not set in next method!');
4584
4741
  }
4585
- }
4586
- else {
4587
- console.error('Upload post complete, but upload not set in next method!');
4588
4742
  }
4589
4743
  });
4590
4744
  }
@@ -4599,7 +4753,7 @@ class Uploader {
4599
4753
  // set retry timer
4600
4754
  this.retryTimerId = window.setTimeout(() => {
4601
4755
  this.retryTimerRunning = false;
4602
- //console.debug("Upload retry timer exprired. Continue processing...")
4756
+ //console.debug("Upload retry timer expired. Continue processing...")
4603
4757
  this.process();
4604
4758
  }, this.RETRY_DELAY);
4605
4759
  this.retryTimerRunning = true;
@@ -4693,12 +4847,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
4693
4847
  * Created by klausj on 17.06.2017.
4694
4848
  */
4695
4849
  class ProjectService {
4696
- constructor(http, platformLoaction, config) {
4850
+ constructor(http, platformLocation, config) {
4697
4851
  this.http = http;
4698
- this.platformLoaction = platformLoaction;
4852
+ this.platformLocation = platformLocation;
4699
4853
  this.config = config;
4700
4854
  this.withCredentials = false;
4701
- console.log("Base Href: " + platformLoaction.getBaseHrefFromDOM());
4855
+ console.log("Base Href: " + platformLocation.getBaseHrefFromDOM());
4702
4856
  let apiEndPoint = '';
4703
4857
  if (config && config.apiEndPoint) {
4704
4858
  apiEndPoint = config.apiEndPoint;
@@ -4781,14 +4935,17 @@ class SessionService {
4781
4935
  let wrapObs = new Observable(subscriber => {
4782
4936
  this._uploadCount++;
4783
4937
  let obs = this.http.patch(sesssUrl, body, { withCredentials: this.withCredentials });
4784
- obs.subscribe((value) => {
4785
- subscriber.next(value);
4786
- }, error => {
4787
- this._uploadCount--;
4788
- subscriber.error(error);
4789
- }, () => {
4790
- this._uploadCount--;
4791
- subscriber.complete();
4938
+ obs.subscribe({
4939
+ next: (value) => {
4940
+ subscriber.next(value);
4941
+ },
4942
+ error: error => {
4943
+ this._uploadCount--;
4944
+ subscriber.error(error);
4945
+ }, complete: () => {
4946
+ this._uploadCount--;
4947
+ subscriber.complete();
4948
+ }
4792
4949
  });
4793
4950
  });
4794
4951
  return wrapObs;
@@ -7402,7 +7559,7 @@ AudioClipUIContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", v
7402
7559
  <audio-signal [pointerPosition]="pointer" [selecting]="selecting" [selection]="selection" (pointerPositionEventEmitter)="pointerPositionChanged($event)" (selectingEventEmitter)="selectingChanged($event)" (selectedEventEmitter)="selectionChanged($event)"></audio-signal>
7403
7560
  <audio-sonagram [pointerPosition]="pointer" [selecting]="selecting" [selection]="selection" (pointerPositionEventEmitter)="pointerPositionChanged($event)" (selectingEventEmitter)="selectingChanged($event)" (selectedEventEmitter)="selectionChanged($event)"></audio-sonagram>
7404
7561
  </div>
7405
- `, isInline: true, styles: ["div{margin:0;padding:0;top:0;left:0;width:100%;height:100%;position:relative;box-sizing:border-box;transform:none;overflow:hidden}\n", "canvas{top:0;left:0;width:0;height:0;cursor:ns-resize;position:absolute;zIndex:1;transform:none}\n", "audio-signal{top:0;left:0;position:absolute;zIndex:1;transform:none}\n", "audio-sonagram{top:0;left:0;position:absolute;zIndex:1;transform:none}\n"], dependencies: [{ kind: "component", type: AudioSignal, selector: "audio-signal" }, { kind: "component", type: Sonagram, selector: "audio-sonagram" }] });
7562
+ `, isInline: true, styles: ["div{margin:0;padding:0;top:0;left:0;width:100%;height:100%;position:relative;box-sizing:border-box;transform:none;overflow:hidden}\n", "canvas{top:0;left:0;width:0;height:0;cursor:ns-resize;position:absolute;z-index:1;transform:none}\n", "audio-signal{top:0;left:0;position:absolute;z-index:1;transform:none}\n", "audio-sonagram{top:0;left:0;position:absolute;z-index:1;transform:none}\n"], dependencies: [{ kind: "component", type: AudioSignal, selector: "audio-signal" }, { kind: "component", type: Sonagram, selector: "audio-sonagram" }] });
7406
7563
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioClipUIContainer, decorators: [{
7407
7564
  type: Component,
7408
7565
  args: [{ selector: 'app-audio', template: `
@@ -7412,7 +7569,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
7412
7569
  <audio-signal [pointerPosition]="pointer" [selecting]="selecting" [selection]="selection" (pointerPositionEventEmitter)="pointerPositionChanged($event)" (selectingEventEmitter)="selectingChanged($event)" (selectedEventEmitter)="selectionChanged($event)"></audio-signal>
7413
7570
  <audio-sonagram [pointerPosition]="pointer" [selecting]="selecting" [selection]="selection" (pointerPositionEventEmitter)="pointerPositionChanged($event)" (selectingEventEmitter)="selectingChanged($event)" (selectedEventEmitter)="selectionChanged($event)"></audio-sonagram>
7414
7571
  </div>
7415
- `, styles: ["div{margin:0;padding:0;top:0;left:0;width:100%;height:100%;position:relative;box-sizing:border-box;transform:none;overflow:hidden}\n", "canvas{top:0;left:0;width:0;height:0;cursor:ns-resize;position:absolute;zIndex:1;transform:none}\n", "audio-signal{top:0;left:0;position:absolute;zIndex:1;transform:none}\n", "audio-sonagram{top:0;left:0;position:absolute;zIndex:1;transform:none}\n"] }]
7572
+ `, styles: ["div{margin:0;padding:0;top:0;left:0;width:100%;height:100%;position:relative;box-sizing:border-box;transform:none;overflow:hidden}\n", "canvas{top:0;left:0;width:0;height:0;cursor:ns-resize;position:absolute;z-index:1;transform:none}\n", "audio-signal{top:0;left:0;position:absolute;z-index:1;transform:none}\n", "audio-sonagram{top:0;left:0;position:absolute;z-index:1;transform:none}\n"] }]
7416
7573
  }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { canvasRef: [{
7417
7574
  type: ViewChild,
7418
7575
  args: ['divider', { static: true }]
@@ -7726,8 +7883,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
7726
7883
  }] } });
7727
7884
 
7728
7885
  class AudioDisplay {
7729
- constructor(route, ref, eRef) {
7730
- this.route = route;
7886
+ constructor(ref, eRef) {
7731
7887
  this.ref = ref;
7732
7888
  this.eRef = eRef;
7733
7889
  this._audioClip = null;
@@ -7790,7 +7946,7 @@ class AudioDisplay {
7790
7946
  this.status = 'ERROR';
7791
7947
  }
7792
7948
  }
7793
- AudioDisplay.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioDisplay, deps: [{ token: i1$2.ActivatedRoute }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
7949
+ AudioDisplay.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioDisplay, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
7794
7950
  AudioDisplay.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: AudioDisplay, selector: "app-audiodisplay", inputs: { playStartAction: "playStartAction", playStopAction: "playStopAction", playSelectionAction: "playSelectionAction", autoPlayOnSelectToggleAction: "autoPlayOnSelectToggleAction", audioData: "audioData", audioClip: "audioClip" }, viewQueries: [{ propertyName: "audioDisplayScrollPane", first: true, predicate: AudioDisplayScrollPane, descendants: true, static: true }], ngImport: i0, template: `
7795
7951
 
7796
7952
  <audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
@@ -7821,7 +7977,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
7821
7977
  [zoomSelectedAction]="zoomSelectedAction"
7822
7978
  [zoomFitToPanelAction]="zoomFitToPanelAction"></audio-display-control>
7823
7979
  `, styles: [":host{display:flex;flex-direction:column;position:absolute;bottom:0;height:100%;width:100%;overflow:hidden;padding:20px;z-index:5;box-sizing:border-box;background-color:#e6e6e6}\n", "legend{margin-left:1em;padding:.2em .8em;font-size:.8em}\n", "fieldset{border:1px darkgray solid}\n"] }]
7824
- }], ctorParameters: function () { return [{ type: i1$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { playStartAction: [{
7980
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { playStartAction: [{
7825
7981
  type: Input
7826
7982
  }], playStopAction: [{
7827
7983
  type: Input
@@ -7852,11 +8008,11 @@ class ResponsiveComponent {
7852
8008
  });
7853
8009
  }
7854
8010
  }
7855
- ResponsiveComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ResponsiveComponent, deps: [{ token: i1$3.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Directive });
8011
+ ResponsiveComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ResponsiveComponent, deps: [{ token: i1$2.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Directive });
7856
8012
  ResponsiveComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: ResponsiveComponent, ngImport: i0 });
7857
8013
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ResponsiveComponent, decorators: [{
7858
8014
  type: Directive
7859
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }]; } });
8015
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }]; } });
7860
8016
 
7861
8017
  class ScrollIntoViewDirective {
7862
8018
  constructor(elRef) {
@@ -8536,7 +8692,7 @@ class Prompting extends ResponsiveComponent {
8536
8692
  this.onPrevItem.emit();
8537
8693
  }
8538
8694
  }
8539
- Prompting.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: Prompting, deps: [{ token: i1$3.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Component });
8695
+ Prompting.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: Prompting, deps: [{ token: i1$2.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Component });
8540
8696
  Prompting.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: Prompting, selector: "app-sprprompting", inputs: { projectName: "projectName", startStopSignalState: "startStopSignalState", promptItem: "promptItem", showPrompt: "showPrompt", items: "items", selectedItemIdx: "selectedItemIdx", transportActions: "transportActions", enableDownload: "enableDownload", audioSignalCollapsed: "audioSignalCollapsed", displayAudioClip: "displayAudioClip", playStartAction: "playStartAction", playSelectionAction: "playSelectionAction", autoPlayOnSelectToggleAction: "autoPlayOnSelectToggleAction", playStopAction: "playStopAction" }, outputs: { onItemSelect: "onItemSelect", onNextItem: "onNextItem", onPrevItem: "onPrevItem" }, viewQueries: [{ propertyName: "simpleTrafficLight", first: true, predicate: SimpleTrafficLight, descendants: true, static: true }, { propertyName: "audioDisplay", first: true, predicate: AudioDisplay, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
8541
8697
 
8542
8698
  <app-simpletrafficlight [status]="startStopSignalState"></app-simpletrafficlight>
@@ -8585,7 +8741,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
8585
8741
 
8586
8742
 
8587
8743
  `, styles: [":host{position:relative;margin:0;padding:0;background:lightgrey;width:100%;flex:1;min-height:0px;display:flex;flex-direction:row;flex-wrap:nowrap}\n", "app-simpletrafficlight{margin:10px;min-height:0px;z-index:3}\n", "app-sprprogress{z-index:3}\n", "div{display:none;position:absolute;z-index:5}\n", "div.active{display:flex;position:absolute;bottom:0;height:90%;width:100%;overflow:hidden;padding:0;z-index:5;box-sizing:border-box;background-color:#0000}\n"] }]
8588
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }]; }, propDecorators: { simpleTrafficLight: [{
8744
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }]; }, propDecorators: { simpleTrafficLight: [{
8589
8745
  type: ViewChild,
8590
8746
  args: [SimpleTrafficLight, { static: true }]
8591
8747
  }], audioDisplay: [{
@@ -8636,7 +8792,7 @@ class SessionFinishedDialog {
8636
8792
  this.dialogRef.close();
8637
8793
  }
8638
8794
  }
8639
- SessionFinishedDialog.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SessionFinishedDialog, deps: [{ token: i1$4.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
8795
+ SessionFinishedDialog.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SessionFinishedDialog, deps: [{ token: i1$3.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
8640
8796
  SessionFinishedDialog.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: SessionFinishedDialog, selector: "spr-session-finished-dialog", ngImport: i0, template: `<h1 mat-dialog-title><mat-icon [style.color]="'green'">done_all</mat-icon> Session finished</h1>
8641
8797
  <div mat-dialog-content>
8642
8798
 
@@ -8646,7 +8802,7 @@ SessionFinishedDialog.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0",
8646
8802
  <div mat-dialog-actions>
8647
8803
  <button mat-button (click)="closeDialog()">OK</button>
8648
8804
  </div>
8649
- `, isInline: true, dependencies: [{ kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: i1$4.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$4.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1$4.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }] });
8805
+ `, isInline: true, dependencies: [{ kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: i1$3.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$3.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1$3.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }] });
8650
8806
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SessionFinishedDialog, decorators: [{
8651
8807
  type: Component,
8652
8808
  args: [{
@@ -8662,7 +8818,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
8662
8818
  </div>
8663
8819
  `
8664
8820
  }]
8665
- }], ctorParameters: function () { return [{ type: i1$4.MatDialogRef }, { type: undefined, decorators: [{
8821
+ }], ctorParameters: function () { return [{ type: i1$3.MatDialogRef }, { type: undefined, decorators: [{
8666
8822
  type: Inject,
8667
8823
  args: [MAT_DIALOG_DATA]
8668
8824
  }] }]; } });
@@ -8676,7 +8832,7 @@ class MessageDialog {
8676
8832
  this.dialogRef.close();
8677
8833
  }
8678
8834
  }
8679
- MessageDialog.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: MessageDialog, deps: [{ token: i1$4.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
8835
+ MessageDialog.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: MessageDialog, deps: [{ token: i1$3.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
8680
8836
  MessageDialog.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: MessageDialog, selector: "msg-dialog", ngImport: i0, template: `<h1 mat-dialog-title><mat-icon *ngIf="data.type==='error'" [style.color]="'red'">error</mat-icon>
8681
8837
  <mat-icon *ngIf="data.type==='warning'" [style.color]="'yellow'">warning</mat-icon>{{data.title}}</h1>
8682
8838
  <div mat-dialog-content>
@@ -8688,7 +8844,7 @@ MessageDialog.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version:
8688
8844
  <div mat-dialog-actions>
8689
8845
  <button mat-button (click)="closeDialog()">OK</button>
8690
8846
  </div>
8691
- `, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: i1$4.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$4.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1$4.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }] });
8847
+ `, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: i1$3.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$3.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1$3.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }] });
8692
8848
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: MessageDialog, decorators: [{
8693
8849
  type: Component,
8694
8850
  args: [{
@@ -8706,7 +8862,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
8706
8862
  </div>
8707
8863
  `
8708
8864
  }]
8709
- }], ctorParameters: function () { return [{ type: i1$4.MatDialogRef }, { type: undefined, decorators: [{
8865
+ }], ctorParameters: function () { return [{ type: i1$3.MatDialogRef }, { type: undefined, decorators: [{
8710
8866
  type: Inject,
8711
8867
  args: [MAT_DIALOG_DATA]
8712
8868
  }] }]; } });
@@ -8996,7 +9152,7 @@ let BasicRecordingService = class BasicRecordingService {
8996
9152
  withCredentials: this.withCredentials
8997
9153
  });
8998
9154
  }
8999
- chunkAudioRequest(aCtx, baseAudioUrl, startFrame = 0, frameLength) {
9155
+ chunkAudioRequest(baseAudioUrl, startFrame = 0, frameLength) {
9000
9156
  let ausps = new URLSearchParams();
9001
9157
  ausps.set('startFrame', startFrame.toString());
9002
9158
  ausps.set('frameLength', frameLength.toString());
@@ -9007,67 +9163,69 @@ let BasicRecordingService = class BasicRecordingService {
9007
9163
  ausps.set('requestUUID', UUID.generate());
9008
9164
  }
9009
9165
  let obs = new Observable(observer => {
9010
- this.audioRequestByURL(baseAudioUrl, ausps).subscribe(resp => {
9011
- // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9012
- if (resp.body) {
9013
- //console.debug("chunkAudioRequest: observer.closed: "+observer.closed);
9014
- //console.debug("Audio file bytes: "+resp.body.byteLength);
9015
- // Check original audio format
9016
- let wr = new WavReader(resp.body);
9017
- const pcmFmt = wr.readFormat();
9018
- const orgFl = wr.frameLength();
9019
- // if(pcmFmt){
9020
- // console.debug("Original WAVE format of download chunk: "+pcmFmt);
9021
- // }else{
9022
- // console.error("Could not read WAVE format of original download chunk!");
9023
- // }
9024
- // if(orgFl){
9025
- // console.debug("Original frame length of download chunk: "+orgFl);
9026
- // }else{
9027
- // console.error("Could not read WAVE format of original download chunk!");
9028
- // }
9029
- if (pcmFmt && orgFl) {
9030
- aCtx.decodeAudioData(resp.body, ab => {
9031
- //console.debug("Decoded audio chunk frames: "+ab.length);
9032
- let chDl = new ChunkDownload(pcmFmt, orgFl, ab);
9033
- observer.next(chDl);
9034
- observer.complete();
9035
- }, error => {
9036
- //if(error instanceof HttpErrorResponse) {
9037
- // if (error.status == 404) {
9038
- // // Interpret not as an error, the file ist not recorded yet
9039
- // observer.next(null);
9040
- // observer.complete()
9041
- // } else {
9042
- // // all other states are errors
9043
- console.error("Recordings service chunkAudioRequest error decoding audio data: " + error.name + ": " + error.message);
9044
- observer.error(error);
9045
- // }
9046
- // }
9047
- });
9166
+ this.audioRequestByURL(baseAudioUrl, ausps).subscribe({
9167
+ next: resp => {
9168
+ // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9169
+ if (resp.body) {
9170
+ //console.debug("chunkAudioRequest: observer.closed: "+observer.closed);
9171
+ //console.debug("Audio file bytes: "+resp.body.byteLength);
9172
+ // Check original audio format
9173
+ let wr = new WavReader(resp.body);
9174
+ const pcmFmt = wr.readFormat();
9175
+ const orgFl = wr.frameLength();
9176
+ // if(pcmFmt){
9177
+ // console.debug("Original WAVE format of download chunk: "+pcmFmt);
9178
+ // }else{
9179
+ // console.error("Could not read WAVE format of original download chunk!");
9180
+ // }
9181
+ // if(orgFl){
9182
+ // console.debug("Original frame length of download chunk: "+orgFl);
9183
+ // }else{
9184
+ // console.error("Could not read WAVE format of original download chunk!");
9185
+ // }
9186
+ if (pcmFmt && orgFl) {
9187
+ AudioContextProvider.decodeAudioData(resp.body).then((ab) => {
9188
+ //console.debug("Decoded audio chunk frames: "+ab.length);
9189
+ let chDl = new ChunkDownload(pcmFmt, orgFl, ab);
9190
+ observer.next(chDl);
9191
+ observer.complete();
9192
+ }).catch(error => {
9193
+ //if(error instanceof HttpErrorResponse) {
9194
+ // if (error.status == 404) {
9195
+ // // Interpret not as an error, the file ist not recorded yet
9196
+ // observer.next(null);
9197
+ // observer.complete()
9198
+ // } else {
9199
+ // // all other states are errors
9200
+ console.error("Recordings service chunkAudioRequest error decoding audio data: " + error.name + ": " + error.message);
9201
+ observer.error(error);
9202
+ // }
9203
+ // }
9204
+ });
9205
+ }
9206
+ else {
9207
+ const errMsg = 'Could not parse audio header for format and/or frame length of download.';
9208
+ console.error(errMsg);
9209
+ observer.error(errMsg);
9210
+ }
9048
9211
  }
9049
9212
  else {
9050
- const errMsg = 'Could not parse audio header for format and/or frame length of download.';
9213
+ const errMsg = 'Fetching audio file: response has no body';
9051
9214
  console.error(errMsg);
9052
9215
  observer.error(errMsg);
9053
9216
  }
9217
+ }, error: (error) => {
9218
+ // all other states are errors
9219
+ //const errMsg='Fetching audio file HTTP error: '+error;
9220
+ //console.error(errMsg);
9221
+ observer.error(error);
9222
+ //observer.complete();
9054
9223
  }
9055
- else {
9056
- const errMsg = 'Fetching audio file: response has no body';
9057
- console.error(errMsg);
9058
- observer.error(errMsg);
9059
- }
9060
- }, (error) => {
9061
- // all other states are errors
9062
- //const errMsg='Fetching audio file HTTP error: '+error;
9063
- //console.error(errMsg);
9064
- observer.error(error);
9065
- //observer.complete();
9066
9224
  });
9067
9225
  });
9068
9226
  return obs;
9069
9227
  }
9070
- chunkAudioRequestToNetAudioBuffer(aCtx, baseAudioUrl, startFrame = 0, orgSampleRate, seconds, frames) {
9228
+ chunkAudioRequestToNetAudioBuffer(baseAudioUrl, startFrame = 0, orgSampleRate, seconds, frames) {
9071
9229
  //let audioUrl=baseAudioUrl+'?startFrame='+startFrame+'&frameLength='+frameLength;
9072
9230
  //let audioUrl=new URL(baseAudioUrl);
9073
9231
  // if(orgSampleRate!=null && frameLength%orgSampleRate>0){
@@ -9091,7 +9249,7 @@ let BasicRecordingService = class BasicRecordingService {
9091
9249
  if (resp.body) {
9092
9250
  //console.debug("chunkAudioRequestTonetAb: subscriber.closed: "+subscriber.closed);
9093
9251
  //console.debug("chunkAudioRequestTonetAb: Audio file bytes: "+resp.body.byteLength);
9094
- aCtx.decodeAudioData(resp.body, ab => {
9252
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9095
9253
  //console.debug("chunkAudioRequestTonetAb: Decoded audio chunk frames for netAb: "+ab.length);
9096
9254
  //console.debug("chunkAudioRequestTonetAb: Create netAb ab from chunk ab...");
9097
9255
  if (frames === null) {
@@ -9105,7 +9263,7 @@ let BasicRecordingService = class BasicRecordingService {
9105
9263
  //console.debug("Platform sr: "+ab.sampleRate+", file sr: "+orgSampleRate+", decoded/org frame length: "+fl+"/"+frames+", ab.length: "+ab.length);
9106
9264
  }
9107
9265
  }
9108
- let nab = NetAudioBuffer.fromChunkAudioBuffer(aCtx, this, baseAudioUrl, ab, fl, frameLength);
9266
+ let nab = NetAudioBuffer.fromChunkAudioBuffer(this, baseAudioUrl, ab, fl, frameLength);
9109
9267
  //let rp=new ReadyProvider();
9110
9268
  //nab.readyProvider=rp;
9111
9269
  //rp.ready();
@@ -9117,7 +9275,7 @@ let BasicRecordingService = class BasicRecordingService {
9117
9275
  subscriber.next(nab);
9118
9276
  subscriber.complete();
9119
9277
  }
9120
- }, error => {
9278
+ }).catch(error => {
9121
9279
  console.error('chunkAudioRequestToNetAb: error: ' + error);
9122
9280
  //if(error instanceof HttpErrorResponse) {
9123
9281
  subscriber.error(error);
@@ -9225,7 +9383,7 @@ class RecordingService extends BasicRecordingService {
9225
9383
  withCredentials: this.withCredentials
9226
9384
  });
9227
9385
  }
9228
- chunkAudioRequestToIndDb(aCtx, persistentAudioStorageTarget, inddbAudioBuffer, baseAudioUrl, startFrame = 0, orgSampleRate, seconds) {
9386
+ chunkAudioRequestToIndDb(persistentAudioStorageTarget, inddbAudioBuffer, baseAudioUrl, startFrame = 0, orgSampleRate, seconds) {
9229
9387
  //let audioUrl=baseAudioUrl+'?startFrame='+startFrame+'&frameLength='+frameLength;
9230
9388
  //let audioUrl=new URL(baseAudioUrl);
9231
9389
  let frameLength = orgSampleRate * Math.round(seconds); // Important: multiple of original sample rate to prevent numeric rounding errors on resampling. 10 seconds is a good value for ind db storage.
@@ -9244,7 +9402,7 @@ class RecordingService extends BasicRecordingService {
9244
9402
  if (resp.body) {
9245
9403
  //console.debug("chunkAudioRequestToIndDb: subscriber.closed: "+subscriber.closed);
9246
9404
  //console.debug("chunkAudioRequestToIndDb: Audio file bytes: "+resp.body.byteLength);
9247
- aCtx.decodeAudioData(resp.body, ab => {
9405
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9248
9406
  //console.debug("chunkAudioRequestToIndDb: Decoded audio chunk frames for inddb: "+ab.length);
9249
9407
  if (!inddbAudioBuffer) {
9250
9408
  //console.debug("chunkAudioRequestToIndDb: Create inddb ab from chunk ab...");
@@ -9288,7 +9446,7 @@ class RecordingService extends BasicRecordingService {
9288
9446
  }
9289
9447
  });
9290
9448
  }
9291
- }, error => {
9449
+ }).catch(error => {
9292
9450
  console.error('chunkAudioRequestToIndDb: error: ' + error);
9293
9451
  //if(error instanceof HttpErrorResponse) {
9294
9452
  subscriber.error(error);
@@ -9296,8 +9454,9 @@ class RecordingService extends BasicRecordingService {
9296
9454
  });
9297
9455
  }
9298
9456
  else {
9299
- console.error('chunkAudioRequestToIndDb: Fetching audio file: response has no body');
9300
- subscriber.error('chunkAudioRequestToIndDb: Fetching audio file: response has no body');
9457
+ const errMsg = 'chunkAudioRequestToIndDb: Fetching audio file: response has no body';
9458
+ console.error(errMsg);
9459
+ subscriber.error(new Error(errMsg));
9301
9460
  }
9302
9461
  },
9303
9462
  error: (error) => {
@@ -9309,13 +9468,13 @@ class RecordingService extends BasicRecordingService {
9309
9468
  });
9310
9469
  return obs;
9311
9470
  }
9312
- chunkedAudioRequestToArrayBuffer(aCtx, baseAudioUrl, orgSampleRate, seconds) {
9471
+ chunkedAudioRequestToArrayBuffer(baseAudioUrl, orgSampleRate, seconds) {
9313
9472
  let obs = new Observable(subscriber => {
9314
9473
  let arrayAudioBuffer = null;
9315
9474
  let startFrame = 0;
9316
9475
  let frameLength = orgSampleRate * Math.round(seconds); // Important: multiple of original sample rate to prevent numeric rounding errors on resampling.
9317
9476
  //console.debug("Chunk audio request startFrame 0");
9318
- let subscr = this.chunkAudioRequest(aCtx, baseAudioUrl, startFrame, frameLength).pipe(expand(value => {
9477
+ let subscr = this.chunkAudioRequest(baseAudioUrl, startFrame, frameLength).pipe(expand(value => {
9319
9478
  if (subscriber.closed) {
9320
9479
  subscr.unsubscribe();
9321
9480
  }
@@ -9334,7 +9493,7 @@ class RecordingService extends BasicRecordingService {
9334
9493
  startFrame += frameLength;
9335
9494
  //console.debug("Next start frame: "+startFrame);
9336
9495
  //console.debug("chunkedAudioRequest: expand() subscriber.closed: "+subscriber.closed);
9337
- return this.chunkAudioRequest(aCtx, baseAudioUrl, startFrame, frameLength);
9496
+ return this.chunkAudioRequest(baseAudioUrl, startFrame, frameLength);
9338
9497
  }
9339
9498
  }
9340
9499
  else {
@@ -9404,14 +9563,14 @@ class RecordingService extends BasicRecordingService {
9404
9563
  });
9405
9564
  return obs;
9406
9565
  }
9407
- chunkedInddbAudioRequest(aCtx, persistentAudioStorageTarget, baseAudioUrl, orgSampleRate, seconds) {
9566
+ chunkedInddbAudioRequest(persistentAudioStorageTarget, baseAudioUrl, orgSampleRate, seconds) {
9408
9567
  let obs = new Observable(subscriber => {
9409
9568
  let inddbAudioBuffer = null;
9410
9569
  let startFrame = 0;
9411
9570
  //let frameLength = DEFAULT_CHUNKED_DOWNLOAD_FRAMELENGTH;
9412
9571
  let frameLength = orgSampleRate * Math.round(seconds);
9413
9572
  //console.debug("chunkedInddbAudioRequest: Chunk audio request for inddb. startFrame: "+startFrame);
9414
- let subscr = this.chunkAudioRequestToIndDb(aCtx, persistentAudioStorageTarget, null, baseAudioUrl, startFrame, orgSampleRate, seconds).pipe(expand(iab => {
9573
+ let subscr = this.chunkAudioRequestToIndDb(persistentAudioStorageTarget, null, baseAudioUrl, startFrame, orgSampleRate, seconds).pipe(expand(iab => {
9415
9574
  // console.debug("chunkedInddbAudioRequest (pipe/expand): Got inddb ab: "+iab);
9416
9575
  if (subscriber.closed) {
9417
9576
  subscr.unsubscribe();
@@ -9432,7 +9591,7 @@ class RecordingService extends BasicRecordingService {
9432
9591
  startFrame += frameLength;
9433
9592
  //console.debug("Next start frame: "+startFrame);
9434
9593
  //console.debug("chunkedInddbAudioRequest: expand() subscriber.closed: "+subscriber.closed);
9435
- return this.chunkAudioRequestToIndDb(aCtx, persistentAudioStorageTarget, inddbAudioBuffer, baseAudioUrl, startFrame, orgSampleRate, seconds);
9594
+ return this.chunkAudioRequestToIndDb(persistentAudioStorageTarget, inddbAudioBuffer, baseAudioUrl, startFrame, orgSampleRate, seconds);
9436
9595
  }
9437
9596
  // } else {
9438
9597
  // return EMPTY;
@@ -9624,7 +9783,7 @@ class RecordingService extends BasicRecordingService {
9624
9783
  // //let recUrl=new URL(recUrlStr);
9625
9784
  // return this.chunkedInddbAudioRequest(aCtx,recUrlStr);
9626
9785
  // }
9627
- fetchRecordingFileAudioBuffer(aCtx, projectName, recordingFile) {
9786
+ fetchRecordingFileAudioBuffer(projectName, recordingFile) {
9628
9787
  let wobs = new Observable(observer => {
9629
9788
  let recFileId = recordingFile.recordingFileId;
9630
9789
  if (!recFileId) {
@@ -9632,36 +9791,38 @@ class RecordingService extends BasicRecordingService {
9632
9791
  }
9633
9792
  if (recordingFile.session && recFileId) {
9634
9793
  let obs = this.fetchAudiofile(projectName, recordingFile.session, recFileId);
9635
- obs.subscribe(resp => {
9636
- // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9637
- if (resp.body) {
9638
- aCtx.decodeAudioData(resp.body, ab => {
9639
- observer.next(ab);
9640
- observer.complete();
9641
- }, error => {
9642
- observer.error(error);
9643
- observer.complete();
9644
- });
9645
- }
9646
- else {
9647
- observer.error('Fetching audio file: response has no body');
9648
- }
9649
- }, (err) => {
9650
- if (err instanceof HttpErrorResponse) {
9651
- if (err.status == 404) {
9652
- // Interpret not as an error, the file ist not recorded yet
9653
- observer.next(null);
9654
- observer.complete();
9794
+ obs.subscribe({
9795
+ next: resp => {
9796
+ // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9797
+ if (resp.body) {
9798
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9799
+ observer.next(ab);
9800
+ observer.complete();
9801
+ }).catch(error => {
9802
+ observer.error(error);
9803
+ observer.complete();
9804
+ });
9805
+ }
9806
+ else {
9807
+ observer.error('Fetching audio file: response has no body');
9808
+ }
9809
+ }, error: (err) => {
9810
+ if (err instanceof HttpErrorResponse) {
9811
+ if (err.status == 404) {
9812
+ // Interpret not as an error, the file ist not recorded yet
9813
+ observer.next(null);
9814
+ observer.complete();
9815
+ }
9816
+ else {
9817
+ // all other states are errors
9818
+ observer.error(err);
9819
+ observer.complete();
9820
+ }
9655
9821
  }
9656
9822
  else {
9657
- // all other states are errors
9658
9823
  observer.error(err);
9659
- observer.complete();
9660
9824
  }
9661
9825
  }
9662
- else {
9663
- observer.error(err);
9664
- }
9665
9826
  });
9666
9827
  }
9667
9828
  else {
@@ -9678,49 +9839,50 @@ class RecordingService extends BasicRecordingService {
9678
9839
  }
9679
9840
  if (recordingFile.session && recFileId) {
9680
9841
  let obs = this.fetchAudiofile(projectName, recordingFile.session, recFileId);
9681
- obs.subscribe(resp => {
9682
- //console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
9683
- // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9684
- if (resp.body) {
9685
- aCtx.decodeAudioData(resp.body, ab => {
9686
- let abs = new AudioBufferSource(ab);
9687
- let adh = new AudioDataHolder(abs);
9688
- RecordingFileUtils.setAudioData(recordingFile, adh);
9689
- if (this.debugDelay > 0) {
9690
- window.setTimeout(() => {
9842
+ obs.subscribe({ next: resp => {
9843
+ //console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
9844
+ // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9845
+ if (resp.body) {
9846
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9847
+ let abs = new AudioBufferSource(ab);
9848
+ let adh = new AudioDataHolder(abs);
9849
+ RecordingFileUtils.setAudioData(recordingFile, adh);
9850
+ if (this.debugDelay > 0) {
9851
+ window.setTimeout(() => {
9852
+ observer.next(recordingFile);
9853
+ observer.complete();
9854
+ }, this.debugDelay);
9855
+ }
9856
+ else {
9691
9857
  observer.next(recordingFile);
9692
9858
  observer.complete();
9693
- }, this.debugDelay);
9859
+ }
9860
+ }).catch(error => {
9861
+ observer.error(error);
9862
+ observer.complete();
9863
+ });
9864
+ }
9865
+ else {
9866
+ observer.error('Fetching audio file: response has no body');
9867
+ }
9868
+ },
9869
+ error: (err) => {
9870
+ if (err instanceof HttpErrorResponse) {
9871
+ if (err.status == 404) {
9872
+ // Interpret not as an error, the file ist not recorded yet
9873
+ observer.next(null);
9874
+ observer.complete();
9694
9875
  }
9695
9876
  else {
9696
- observer.next(recordingFile);
9877
+ // all other states are errors
9878
+ observer.error(err);
9697
9879
  observer.complete();
9698
9880
  }
9699
- }, error => {
9700
- observer.error(error);
9701
- observer.complete();
9702
- });
9703
- }
9704
- else {
9705
- observer.error('Fetching audio file: response has no body');
9706
- }
9707
- }, (err) => {
9708
- if (err instanceof HttpErrorResponse) {
9709
- if (err.status == 404) {
9710
- // Interpret not as an error, the file ist not recorded yet
9711
- observer.next(null);
9712
- observer.complete();
9713
9881
  }
9714
9882
  else {
9715
- // all other states are errors
9716
9883
  observer.error(err);
9717
- observer.complete();
9718
9884
  }
9719
- }
9720
- else {
9721
- observer.error(err);
9722
- }
9723
- });
9885
+ } });
9724
9886
  }
9725
9887
  else {
9726
9888
  observer.error();
@@ -9728,7 +9890,7 @@ class RecordingService extends BasicRecordingService {
9728
9890
  });
9729
9891
  return wobs;
9730
9892
  }
9731
- fetchSprRecordingFileAudioBuffer(aCtx, projectName, recordingFile) {
9893
+ fetchSprRecordingFileAudioBuffer(projectName, recordingFile) {
9732
9894
  let wobs = new Observable(observer => {
9733
9895
  if (recordingFile.session) {
9734
9896
  let obs = this.fetchSprAudiofile(projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
@@ -9736,11 +9898,11 @@ class RecordingService extends BasicRecordingService {
9736
9898
  next: resp => {
9737
9899
  // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9738
9900
  if (resp.body) {
9739
- aCtx.decodeAudioData(resp.body, ab => {
9901
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9740
9902
  //RecordingFileUtils.setAudioData(recordingFile,new AudioDataHolder(ab,null));
9741
9903
  observer.next(ab);
9742
9904
  observer.complete();
9743
- }, error => {
9905
+ }).catch(error => {
9744
9906
  observer.error(error);
9745
9907
  observer.complete();
9746
9908
  });
@@ -9768,14 +9930,14 @@ class RecordingService extends BasicRecordingService {
9768
9930
  });
9769
9931
  return wobs;
9770
9932
  }
9771
- fetchSprRecordingFileArrayAudioBuffer(aCtx, projectName, recordingFile) {
9933
+ fetchSprRecordingFileArrayAudioBuffer(projectName, recordingFile) {
9772
9934
  let wobs = new Observable(observer => {
9773
9935
  if (recordingFile.session) {
9774
9936
  let baseUrl = this.sprAudioFileUrl(projectName, recordingFile);
9775
9937
  if (baseUrl) {
9776
9938
  if (recordingFile.samplerate) {
9777
9939
  let lengthInSeconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9778
- let obs = this.chunkedAudioRequestToArrayBuffer(aCtx, baseUrl, recordingFile.samplerate, lengthInSeconds);
9940
+ let obs = this.chunkedAudioRequestToArrayBuffer(baseUrl, recordingFile.samplerate, lengthInSeconds);
9779
9941
  //let obs = this.fetchSprAudiofileArrayBuffer(aCtx,projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
9780
9942
  let subscr = obs.subscribe({
9781
9943
  next: aab => {
@@ -9812,14 +9974,14 @@ class RecordingService extends BasicRecordingService {
9812
9974
  });
9813
9975
  return wobs;
9814
9976
  }
9815
- fetchRecordingFileArrayAudioBuffer(aCtx, projectName, recordingFile) {
9977
+ fetchRecordingFileArrayAudioBuffer(projectName, recordingFile) {
9816
9978
  let wobs = new Observable(observer => {
9817
9979
  if (recordingFile.session) {
9818
9980
  let baseUrl = this.audioFileUrl(projectName, recordingFile);
9819
9981
  if (baseUrl) {
9820
9982
  if (recordingFile.samplerate) {
9821
9983
  let lengthInSeconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9822
- let obs = this.chunkedAudioRequestToArrayBuffer(aCtx, baseUrl, recordingFile.samplerate, lengthInSeconds);
9984
+ let obs = this.chunkedAudioRequestToArrayBuffer(baseUrl, recordingFile.samplerate, lengthInSeconds);
9823
9985
  //let obs = this.fetchSprAudiofileArrayBuffer(aCtx,projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
9824
9986
  let subscr = obs.subscribe({
9825
9987
  next: aab => {
@@ -9856,14 +10018,14 @@ class RecordingService extends BasicRecordingService {
9856
10018
  });
9857
10019
  return wobs;
9858
10020
  }
9859
- fetchSprRecordingFileIndDbAudioBuffer(aCtx, persistentAudioStorageTarget, projectName, recordingFile) {
10021
+ fetchSprRecordingFileIndDbAudioBuffer(persistentAudioStorageTarget, projectName, recordingFile) {
9860
10022
  let wobs = new Observable(observer => {
9861
10023
  if (recordingFile.session) {
9862
10024
  let baseUrl = this.sprAudioFileUrl(projectName, recordingFile);
9863
10025
  if (baseUrl) {
9864
10026
  if (recordingFile.samplerate) {
9865
10027
  let lengthInSeconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9866
- let obs = this.chunkedInddbAudioRequest(aCtx, persistentAudioStorageTarget, baseUrl, recordingFile.samplerate, lengthInSeconds);
10028
+ let obs = this.chunkedInddbAudioRequest(persistentAudioStorageTarget, baseUrl, recordingFile.samplerate, lengthInSeconds);
9867
10029
  let subscr = obs.subscribe({
9868
10030
  next: aab => {
9869
10031
  //console.debug("fetchSprRecordingFileIndDbAudioBuffer: observer.closed: "+observer.closed);
@@ -9899,14 +10061,14 @@ class RecordingService extends BasicRecordingService {
9899
10061
  });
9900
10062
  return wobs;
9901
10063
  }
9902
- fetchRecordingFileIndDbAudioBuffer(aCtx, persistentAudioStorageTarget, projectName, recordingFile) {
10064
+ fetchRecordingFileIndDbAudioBuffer(persistentAudioStorageTarget, projectName, recordingFile) {
9903
10065
  let wobs = new Observable(observer => {
9904
10066
  if (recordingFile.session) {
9905
10067
  let baseUrl = this.audioFileUrl(projectName, recordingFile);
9906
10068
  if (baseUrl) {
9907
10069
  if (recordingFile.samplerate) {
9908
10070
  let lengthInSeconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9909
- let obs = this.chunkedInddbAudioRequest(aCtx, persistentAudioStorageTarget, baseUrl, recordingFile.samplerate, lengthInSeconds);
10071
+ let obs = this.chunkedInddbAudioRequest(persistentAudioStorageTarget, baseUrl, recordingFile.samplerate, lengthInSeconds);
9910
10072
  let subscr = obs.subscribe({
9911
10073
  next: aab => {
9912
10074
  //console.debug("fetchSprRecordingFileIndDbAudioBuffer: observer.closed: "+observer.closed);
@@ -9942,14 +10104,14 @@ class RecordingService extends BasicRecordingService {
9942
10104
  });
9943
10105
  return wobs;
9944
10106
  }
9945
- fetchSprRecordingFileNetAudioBuffer(aCtx, projectName, recordingFile) {
10107
+ fetchSprRecordingFileNetAudioBuffer(projectName, recordingFile) {
9946
10108
  let wobs = new Observable(observer => {
9947
10109
  if (recordingFile.session) {
9948
10110
  let baseUrl = this.sprAudioFileUrl(projectName, recordingFile);
9949
10111
  if (baseUrl) {
9950
10112
  let seconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9951
10113
  if (recordingFile.samplerate) {
9952
- let obs = this.chunkAudioRequestToNetAudioBuffer(aCtx, baseUrl, 0, recordingFile.samplerate, seconds, recordingFile.frames);
10114
+ let obs = this.chunkAudioRequestToNetAudioBuffer(baseUrl, 0, recordingFile.samplerate, seconds, recordingFile.frames);
9953
10115
  let subscr = obs.subscribe({
9954
10116
  next: aab => {
9955
10117
  //console.debug("fetchSprRecordingFileIndDbAudioBuffer: observer.closed: "+observer.closed);
@@ -9990,14 +10152,14 @@ class RecordingService extends BasicRecordingService {
9990
10152
  });
9991
10153
  return wobs;
9992
10154
  }
9993
- fetchRecordingFileNetAudioBuffer(aCtx, projectName, recordingFile) {
10155
+ fetchRecordingFileNetAudioBuffer(projectName, recordingFile) {
9994
10156
  let wobs = new Observable(observer => {
9995
10157
  if (recordingFile.session) {
9996
10158
  let baseUrl = this.audioFileUrl(projectName, recordingFile);
9997
10159
  if (baseUrl) {
9998
10160
  let seconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9999
10161
  if (recordingFile.samplerate) {
10000
- let obs = this.chunkAudioRequestToNetAudioBuffer(aCtx, baseUrl, 0, recordingFile.samplerate, seconds, recordingFile.frames);
10162
+ let obs = this.chunkAudioRequestToNetAudioBuffer(baseUrl, 0, recordingFile.samplerate, seconds, recordingFile.frames);
10001
10163
  let subscr = obs.subscribe({
10002
10164
  next: aab => {
10003
10165
  //console.debug("fetchSprRecordingFileIndDbAudioBuffer: observer.closed: "+observer.closed);
@@ -10042,83 +10204,87 @@ class RecordingService extends BasicRecordingService {
10042
10204
  let wobs = new Observable(observer => {
10043
10205
  if (recordingFile.session) {
10044
10206
  let obs = this.fetchSprAudiofile(projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
10045
- obs.subscribe(resp => {
10046
- //console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
10047
- // Do not use Promise version, which does not work with Safari 13 (13.0.5)
10207
+ obs.subscribe({
10208
+ next: resp => {
10209
+ //console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
10210
+ // Do not use Promise version, which does not work with Safari 13 (13.0.5)
10211
+ if (resp.body) {
10212
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
10213
+ let abs = new AudioBufferSource(ab);
10214
+ RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(abs));
10215
+ if (this.debugDelay > 0) {
10216
+ window.setTimeout(() => {
10217
+ observer.next(recordingFile);
10218
+ observer.complete();
10219
+ }, this.debugDelay);
10220
+ }
10221
+ else {
10222
+ observer.next(recordingFile);
10223
+ observer.complete();
10224
+ }
10225
+ }).catch(error => {
10226
+ observer.error(error);
10227
+ observer.complete();
10228
+ });
10229
+ }
10230
+ else {
10231
+ observer.error('Fetching audio file: response has no body');
10232
+ }
10233
+ },
10234
+ error: (err) => {
10235
+ if (err instanceof HttpErrorResponse && err.status == 404) {
10236
+ // Interpret not as an error, the file ist not recorded yet
10237
+ observer.next(null);
10238
+ observer.complete();
10239
+ }
10240
+ else {
10241
+ // all other states are errors
10242
+ observer.error(err);
10243
+ }
10244
+ }
10245
+ });
10246
+ }
10247
+ else {
10248
+ observer.error();
10249
+ }
10250
+ });
10251
+ return wobs;
10252
+ }
10253
+ fetchRecordingFile(aCtx, projectName, sessId, itemcode, version) {
10254
+ let wobs = new Observable(observer => {
10255
+ let obs = this.fetchSprAudiofile(projectName, sessId, itemcode, version);
10256
+ obs.subscribe({ next: resp => {
10048
10257
  if (resp.body) {
10049
- aCtx.decodeAudioData(resp.body, ab => {
10258
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
10050
10259
  let abs = new AudioBufferSource(ab);
10051
- RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(abs));
10260
+ let adh = new AudioDataHolder(abs);
10261
+ let rf = new SprRecordingFile(sessId, itemcode, version, adh);
10052
10262
  if (this.debugDelay > 0) {
10053
10263
  window.setTimeout(() => {
10054
- observer.next(recordingFile);
10264
+ observer.next(rf);
10055
10265
  observer.complete();
10056
10266
  }, this.debugDelay);
10057
10267
  }
10058
10268
  else {
10059
- observer.next(recordingFile);
10269
+ observer.next(rf);
10060
10270
  observer.complete();
10061
10271
  }
10062
- }, error => {
10063
- observer.error(error);
10064
- observer.complete();
10065
- });
10272
+ }).catch((reason) => { observer.error(reason); });
10066
10273
  }
10067
10274
  else {
10068
- observer.error('Fetching audio file: response has no body');
10275
+ observer.error();
10069
10276
  }
10070
- }, (err) => {
10277
+ },
10278
+ error: (err) => {
10071
10279
  if (err instanceof HttpErrorResponse && err.status == 404) {
10072
10280
  // Interpret not as an error, the file ist not recorded yet
10073
10281
  observer.next(null);
10074
10282
  observer.complete();
10075
10283
  }
10076
10284
  else {
10077
- // all other states are errors
10285
+ // all other errors are real errors
10078
10286
  observer.error(err);
10079
10287
  }
10080
- });
10081
- }
10082
- else {
10083
- observer.error();
10084
- }
10085
- });
10086
- return wobs;
10087
- }
10088
- fetchRecordingFile(aCtx, projectName, sessId, itemcode, version) {
10089
- let wobs = new Observable(observer => {
10090
- let obs = this.fetchSprAudiofile(projectName, sessId, itemcode, version);
10091
- obs.subscribe(resp => {
10092
- // Do not use Promise version, which does not work with Safari 13
10093
- if (resp.body) {
10094
- aCtx.decodeAudioData(resp.body, ab => {
10095
- let abs = new AudioBufferSource(ab);
10096
- let adh = new AudioDataHolder(abs);
10097
- let rf = new SprRecordingFile(sessId, itemcode, version, adh);
10098
- if (this.debugDelay > 0) {
10099
- window.setTimeout(() => {
10100
- observer.next(rf);
10101
- observer.complete();
10102
- }, this.debugDelay);
10103
- }
10104
- else {
10105
- observer.next(rf);
10106
- observer.complete();
10107
- }
10108
- });
10109
- }
10110
- else {
10111
- observer.error();
10112
- }
10113
- }, (err) => {
10114
- if (err instanceof HttpErrorResponse && err.status == 404) {
10115
- // Interpret not as an error, the file ist not recorded yet
10116
- observer.next(null);
10117
- observer.complete();
10118
- }
10119
- else {
10120
- // all other errors are real errors
10121
- observer.error(err);
10122
10288
  }
10123
10289
  });
10124
10290
  });
@@ -10138,23 +10304,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
10138
10304
  args: [SPEECHRECORDER_CONFIG]
10139
10305
  }] }]; } });
10140
10306
 
10141
- class AudioContextProvider {
10142
- static audioContextInstance() {
10143
- if (!this._audioContext) {
10144
- let debugFail = false;
10145
- if (!window.AudioContext || typeof window.AudioContext !== 'function' || debugFail) {
10146
- throw new Error('Browser does not support Web Audio API!');
10147
- this._audioContext = null;
10148
- }
10149
- else {
10150
- this._audioContext = new window.AudioContext();
10151
- }
10152
- }
10153
- return this._audioContext;
10154
- }
10155
- }
10156
- AudioContextProvider._audioContext = null;
10157
-
10158
10307
  class Item {
10159
10308
  constructor(_promptAsString, _training, _recording) {
10160
10309
  this._promptAsString = _promptAsString;
@@ -10577,7 +10726,7 @@ class UploadStatus {
10577
10726
  constructor() {
10578
10727
  this._awaitNewUpload = false;
10579
10728
  this.spinnerMode = 'determinate';
10580
- this._colorStatus = 'primary';
10729
+ this.colorStatus = 'primary';
10581
10730
  this._value = 100;
10582
10731
  this.displayValue = null;
10583
10732
  this.toolTipText = '';
@@ -10616,13 +10765,13 @@ class UploadStatus {
10616
10765
  set status(status) {
10617
10766
  this._status = status;
10618
10767
  if ('accent' === status) {
10619
- this._colorStatus = 'accent';
10768
+ this.colorStatus = 'accent';
10620
10769
  }
10621
10770
  else if ('warn' === status) {
10622
- this._colorStatus = 'warn';
10771
+ this.colorStatus = 'warn';
10623
10772
  }
10624
10773
  else {
10625
- this._colorStatus = 'primary';
10774
+ this.colorStatus = 'primary';
10626
10775
  }
10627
10776
  this._updateSpinner();
10628
10777
  }
@@ -10632,12 +10781,14 @@ class UploadStatus {
10632
10781
  }
10633
10782
  UploadStatus.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UploadStatus, deps: [], target: i0.ɵɵFactoryTarget.Component });
10634
10783
  UploadStatus.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: UploadStatus, selector: "app-uploadstatus", inputs: { value: "value", awaitNewUpload: "awaitNewUpload", status: "status" }, ngImport: i0, template: `
10635
- <mat-progress-spinner [mode]="spinnerMode" [color]="status" [diameter]="30" [strokeWidth]="5" [value]="_value" [matTooltip]="toolTipText"></mat-progress-spinner>
10784
+ <mat-progress-spinner [mode]="spinnerMode" [color]="colorStatus" [diameter]="30" [strokeWidth]="5" [value]="_value"
10785
+ [matTooltip]="toolTipText"></mat-progress-spinner>
10636
10786
  `, isInline: true, styles: [":host{text-align:left}\n", "mat-progress-spinner{display:inline-block}\n"], dependencies: [{ kind: "component", type: i3$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
10637
10787
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UploadStatus, decorators: [{
10638
10788
  type: Component,
10639
10789
  args: [{ selector: 'app-uploadstatus', template: `
10640
- <mat-progress-spinner [mode]="spinnerMode" [color]="status" [diameter]="30" [strokeWidth]="5" [value]="_value" [matTooltip]="toolTipText"></mat-progress-spinner>
10790
+ <mat-progress-spinner [mode]="spinnerMode" [color]="colorStatus" [diameter]="30" [strokeWidth]="5" [value]="_value"
10791
+ [matTooltip]="toolTipText"></mat-progress-spinner>
10641
10792
  `, styles: [":host{text-align:left}\n", "mat-progress-spinner{display:inline-block}\n"] }]
10642
10793
  }], propDecorators: { value: [{
10643
10794
  type: Input
@@ -10746,7 +10897,7 @@ class TransportPanel extends ResponsiveComponent {
10746
10897
  }
10747
10898
  }
10748
10899
  }
10749
- TransportPanel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TransportPanel, deps: [{ token: i1$3.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Component });
10900
+ TransportPanel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: TransportPanel, deps: [{ token: i1$2.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Component });
10750
10901
  TransportPanel.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: TransportPanel, selector: "app-sprtransport", inputs: { readonly: "readonly", actions: "actions", navigationEnabled: "navigationEnabled", pausingEnabled: "pausingEnabled" }, usesInheritance: true, ngImport: i0, template: `
10751
10902
  <button id="bwdBtn" *ngIf="navigationEnabled" (click)="actions.bwdAction.perform()" [disabled]="bwdDisabled()"
10752
10903
  mat-raised-button>
@@ -10791,7 +10942,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
10791
10942
  </button>
10792
10943
 
10793
10944
  `, styles: [":host{flex:20;align-self:center;width:100%;text-align:center;align-content:center;margin:0}\n", "div{display:inline;flex:0}\n", "button{touch-action:manipulation}\n"] }]
10794
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }]; }, propDecorators: { readonly: [{
10945
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }]; }, propDecorators: { readonly: [{
10795
10946
  type: Input
10796
10947
  }], actions: [{
10797
10948
  type: Input
@@ -10863,7 +11014,7 @@ class ControlPanel extends ResponsiveComponent {
10863
11014
  return this._ready;
10864
11015
  }
10865
11016
  }
10866
- ControlPanel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ControlPanel, deps: [{ token: i1$3.BreakpointObserver }, { token: i1$4.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
11017
+ ControlPanel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ControlPanel, deps: [{ token: i1$2.BreakpointObserver }, { token: i1$3.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
10867
11018
  ControlPanel.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: ControlPanel, selector: "app-sprcontrolpanel", inputs: { readonly: "readonly", transportActions: "transportActions", processing: "processing", statusMsg: "statusMsg", statusAlertType: "statusAlertType", statusWaiting: "statusWaiting", uploadStatus: "uploadStatus", uploadProgress: "uploadProgress", currentRecording: "currentRecording", enableUploadRecordings: "enableUploadRecordings", navigationEnabled: "navigationEnabled", ready: "ready" }, viewQueries: [{ propertyName: "statusDisplay", first: true, predicate: StatusDisplay, descendants: true, static: true }, { propertyName: "transportPanel", first: true, predicate: TransportPanel, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
10868
11019
  <div *ngIf="!screenXs" style="flex-direction: row" >
10869
11020
  <app-sprstatusdisplay style="flex:0 0 0" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
@@ -10873,9 +11024,9 @@ ControlPanel.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version:
10873
11024
  [status]="uploadStatus" [awaitNewUpload]="processing"></app-uploadstatus>
10874
11025
  <app-readystateindicator [ready]="_ready"></app-readystateindicator>
10875
11026
  </div>
10876
- <div *ngIf="screenXs"style="flex-direction: column" >
11027
+ <div *ngIf="screenXs" style="flex-direction: column" >
10877
11028
  <div style="flex-direction: row" class="flexFill" >
10878
- <app-sprstatusdisplay style="flex:10 0 0;flex-align:left" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
11029
+ <app-sprstatusdisplay style="flex:10 0 0" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
10879
11030
  class="hidden-xs"></app-sprstatusdisplay>
10880
11031
  <app-uploadstatus style="flex:0 0 0" *ngIf="enableUploadRecordings" [value]="uploadProgress"
10881
11032
  [status]="uploadStatus" [awaitNewUpload]="processing"></app-uploadstatus>
@@ -10896,9 +11047,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
10896
11047
  [status]="uploadStatus" [awaitNewUpload]="processing"></app-uploadstatus>
10897
11048
  <app-readystateindicator [ready]="_ready"></app-readystateindicator>
10898
11049
  </div>
10899
- <div *ngIf="screenXs"style="flex-direction: column" >
11050
+ <div *ngIf="screenXs" style="flex-direction: column" >
10900
11051
  <div style="flex-direction: row" class="flexFill" >
10901
- <app-sprstatusdisplay style="flex:10 0 0;flex-align:left" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
11052
+ <app-sprstatusdisplay style="flex:10 0 0" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
10902
11053
  class="hidden-xs"></app-sprstatusdisplay>
10903
11054
  <app-uploadstatus style="flex:0 0 0" *ngIf="enableUploadRecordings" [value]="uploadProgress"
10904
11055
  [status]="uploadStatus" [awaitNewUpload]="processing"></app-uploadstatus>
@@ -10908,7 +11059,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
10908
11059
 
10909
11060
  </div>
10910
11061
  `, styles: ["div{align-content:center;align-items:center;margin:0;padding:20px;min-height:min-content}\n"] }]
10911
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }, { type: i1$4.MatDialog }]; }, propDecorators: { statusDisplay: [{
11062
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }, { type: i1$3.MatDialog }]; }, propDecorators: { statusDisplay: [{
10912
11063
  type: ViewChild,
10913
11064
  args: [StatusDisplay, { static: true }]
10914
11065
  }], transportPanel: [{
@@ -11559,7 +11710,7 @@ class RecordingItemControls extends ResponsiveComponent {
11559
11710
  // this.status = 'ERROR';
11560
11711
  }
11561
11712
  }
11562
- RecordingItemControls.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingItemControls, deps: [{ token: i1$3.BreakpointObserver }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
11713
+ RecordingItemControls.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingItemControls, deps: [{ token: i1$2.BreakpointObserver }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
11563
11714
  RecordingItemControls.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: RecordingItemControls, selector: "spr-recordingitemcontrols", inputs: { audioSignalCollapsed: "audioSignalCollapsed", enableDownload: "enableDownload", peakDbLvl: "peakDbLvl", agc: "agc", disableAudioDetails: "disableAudioDetails", audioLoaded: "audioLoaded", playStartAction: "playStartAction", playStopAction: "playStopAction", displayLevelInfos: "displayLevelInfos" }, outputs: { onShowRecordingDetails: "onShowRecordingDetails", onDownloadRecording: "onDownloadRecording" }, usesInheritance: true, ngImport: i0, template: `
11564
11715
  <button matTooltip="Start playback" (click)="playStartAction?.perform()"
11565
11716
  [disabled]="playStartAction?.disabled"
@@ -11608,7 +11759,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
11608
11759
  [style.color]="(peakDbLvl > warnDbLevel)?'red':'black'">{{peakDbLvl | number:'1.1-1'}} dB </span></td></tr>
11609
11760
  <tr *ngIf="_agc"><td>AGC:</td><td><span matTooltip="Auto gain control">{{agcString}}</span></td></tr></table></div>
11610
11761
  `, styles: [":host{flex:0;width:100%;background:darkgray;padding:4px;box-sizing:border-box;height:100%;display:flex;flex-direction:row;flex-wrap:nowrap}\n", "span{flex:0;font-weight:700;display:inline-block;white-space:nowrap;box-sizing:border-box}\n", "button{touch-action:manipulation}\n"] }]
11611
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { audioSignalCollapsed: [{
11762
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { audioSignalCollapsed: [{
11612
11763
  type: Input
11613
11764
  }], enableDownload: [{
11614
11765
  type: Input
@@ -11689,7 +11840,7 @@ class RecordingItemDisplay extends ResponsiveComponent {
11689
11840
  let peakDBVal = levelInfo.powerLevelDB();
11690
11841
  if (this.peakDbLvl < peakDBVal) {
11691
11842
  this.peakDbLvl = peakDBVal;
11692
- // the event comes from outside of an Angular zone
11843
+ // the event comes from outside an Angular zone
11693
11844
  this.changeDetectorRef.detectChanges();
11694
11845
  }
11695
11846
  this.liveLevel.update(levelInfo);
@@ -11705,7 +11856,7 @@ class RecordingItemDisplay extends ResponsiveComponent {
11705
11856
  this.changeDetectorRef.detectChanges();
11706
11857
  }
11707
11858
  }
11708
- RecordingItemDisplay.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingItemDisplay, deps: [{ token: i1$3.BreakpointObserver }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
11859
+ RecordingItemDisplay.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingItemDisplay, deps: [{ token: i1$2.BreakpointObserver }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
11709
11860
  RecordingItemDisplay.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: RecordingItemDisplay, selector: "spr-recordingitemdisplay", inputs: { streamingMode: "streamingMode", audioSignalCollapsed: "audioSignalCollapsed", enableDownload: "enableDownload", agc: "agc", playStartAction: "playStartAction", playStopAction: "playStopAction", displayAudioBuffer: "displayAudioBuffer", displayLevelInfos: "displayLevelInfos" }, outputs: { onShowRecordingDetails: "onShowRecordingDetails", onDownloadRecording: "onDownloadRecording" }, viewQueries: [{ propertyName: "liveLevel", first: true, predicate: LevelBar, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
11710
11861
  <div [class]="{audioStatusDisplay:!screenXs,audioStatusDisplayXs:screenXs}">
11711
11862
  <audio-levelbar style="flex:1 0 1%" [streamingMode]="streamingMode" [displayLevelInfos]="_displayLevelInfos"></audio-levelbar>
@@ -11720,7 +11871,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
11720
11871
  <spr-recordingitemcontrols style="flex:0 0 0px" [audioLoaded]="displayAudioBuffer!==null" [playStartAction]="playStartAction" [playStopAction]="playStopAction" [peakDbLvl]="peakDbLvl" [agc]="_agc" (onShowRecordingDetails)="onShowRecordingDetails.emit()"></spr-recordingitemcontrols>
11721
11872
  </div>
11722
11873
  `, styles: ["div{width:100%;background:darkgray;padding:4px;box-sizing:border-box;flex-wrap:nowrap}\n", "audio-levelbar{box-sizing:border-box}\n", ".audioStatusDisplay{display:flex;flex-direction:row;height:100px;min-height:100px}\n", ".audioStatusDisplayXs{display:flex;flex-direction:column;height:125px;min-height:125px}\n"] }]
11723
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { liveLevel: [{
11874
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { liveLevel: [{
11724
11875
  type: ViewChild,
11725
11876
  args: [LevelBar, { static: true }]
11726
11877
  }], streamingMode: [{
@@ -12023,6 +12174,7 @@ let BasicRecorder = class BasicRecorder extends ResponsiveComponent {
12023
12174
  this._wakeLock = false;
12024
12175
  this._selectedDeviceId = undefined;
12025
12176
  this._channelCount = 2;
12177
+ this._allowEchoCancellation = false;
12026
12178
  this._session = null;
12027
12179
  this._recordingFile = null;
12028
12180
  this.startedDate = null;
@@ -12064,6 +12216,12 @@ let BasicRecorder = class BasicRecorder extends ResponsiveComponent {
12064
12216
  this.streamLevelMeasure = new StreamLevelMeasure();
12065
12217
  this.selCaptureDeviceId = null;
12066
12218
  }
12219
+ get allowEchoCancellation() {
12220
+ return this._allowEchoCancellation;
12221
+ }
12222
+ set allowEchoCancellation(value) {
12223
+ this._allowEchoCancellation = value;
12224
+ }
12067
12225
  get maxAutoNetMemStoreSamples() {
12068
12226
  return this._maxAutoNetMemStoreSamples;
12069
12227
  }
@@ -12448,7 +12606,7 @@ let BasicRecorder = class BasicRecorder extends ResponsiveComponent {
12448
12606
  else {
12449
12607
  console.log("Open session with default audio device for " + this._channelCount + " channels");
12450
12608
  }
12451
- this.ac.open(this._channelCount, this._selectedDeviceId, this._autoGainControlConfigs);
12609
+ this.ac.open(this._channelCount, this._selectedDeviceId, this._autoGainControlConfigs, this._allowEchoCancellation);
12452
12610
  }
12453
12611
  else {
12454
12612
  this.ac.start();
@@ -12804,6 +12962,7 @@ class SessionManager extends BasicRecorder {
12804
12962
  this.bpo = bpo;
12805
12963
  this.renderer = renderer;
12806
12964
  this.recFileService = recFileService;
12965
+ this.offlineAudioContext = null;
12807
12966
  this.enableUploadRecordings = true;
12808
12967
  this.enableDownloadRecordings = false;
12809
12968
  this.status = 0 /* BLOCKED */;
@@ -12860,37 +13019,58 @@ class SessionManager extends BasicRecorder {
12860
13019
  this.transportActions.nextAction.disabled = true;
12861
13020
  this.transportActions.pauseAction.disabled = true;
12862
13021
  this.playStartAction.disabled = true;
12863
- let context = null;
12864
- try {
12865
- context = AudioContextProvider.audioContextInstance();
12866
- }
12867
- catch (err) {
12868
- this.status = 9 /* ERROR */;
12869
- let errMsg = 'Unknown error';
12870
- if (err instanceof Error) {
12871
- errMsg = err.message;
12872
- }
12873
- this.statusMsg = 'ERROR: ' + errMsg;
12874
- this.statusAlertType = 'error';
12875
- this.dialog.open(MessageDialog, {
12876
- data: {
12877
- type: 'error',
12878
- title: 'Error',
12879
- msg: errMsg,
12880
- advice: 'Please use a supported browser.',
12881
- }
12882
- });
12883
- return;
12884
- }
12885
- if (context) {
12886
- console.info("State of audio context: " + context.state);
13022
+ // let context:AudioContext|null=null;
13023
+ // try {
13024
+ // context = AudioContextProvider.audioContextInstance();
13025
+ // } catch (err) {
13026
+ // this.status = Status.ERROR;
13027
+ // let errMsg = 'Unknown error';
13028
+ // if(err instanceof Error){
13029
+ // errMsg=err.message;
13030
+ // }
13031
+ // this.statusMsg = 'ERROR: ' + errMsg;
13032
+ // this.statusAlertType = 'error';
13033
+ // this.dialog.open(MessageDialog, {
13034
+ // data: {
13035
+ // type: 'error',
13036
+ // title: 'Error',
13037
+ // msg: errMsg,
13038
+ // advice: 'Please use a supported browser.',
13039
+ // }
13040
+ // });
13041
+ // return;
13042
+ // }
13043
+ // if(context) {
13044
+ // console.info("State of audio context: " + context.state)
13045
+ // }else{
13046
+ // console.info("No audio context available!");
13047
+ // }
13048
+ // if (!context || !navigator.mediaDevices) {
13049
+ // this.status = Status.ERROR;
13050
+ // let errMsg = 'Browser does not support Media streams!';
13051
+ // this.statusMsg = 'ERROR: ' + errMsg;
13052
+ // this.statusAlertType = 'error';
13053
+ // this.dialog.open(MessageDialog, {
13054
+ // data: {
13055
+ // type: 'error',
13056
+ // title: 'Error',
13057
+ // msg: errMsg,
13058
+ // advice: 'Please use a supported browser.',
13059
+ // }
13060
+ // });
13061
+ // return;
13062
+ // } else {
13063
+ this.ac = new AudioCapture();
13064
+ if (this.ac) {
13065
+ this.transportActions.startAction.onAction = () => this.startItem();
13066
+ this.ac.listener = this;
13067
+ this.configureStreamCaptureStream();
13068
+ // Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
13069
+ //this.ac.listDevices();
12887
13070
  }
12888
13071
  else {
12889
- console.info("No audio context available!");
12890
- }
12891
- if (!context || !navigator.mediaDevices) {
12892
- this.status = 9 /* ERROR */;
12893
- let errMsg = 'Browser does not support Media streams!';
13072
+ this.transportActions.startAction.disabled = true;
13073
+ let errMsg = 'Browser does not support Media/Audio API!';
12894
13074
  this.statusMsg = 'ERROR: ' + errMsg;
12895
13075
  this.statusAlertType = 'error';
12896
13076
  this.dialog.open(MessageDialog, {
@@ -12903,38 +13083,13 @@ class SessionManager extends BasicRecorder {
12903
13083
  });
12904
13084
  return;
12905
13085
  }
12906
- else {
12907
- this.ac = new AudioCapture(context);
12908
- if (this.ac) {
12909
- this.transportActions.startAction.onAction = () => this.startItem();
12910
- this.ac.listener = this;
12911
- this.configureStreamCaptureStream();
12912
- // Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
12913
- //this.ac.listDevices();
12914
- }
12915
- else {
12916
- this.transportActions.startAction.disabled = true;
12917
- let errMsg = 'Browser does not support Media/Audio API!';
12918
- this.statusMsg = 'ERROR: ' + errMsg;
12919
- this.statusAlertType = 'error';
12920
- this.dialog.open(MessageDialog, {
12921
- data: {
12922
- type: 'error',
12923
- title: 'Error',
12924
- msg: errMsg,
12925
- advice: 'Please use a supported browser.',
12926
- }
12927
- });
12928
- return;
12929
- }
12930
- this.transportActions.stopAction.onAction = () => this.stopItem();
12931
- this.transportActions.nextAction.onAction = () => this.stopItem();
12932
- this.transportActions.pauseAction.onAction = () => this.pauseItem();
12933
- this.transportActions.fwdAction.onAction = () => this.nextItem();
12934
- this.transportActions.fwdNextAction.onAction = () => this.nextUnrecordedItem();
12935
- this.transportActions.bwdAction.onAction = () => this.prevItem();
12936
- this.playStartAction.onAction = () => this.controlAudioPlayer?.start();
12937
- }
13086
+ this.transportActions.stopAction.onAction = () => this.stopItem();
13087
+ this.transportActions.nextAction.onAction = () => this.stopItem();
13088
+ this.transportActions.pauseAction.onAction = () => this.pauseItem();
13089
+ this.transportActions.fwdAction.onAction = () => this.nextItem();
13090
+ this.transportActions.fwdNextAction.onAction = () => this.nextUnrecordedItem();
13091
+ this.transportActions.bwdAction.onAction = () => this.prevItem();
13092
+ this.playStartAction.onAction = () => this.controlAudioPlayer?.start();
12938
13093
  this.startStopSignalState = 4 /* OFF */;
12939
13094
  }
12940
13095
  onKeyPress(ke) {
@@ -13241,7 +13396,7 @@ class SessionManager extends BasicRecorder {
13241
13396
  }
13242
13397
  else {
13243
13398
  //console.debug("Fetch audio and store to indexed db...");
13244
- this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileIndDbAudioBuffer(this._controlAudioPlayer.context, this._persistentAudioStorageTarget, this._session.project, rf).subscribe({
13399
+ this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileIndDbAudioBuffer(this._persistentAudioStorageTarget, this._session.project, rf).subscribe({
13245
13400
  next: (iab) => {
13246
13401
  //console.debug("Sessionmanager: Received inddb audio buffer: "+iab);
13247
13402
  nextIab = iab;
@@ -13283,7 +13438,7 @@ class SessionManager extends BasicRecorder {
13283
13438
  // Fetch chunked audio buffer from network
13284
13439
  let nextNetAb = null;
13285
13440
  //console.debug("Fetch chunked audio from network");
13286
- this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileNetAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
13441
+ this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileNetAudioBuffer(this._session.project, rf).subscribe({
13287
13442
  next: (netAb) => {
13288
13443
  //console.debug("Sessionmanager: Received net audio buffer: "+netAb);
13289
13444
  nextNetAb = netAb;
@@ -13325,7 +13480,7 @@ class SessionManager extends BasicRecorder {
13325
13480
  // Fetch chunked array audio buffer
13326
13481
  let nextAab = null;
13327
13482
  //console.debug("Fetch audio and store to (chunked) array buffer...");
13328
- this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileArrayAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
13483
+ this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileArrayAudioBuffer(this._session.project, rf).subscribe({
13329
13484
  next: (aab) => {
13330
13485
  nextAab = aab;
13331
13486
  },
@@ -13363,7 +13518,7 @@ class SessionManager extends BasicRecorder {
13363
13518
  else {
13364
13519
  // Fetch regular audio buffer
13365
13520
  //console.debug("Fetch audio and store to audio buffer...");
13366
- this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
13521
+ this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileAudioBuffer(this._session.project, rf).subscribe({
13367
13522
  next: (ab) => {
13368
13523
  this.liveLevelDisplayState = State.READY;
13369
13524
  let fabDh = null;
@@ -13750,7 +13905,7 @@ class SessionManager extends BasicRecorder {
13750
13905
  const sr = this.ac.currentSampleRate;
13751
13906
  const chFl = sr * RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
13752
13907
  //console.debug("stopped(): rfID: "+this._recordingFile?.recordingFileId+", net ab url: " + burl+", frames: "+this.ac.framesRecorded+", sample rate: "+sr);
13753
- let netAb = new NetAudioBuffer(this.ac.context, this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
13908
+ let netAb = new NetAudioBuffer(this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
13754
13909
  as = netAb;
13755
13910
  if (this.uploadSet) {
13756
13911
  //let rp=new ReadyProvider();
@@ -13797,7 +13952,7 @@ class SessionManager extends BasicRecorder {
13797
13952
  const sr = this.ac.currentSampleRate;
13798
13953
  const chFl = sr * RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
13799
13954
  //console.debug("stopped(): rfID: "+this._recordingFile?.recordingFileId+", net ab url: " + burl+", frames: "+this.ac.framesRecorded+", sample rate: "+sr);
13800
- const netAb = new NetAudioBuffer(this.ac.context, this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
13955
+ const netAb = new NetAudioBuffer(this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
13801
13956
  as = netAb;
13802
13957
  if (this.uploadSet) {
13803
13958
  this.uploadSet.onDone = (uploadSet) => {
@@ -13835,8 +13990,8 @@ class SessionManager extends BasicRecorder {
13835
13990
  // TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
13836
13991
  // TODO duplicate conversion for manual download
13837
13992
  //console.log("Build wav writer...");
13838
- this.processingRecording = true;
13839
13993
  if (ab) {
13994
+ this.processingRecording = true;
13840
13995
  let ww = new WavWriter();
13841
13996
  //new REST API URL
13842
13997
  let apiEndPoint = '';
@@ -13971,7 +14126,7 @@ class SessionManager extends BasicRecorder {
13971
14126
  }
13972
14127
  }
13973
14128
  }
13974
- SessionManager.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SessionManager, deps: [{ token: i1$3.BreakpointObserver }, { token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i1$4.MatDialog }, { token: SessionService }, { token: RecordingService }, { token: SpeechRecorderUploader }, { token: SPEECHRECORDER_CONFIG }], target: i0.ɵɵFactoryTarget.Component });
14129
+ SessionManager.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SessionManager, deps: [{ token: i1$2.BreakpointObserver }, { token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i1$3.MatDialog }, { token: SessionService }, { token: RecordingService }, { token: SpeechRecorderUploader }, { token: SPEECHRECORDER_CONFIG }], target: i0.ɵɵFactoryTarget.Component });
13975
14130
  SessionManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: SessionManager, selector: "app-sprrecordingsession", inputs: { projectName: "projectName", dataSaved: "dataSaved" }, host: { listeners: { "window:keypress": "onKeyPress($event)", "window:keydown": "onKeyDown($event)" } }, providers: [SessionService], viewQueries: [{ propertyName: "prompting", first: true, predicate: Prompting, descendants: true, static: true }, { propertyName: "liveLevelDisplay", first: true, predicate: LevelBar, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
13976
14131
  <app-warningbar [show]="isTestSession()" warningText="Test recording only!"></app-warningbar>
13977
14132
  <app-warningbar [show]="isDefaultAudioTestSession()" warningText="This test uses default audio device! Regular sessions may require a particular audio device (microphone)!"></app-warningbar>
@@ -14074,7 +14229,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
14074
14229
  </div>
14075
14230
  </div>
14076
14231
  `, styles: [":host{flex:2;background:lightgrey;display:flex;flex-direction:column;margin:0;padding:0;min-height:0px;overflow:hidden}\n", ".ricontrols{display:flex;padding:4px;box-sizing:border-box;height:100%;flex-direction:row;justify-content:flex-end;align-items:center;align-content:center}\n", ".dark{background:darkgray}\n", ".controlpanel{display:flex;flex-direction:row;align-content:center;align-items:center;margin:0;padding:20px;min-height:min-content}\n", ".audioStatusDisplay{display:flex;flex-direction:row;height:100px;min-height:100px}\n", ".audioStatusDisplayXs{display:flex;flex-direction:column;height:125px;min-height:125px}\n"] }]
14077
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i1$4.MatDialog }, { type: SessionService }, { type: RecordingService }, { type: SpeechRecorderUploader }, { type: SpeechRecorderConfig, decorators: [{
14232
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i1$3.MatDialog }, { type: SessionService }, { type: RecordingService }, { type: SpeechRecorderUploader }, { type: SpeechRecorderConfig, decorators: [{
14078
14233
  type: Inject,
14079
14234
  args: [SPEECHRECORDER_CONFIG]
14080
14235
  }] }]; }, propDecorators: { projectName: [{
@@ -14344,18 +14499,10 @@ class SpeechrecorderngComponent extends RecorderComponent {
14344
14499
  console.error(errMsg);
14345
14500
  }
14346
14501
  ngOnInit() {
14347
- try {
14348
- let audioContext = AudioContextProvider.audioContextInstance();
14349
- if (audioContext) {
14350
- this.controlAudioPlayer = new AudioPlayer(audioContext, this);
14351
- }
14352
- this.sm.controlAudioPlayer = this.controlAudioPlayer;
14353
- this.sm.statusAlertType = 'info';
14354
- this.sm.statusMsg = 'Player initialized.';
14355
- }
14356
- catch (err) {
14357
- this.handleError(err);
14358
- }
14502
+ this.controlAudioPlayer = new AudioPlayer(this);
14503
+ this.sm.controlAudioPlayer = this.controlAudioPlayer;
14504
+ this.sm.statusAlertType = 'info';
14505
+ this.sm.statusMsg = 'Player initialized.';
14359
14506
  }
14360
14507
  ngAfterViewInit() {
14361
14508
  // let wakeLockSupp=('wakeLock' in navigator);
@@ -14520,7 +14667,7 @@ class SpeechrecorderngComponent extends RecorderComponent {
14520
14667
  }
14521
14668
  else {
14522
14669
  // all this attempts to customize the message do not work anymore (for security reasons)!!
14523
- var message = "Please do not leave the page, until all recordings are uploaded!";
14670
+ const message = "Please do not leave the page, until all recordings are uploaded!";
14524
14671
  alert(message);
14525
14672
  e = e || window.event;
14526
14673
  if (e) {
@@ -14612,6 +14759,9 @@ class SpeechrecorderngComponent extends RecorderComponent {
14612
14759
  chCnt = ProjectUtil.audioChannelCount(project);
14613
14760
  console.info("Project requested recording channel count: " + chCnt);
14614
14761
  this.sm.autoGainControlConfigs = project.autoGainControlConfigs;
14762
+ if (project.allowEchoCancellation !== undefined) {
14763
+ this.sm.allowEchoCancellation = project.allowEchoCancellation;
14764
+ }
14615
14765
  if (project.chunkedRecording === true) {
14616
14766
  console.debug("Enable chunked upload: chunkSize: " + BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS);
14617
14767
  this.sm.uploadChunkSizeSeconds = BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS;
@@ -14644,7 +14794,7 @@ class SpeechrecorderngComponent extends RecorderComponent {
14644
14794
  projUrl = window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/wikispeech/rest/projects/?sessionId=' + this.sessionId;
14645
14795
  }
14646
14796
  if (projUrl) {
14647
- var pLoader = new XMLHttpRequest();
14797
+ const pLoader = new XMLHttpRequest();
14648
14798
  pLoader.open("GET", projUrl, true);
14649
14799
  pLoader.setRequestHeader('Accept', 'application/json');
14650
14800
  pLoader.responseType = "json";
@@ -14679,7 +14829,7 @@ class SpeechrecorderngComponent extends RecorderComponent {
14679
14829
  this.sm.statusMsg = 'ERROR: Recording.';
14680
14830
  }
14681
14831
  }
14682
- SpeechrecorderngComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SpeechrecorderngComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1$2.Router }, { token: i0.ChangeDetectorRef }, { token: SessionService }, { token: ProjectService }, { token: ScriptService }, { token: RecordingService }, { token: SpeechRecorderUploader }], target: i0.ɵɵFactoryTarget.Component });
14832
+ SpeechrecorderngComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SpeechrecorderngComponent, deps: [{ token: i4$2.ActivatedRoute }, { token: i4$2.Router }, { token: i0.ChangeDetectorRef }, { token: SessionService }, { token: ProjectService }, { token: ScriptService }, { token: RecordingService }, { token: SpeechRecorderUploader }], target: i0.ɵɵFactoryTarget.Component });
14683
14833
  SpeechrecorderngComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: SpeechrecorderngComponent, selector: "app-speechrecorder", providers: [SessionService], viewQueries: [{ propertyName: "sm", first: true, predicate: SessionManager, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
14684
14834
  <app-sprrecordingsession [projectName]="project?.name" [dataSaved]="dataSaved"></app-sprrecordingsession>
14685
14835
  `, isInline: true, styles: [":host{flex:2;display:flex;flex-direction:column;min-height:0}\n"], dependencies: [{ kind: "component", type: SessionManager, selector: "app-sprrecordingsession", inputs: ["projectName", "dataSaved"] }] });
@@ -14688,7 +14838,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
14688
14838
  args: [{ selector: 'app-speechrecorder', providers: [SessionService], template: `
14689
14839
  <app-sprrecordingsession [projectName]="project?.name" [dataSaved]="dataSaved"></app-sprrecordingsession>
14690
14840
  `, styles: [":host{flex:2;display:flex;flex-direction:column;min-height:0}\n"] }]
14691
- }], ctorParameters: function () { return [{ type: i1$2.ActivatedRoute }, { type: i1$2.Router }, { type: i0.ChangeDetectorRef }, { type: SessionService }, { type: ProjectService }, { type: ScriptService }, { type: RecordingService }, { type: SpeechRecorderUploader }]; }, propDecorators: { sm: [{
14841
+ }], ctorParameters: function () { return [{ type: i4$2.ActivatedRoute }, { type: i4$2.Router }, { type: i0.ChangeDetectorRef }, { type: SessionService }, { type: ProjectService }, { type: ScriptService }, { type: RecordingService }, { type: SpeechRecorderUploader }]; }, propDecorators: { sm: [{
14692
14842
  type: ViewChild,
14693
14843
  args: [SessionManager, { static: true }]
14694
14844
  }] } });
@@ -14708,10 +14858,8 @@ class AudioDisplayPlayer {
14708
14858
  this.ref = ref;
14709
14859
  this.eRef = eRef;
14710
14860
  this._audioUrl = null;
14711
- this.aCtx = null;
14712
14861
  this._audioClip = null;
14713
14862
  this.currentLoader = null;
14714
- //console.log("constructor: "+this.ac);
14715
14863
  this.parentE = this.eRef.nativeElement;
14716
14864
  this.playStartAction = new Action("Start");
14717
14865
  this.playSelectionAction = new Action("Play selected");
@@ -14719,26 +14867,18 @@ class AudioDisplayPlayer {
14719
14867
  this.status = "Player created.";
14720
14868
  }
14721
14869
  ngOnInit() {
14722
- //console.log("OnInit: "+this.ac);
14723
14870
  this.zoomSelectedAction = this.audioDisplayScrollPane.zoomSelectedAction;
14724
14871
  this.zoomFitToPanelAction = this.audioDisplayScrollPane.zoomFitToPanelAction;
14725
14872
  this.zoomOutAction = this.audioDisplayScrollPane.zoomOutAction;
14726
14873
  this.zoomInAction = this.audioDisplayScrollPane.zoomInAction;
14727
- try {
14728
- this.aCtx = AudioContextProvider.audioContextInstance();
14729
- if (this.aCtx) {
14730
- this.ap = new AudioPlayer(this.aCtx, this);
14731
- }
14732
- }
14733
- catch (err) {
14734
- if (err instanceof Error) {
14735
- this.status = err.message;
14736
- }
14737
- }
14874
+ this.ap = new AudioPlayer(this);
14738
14875
  }
14739
14876
  ngAfterViewInit() {
14740
- if (this.aCtx && this.ap) {
14741
- this.playStartAction.onAction = () => this.ap?.start();
14877
+ if (this.ap) {
14878
+ this.playStartAction.onAction = () => {
14879
+ console.debug("Start action, player: " + this.ap);
14880
+ this.ap?.start();
14881
+ };
14742
14882
  this.playSelectionAction.onAction = () => this.ap?.startSelected();
14743
14883
  this.playStopAction.onAction = () => this.ap?.stop();
14744
14884
  }
@@ -14803,15 +14943,12 @@ class AudioDisplayPlayer {
14803
14943
  //console.debug("Loaded");
14804
14944
  this.status = 'Audio file loaded.';
14805
14945
  //console.debug("Received data ", data.byteLength);
14806
- // Do not use Promise version, which does not work with Safari 13
14807
- if (this.aCtx) {
14808
- this.aCtx.decodeAudioData(data, (audioBuffer) => {
14809
- //console.debug("Audio Buffer Samplerate: ", audioBuffer.sampleRate)
14810
- let as = new AudioBufferSource(audioBuffer);
14811
- let adh = new AudioDataHolder(as);
14812
- this.audioClip = new AudioClip(adh);
14813
- });
14814
- }
14946
+ AudioContextProvider.decodeAudioData(data).then(audioBuffer => {
14947
+ //console.debug("Audio Buffer Samplerate: ", audioBuffer.sampleRate)
14948
+ let as = new AudioBufferSource(audioBuffer);
14949
+ let adh = new AudioDataHolder(as);
14950
+ this.audioClip = new AudioClip(adh);
14951
+ });
14815
14952
  }
14816
14953
  set audioData(audioData) {
14817
14954
  this.audioDisplayScrollPane.audioData = audioData;
@@ -14894,7 +15031,7 @@ class AudioDisplayPlayer {
14894
15031
  this.status = 'ERROR';
14895
15032
  }
14896
15033
  }
14897
- AudioDisplayPlayer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioDisplayPlayer, deps: [{ token: i1$2.ActivatedRoute }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
15034
+ AudioDisplayPlayer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioDisplayPlayer, deps: [{ token: i4$2.ActivatedRoute }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
14898
15035
  AudioDisplayPlayer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: AudioDisplayPlayer, selector: "app-audiodisplayplayer", inputs: { playStartAction: "playStartAction", playStopAction: "playStopAction", playSelectionAction: "playSelectionAction", autoPlayOnSelectToggleAction: "autoPlayOnSelectToggleAction", audioData: "audioData", audioClip: "audioClip" }, viewQueries: [{ propertyName: "audioDisplayScrollPane", first: true, predicate: AudioDisplayScrollPane, descendants: true, static: true }], ngImport: i0, template: `
14899
15036
 
14900
15037
  <audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
@@ -14925,7 +15062,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
14925
15062
  [zoomSelectedAction]="zoomSelectedAction"
14926
15063
  [zoomFitToPanelAction]="zoomFitToPanelAction"></audio-display-control><p>{{status}}
14927
15064
  `, styles: [":host{display:flex;flex-direction:column;position:absolute;bottom:0;height:100%;width:100%;overflow:hidden;padding:20px;z-index:5;box-sizing:border-box;background-color:#000000bf}\n"] }]
14928
- }], ctorParameters: function () { return [{ type: i1$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { playStartAction: [{
15065
+ }], ctorParameters: function () { return [{ type: i4$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { playStartAction: [{
14929
15066
  type: Input
14930
15067
  }], playStopAction: [{
14931
15068
  type: Input
@@ -15071,41 +15208,42 @@ class RecordingFileService extends BasicRecordingService {
15071
15208
  });
15072
15209
  }
15073
15210
  // TODO test
15074
- fetchAndApplyRecordingFile(aCtx, recordingFile) {
15211
+ fetchAndApplyRecordingFile(recordingFile) {
15075
15212
  let wobs = new Observable(observer => {
15076
15213
  if (recordingFile.recordingFileId) {
15077
15214
  let obs = this.fetchAudiofile(recordingFile.recordingFileId);
15078
- obs.subscribe(resp => {
15079
- // Do not use Promise version, which does not work with Safari 13
15080
- if (resp.body) {
15081
- aCtx.decodeAudioData(resp.body, ab => {
15082
- let as = new AudioBufferSource(ab);
15083
- RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(as));
15084
- if (this.debugDelay > 0) {
15085
- window.setTimeout(() => {
15215
+ obs.subscribe({ next: resp => {
15216
+ if (resp.body) {
15217
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
15218
+ let as = new AudioBufferSource(ab);
15219
+ RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(as));
15220
+ if (this.debugDelay > 0) {
15221
+ window.setTimeout(() => {
15222
+ observer.next(recordingFile);
15223
+ observer.complete();
15224
+ }, this.debugDelay);
15225
+ }
15226
+ else {
15086
15227
  observer.next(recordingFile);
15087
15228
  observer.complete();
15088
- }, this.debugDelay);
15089
- }
15090
- else {
15091
- observer.next(recordingFile);
15092
- observer.complete();
15093
- }
15094
- });
15095
- }
15096
- else {
15097
- observer.error('Received no audio data!');
15098
- }
15099
- }, (error) => {
15100
- if (error.status == 404) {
15101
- // Interpret not as an error, the file ist not recorded yet
15102
- observer.next(null);
15103
- observer.complete();
15104
- }
15105
- else {
15106
- // all other states are errors
15107
- observer.error(error);
15108
- observer.complete();
15229
+ }
15230
+ }).catch(reason => { observer.error(reason); });
15231
+ }
15232
+ else {
15233
+ observer.error('Received no audio data!');
15234
+ }
15235
+ },
15236
+ error: (error) => {
15237
+ if (error.status == 404) {
15238
+ // Interpret not as an error, the file ist not recorded yet
15239
+ observer.next(null);
15240
+ observer.complete();
15241
+ }
15242
+ else {
15243
+ // all other states are errors
15244
+ observer.error(error);
15245
+ observer.complete();
15246
+ }
15109
15247
  }
15110
15248
  });
15111
15249
  }
@@ -15119,82 +15257,40 @@ class RecordingFileService extends BasicRecordingService {
15119
15257
  let wobs = new Observable(observer => {
15120
15258
  let rf = null;
15121
15259
  let rfDescrObs = this.recordingFileDescrObserver(recordingFileId);
15122
- rfDescrObs.subscribe(value => {
15123
- rf = value;
15124
- }, (error) => {
15125
- observer.error(error);
15126
- }, () => {
15127
- let rfAudioObs = this.fetchAudiofile(recordingFileId);
15128
- rfAudioObs.subscribe(resp => {
15129
- // Do not use Promise version, which does not work with Safari 13
15130
- if (resp.body) {
15131
- aCtx.decodeAudioData(resp.body, ab => {
15132
- if (rf) {
15133
- let as = new AudioBufferSource(ab);
15134
- RecordingFileUtils.setAudioData(rf, new AudioDataHolder(as));
15135
- }
15136
- else {
15137
- observer.error('Recording file object null');
15138
- }
15139
- if (this.debugDelay > 0) {
15140
- window.setTimeout(() => {
15141
- observer.next(rf);
15142
- observer.complete();
15143
- }, this.debugDelay);
15260
+ rfDescrObs.subscribe({ next: value => {
15261
+ rf = value;
15262
+ }, error: (error) => {
15263
+ observer.error(error);
15264
+ }, complete: () => {
15265
+ let rfAudioObs = this.fetchAudiofile(recordingFileId);
15266
+ rfAudioObs.subscribe({
15267
+ next: resp => {
15268
+ // Do not use Promise version, which does not work with Safari 13
15269
+ if (resp.body) {
15270
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
15271
+ if (rf) {
15272
+ let as = new AudioBufferSource(ab);
15273
+ RecordingFileUtils.setAudioData(rf, new AudioDataHolder(as));
15274
+ }
15275
+ else {
15276
+ observer.error('Recording file object null');
15277
+ }
15278
+ if (this.debugDelay > 0) {
15279
+ window.setTimeout(() => {
15280
+ observer.next(rf);
15281
+ observer.complete();
15282
+ }, this.debugDelay);
15283
+ }
15284
+ else {
15285
+ observer.next(rf);
15286
+ observer.complete();
15287
+ }
15288
+ }).catch(reason => { observer.error(reason); });
15144
15289
  }
15145
15290
  else {
15146
- observer.next(rf);
15147
- observer.complete();
15148
- }
15149
- });
15150
- }
15151
- else {
15152
- observer.error('Received no audio data');
15153
- }
15154
- }, (error) => {
15155
- if (error.status == 404) {
15156
- // Interpret not as an error, the file ist not recorded yet
15157
- observer.next(null);
15158
- observer.complete();
15159
- }
15160
- else {
15161
- // all other states are errors
15162
- observer.error(error);
15163
- observer.complete();
15164
- }
15165
- });
15166
- });
15167
- });
15168
- return wobs;
15169
- }
15170
- fetchSprRecordingFile(aCtx, recordingFileId) {
15171
- let wobs = new Observable(observer => {
15172
- let rf = null;
15173
- let rfDescrObs = this.sprRecordingFileDescrObserver(recordingFileId);
15174
- rfDescrObs.subscribe(value => {
15175
- rf = value;
15176
- }, (error) => {
15177
- observer.error(error);
15178
- }, () => {
15179
- let sampleCnt = null;
15180
- if (rf && rf.channels && rf.frames) {
15181
- sampleCnt = rf.channels * rf.frames;
15182
- }
15183
- // TODO use download storage type depending on sample count of file
15184
- if (rf && rf.samplerate && sampleCnt != null && sampleCnt > this._maxAutoNetMemStoreSamples) {
15185
- const baseUrl = this.recoFileUrl(recordingFileId);
15186
- const obNetAb = this.chunkAudioRequestToNetAudioBuffer(aCtx, baseUrl, 0, rf?.samplerate, BasicRecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS, rf.frames);
15187
- obNetAb.subscribe({
15188
- next: (nab) => {
15189
- let adh = new AudioDataHolder(nab);
15190
- if (rf) {
15191
- RecordingFileUtils.setAudioData(rf, adh);
15192
- observer.next(rf);
15291
+ observer.error('Received no audio data');
15193
15292
  }
15194
15293
  },
15195
- complete: () => {
15196
- observer.complete();
15197
- },
15198
15294
  error: (error) => {
15199
15295
  if (error.status == 404) {
15200
15296
  // Interpret not as an error, the file ist not recorded yet
@@ -15209,47 +15305,97 @@ class RecordingFileService extends BasicRecordingService {
15209
15305
  }
15210
15306
  });
15211
15307
  }
15212
- else {
15213
- let rfAudioObs = this.fetchAudiofile(recordingFileId);
15214
- rfAudioObs.subscribe(resp => {
15215
- // Do not use Promise version, which does not work with Safari 13
15216
- if (resp.body) {
15217
- aCtx.decodeAudioData(resp.body, ab => {
15308
+ });
15309
+ });
15310
+ return wobs;
15311
+ }
15312
+ fetchSprRecordingFile(recordingFileId) {
15313
+ let wobs = new Observable(observer => {
15314
+ let rf = null;
15315
+ let rfDescrObs = this.sprRecordingFileDescrObserver(recordingFileId);
15316
+ rfDescrObs.subscribe({ next: value => {
15317
+ rf = value;
15318
+ },
15319
+ error: (error) => {
15320
+ observer.error(error);
15321
+ }, complete: () => {
15322
+ let sampleCnt = null;
15323
+ if (rf && rf.channels && rf.frames) {
15324
+ sampleCnt = rf.channels * rf.frames;
15325
+ }
15326
+ // TODO use download storage type depending on sample count of file
15327
+ if (rf && rf.samplerate && sampleCnt != null && sampleCnt > this._maxAutoNetMemStoreSamples) {
15328
+ const baseUrl = this.recoFileUrl(recordingFileId);
15329
+ const obNetAb = this.chunkAudioRequestToNetAudioBuffer(baseUrl, 0, rf?.samplerate, BasicRecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS, rf.frames);
15330
+ obNetAb.subscribe({
15331
+ next: (nab) => {
15332
+ let adh = new AudioDataHolder(nab);
15218
15333
  if (rf) {
15219
- let as = new AudioBufferSource(ab);
15220
- let adh = new AudioDataHolder(as);
15221
15334
  RecordingFileUtils.setAudioData(rf, adh);
15335
+ observer.next(rf);
15336
+ }
15337
+ },
15338
+ complete: () => {
15339
+ observer.complete();
15340
+ },
15341
+ error: (error) => {
15342
+ if (error.status == 404) {
15343
+ // Interpret not as an error, the file ist not recorded yet
15344
+ observer.next(null);
15345
+ observer.complete();
15222
15346
  }
15223
15347
  else {
15224
- observer.error('Recording file object null');
15348
+ // all other states are errors
15349
+ observer.error(error);
15350
+ observer.complete();
15225
15351
  }
15226
- if (this.debugDelay > 0) {
15227
- window.setTimeout(() => {
15228
- observer.next(rf);
15229
- observer.complete();
15230
- }, this.debugDelay);
15352
+ }
15353
+ });
15354
+ }
15355
+ else {
15356
+ let rfAudioObs = this.fetchAudiofile(recordingFileId);
15357
+ rfAudioObs.subscribe({ next: resp => {
15358
+ // Do not use Promise version, which does not work with Safari 13
15359
+ if (resp.body) {
15360
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
15361
+ if (rf) {
15362
+ let as = new AudioBufferSource(ab);
15363
+ let adh = new AudioDataHolder(as);
15364
+ RecordingFileUtils.setAudioData(rf, adh);
15365
+ }
15366
+ else {
15367
+ observer.error('Recording file object null');
15368
+ }
15369
+ if (this.debugDelay > 0) {
15370
+ window.setTimeout(() => {
15371
+ observer.next(rf);
15372
+ observer.complete();
15373
+ }, this.debugDelay);
15374
+ }
15375
+ else {
15376
+ observer.next(rf);
15377
+ observer.complete();
15378
+ }
15379
+ }).catch(reason => { observer.error(reason); });
15231
15380
  }
15232
15381
  else {
15233
- observer.next(rf);
15382
+ observer.error('Received no audio data');
15383
+ }
15384
+ },
15385
+ error: (error) => {
15386
+ if (error.status == 404) {
15387
+ // Interpret not as an error, the file ist not recorded yet
15388
+ observer.next(null);
15234
15389
  observer.complete();
15235
15390
  }
15236
- });
15237
- }
15238
- else {
15239
- observer.error('Received no audio data');
15240
- }
15241
- }, (error) => {
15242
- if (error.status == 404) {
15243
- // Interpret not as an error, the file ist not recorded yet
15244
- observer.next(null);
15245
- observer.complete();
15246
- }
15247
- else {
15248
- // all other states are errors
15249
- observer.error(error);
15250
- observer.complete();
15251
- }
15252
- });
15391
+ else {
15392
+ // all other states are errors
15393
+ observer.error(error);
15394
+ observer.complete();
15395
+ }
15396
+ }
15397
+ });
15398
+ }
15253
15399
  }
15254
15400
  });
15255
15401
  });
@@ -15301,7 +15447,7 @@ RecordingFileNaviComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0
15301
15447
  <legend>Versions</legend>
15302
15448
  <mat-progress-spinner *ngIf="naviInfoLoading" mode="indeterminate" [diameter]="15"></mat-progress-spinner>
15303
15449
  <select *ngIf="!naviInfoLoading" [disabled]="versions==null || versions.length==1" (change)="selectVersionChange($event)">
15304
- <option *ngFor="let v of versions; let i = index" [selected]="v===version" value="{{v}}">{{v}}<span *ngIf="i==0"> (latest)</span></option>
15450
+ <option *ngFor="let v of versions; let i = index" [selected]="v===version" value="{{v}}">{{v}}<ng-container *ngIf="i==0"> (latest)</ng-container></option>
15305
15451
  </select>
15306
15452
  </fieldset>
15307
15453
  <fieldset>
@@ -15336,7 +15482,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
15336
15482
  <legend>Versions</legend>
15337
15483
  <mat-progress-spinner *ngIf="naviInfoLoading" mode="indeterminate" [diameter]="15"></mat-progress-spinner>
15338
15484
  <select *ngIf="!naviInfoLoading" [disabled]="versions==null || versions.length==1" (change)="selectVersionChange($event)">
15339
- <option *ngFor="let v of versions; let i = index" [selected]="v===version" value="{{v}}">{{v}}<span *ngIf="i==0"> (latest)</span></option>
15485
+ <option *ngFor="let v of versions; let i = index" [selected]="v===version" value="{{v}}">{{v}}<ng-container *ngIf="i==0"> (latest)</ng-container></option>
15340
15486
  </select>
15341
15487
  </fieldset>
15342
15488
  <fieldset>
@@ -15388,9 +15534,9 @@ class RecordingFileMetaComponent {
15388
15534
  constructor() {
15389
15535
  this.sessionId = null;
15390
15536
  this._recordingFile = null;
15391
- this.stateLoading = false;
15392
15537
  this.itemCode = null;
15393
15538
  this.uuid = null;
15539
+ this.stateLoading = false;
15394
15540
  }
15395
15541
  get recordingFile() {
15396
15542
  return this._recordingFile;
@@ -15498,7 +15644,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
15498
15644
  </mat-card-content>
15499
15645
  </mat-card>
15500
15646
  ` }]
15501
- }], propDecorators: { sessionId: [{
15647
+ }], ctorParameters: function () { return []; }, propDecorators: { sessionId: [{
15502
15648
  type: Input
15503
15649
  }], stateLoading: [{
15504
15650
  type: Input
@@ -15519,7 +15665,6 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15519
15665
  this.ref = ref;
15520
15666
  this.eRef = eRef;
15521
15667
  this.dialog = dialog;
15522
- //protected _recordingFileId: string | number = null;
15523
15668
  this.sessionId = null;
15524
15669
  this.sessionIdFromRoute = null;
15525
15670
  this.availRecFiles = null;
@@ -15528,9 +15673,11 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15528
15673
  this.recordingFileVersion = null;
15529
15674
  this.routedByQueryParam = false;
15530
15675
  this.posInList = null;
15531
- this.audioFetching = false;
15532
- this.naviInfoLoading = false;
15533
15676
  this.parentE = this.eRef.nativeElement;
15677
+ // TODO Should be initialized with false, but this causes in debug mode:
15678
+ // ERROR Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'. Find more at https://angular.io/errors/NG0100
15679
+ this.audioFetching = true;
15680
+ this.naviInfoLoading = false;
15534
15681
  this.firstAction = new Action('First');
15535
15682
  this.firstAction.onAction = () => {
15536
15683
  this.posInList = 0;
@@ -15696,10 +15843,9 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15696
15843
  this.recordingFile = null;
15697
15844
  this.posInList = null;
15698
15845
  this.updateActions();
15699
- let audioContext = AudioContextProvider.audioContextInstance();
15700
- if (audioContext) {
15701
- this.audioFetching = true;
15702
- this.recordingFileService.fetchSprRecordingFile(audioContext, rfId).subscribe(value => {
15846
+ this.audioFetching = true;
15847
+ this.recordingFileService.fetchSprRecordingFile(rfId).subscribe({
15848
+ next: value => {
15703
15849
  this.audioFetching = false;
15704
15850
  this.status = 'Audio file loaded.';
15705
15851
  let clip = null;
@@ -15737,11 +15883,11 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15737
15883
  }
15738
15884
  this.audioClip = clip;
15739
15885
  this.loadedRecfile();
15740
- }, error1 => {
15886
+ }, error: error1 => {
15741
15887
  this.audioFetching = false;
15742
15888
  this.status = 'Error loading audio file!';
15743
- });
15744
- }
15889
+ }
15890
+ });
15745
15891
  }
15746
15892
  loadedRecfile() {
15747
15893
  if (this.recordingFile && !this.sessionId) {
@@ -15767,7 +15913,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15767
15913
  this.lastAction.disabled = (this.posInList == null || itemCnt == null || this.posInList >= itemCnt - 1);
15768
15914
  }
15769
15915
  loadSession(sessionId) {
15770
- // load session and recording file meta data only when on init and when session changes
15916
+ // load session and recording file metadata only when on init and when session changes
15771
15917
  if (sessionId != this.sessionId) {
15772
15918
  // tell UI that we are working...
15773
15919
  this.naviInfoLoading = true;
@@ -15805,7 +15951,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15805
15951
  else {
15806
15952
  // rec file with itemcode already exists, add (push) this version ...
15807
15953
  exRfsForIc.push(rfd);
15808
- // .. and sort latest version (highest version number) to lowest index
15954
+ // ... and sort latest version (highest version number) to lowest index
15809
15955
  exRfsForIc.sort((rfd1, rfd2) => {
15810
15956
  return rfd2.version - rfd1.version;
15811
15957
  });
@@ -15859,7 +16005,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15859
16005
  }
15860
16006
  }
15861
16007
  }
15862
- RecordingFileViewComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingFileViewComponent, deps: [{ token: RecordingFileService }, { token: RecordingService }, { token: SessionService }, { token: i1$2.Router }, { token: i1$2.ActivatedRoute }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i1$4.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
16008
+ RecordingFileViewComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingFileViewComponent, deps: [{ token: RecordingFileService }, { token: RecordingService }, { token: SessionService }, { token: i4$2.Router }, { token: i4$2.ActivatedRoute }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i1$3.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
15863
16009
  RecordingFileViewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: RecordingFileViewComponent, selector: "app-audiodisplayplayer", viewQueries: [{ propertyName: "ac", first: true, predicate: AudioDisplayScrollPane, descendants: true }], usesInheritance: true, ngImport: i0, template: `
15864
16010
 
15865
16011
  <audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
@@ -15898,7 +16044,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
15898
16044
  <app-recording-file-navi [items]="availRecFiles?.length" [itemPos]="posInList" [version]="recordingFileVersion" [versions]="versions" [firstAction]="firstAction" [prevAction]="prevAction" [nextAction]="nextAction" [lastAction]="lastAction" [selectVersion]="toVersionAction" [naviInfoLoading]="naviInfoLoading"></app-recording-file-navi>
15899
16045
  </div>
15900
16046
  `, styles: [":host{flex:2;display:flex;flex-direction:column;min-height:0;overflow:hidden;padding:20px;z-index:5;box-sizing:border-box;background-color:#fff}\n", ".ctrlview{display:flex;flex-direction:row}\n", "audio-display-control{flex:3}\n"] }]
15901
- }], ctorParameters: function () { return [{ type: RecordingFileService }, { type: RecordingService }, { type: SessionService }, { type: i1$2.Router }, { type: i1$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i1$4.MatDialog }]; }, propDecorators: { ac: [{
16047
+ }], ctorParameters: function () { return [{ type: RecordingFileService }, { type: RecordingService }, { type: SessionService }, { type: i4$2.Router }, { type: i4$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i1$3.MatDialog }]; }, propDecorators: { ac: [{
15902
16048
  type: ViewChild,
15903
16049
  args: [AudioDisplayScrollPane]
15904
16050
  }] } });
@@ -15963,27 +16109,28 @@ class RecordingFileUI extends RecordingFileViewComponent {
15963
16109
  sf = s.startFrame;
15964
16110
  ef = s.endFrame;
15965
16111
  }
15966
- this.recordingFileService.saveEditSelection(this.recordingFile.recordingFileId, sr, sf, ef).subscribe((value) => {
15967
- }, () => {
15968
- this.dialog.open(MessageDialog, {
15969
- data: {
15970
- type: 'error',
15971
- title: 'Save selection edit error',
15972
- msg: "Could not save edit selection to WikiSpeech server!",
15973
- advice: "Please check network connection and server state."
15974
- }
15975
- });
15976
- }, () => {
15977
- // Or use returned selection value from server?
15978
- this.savedEditSelection = s;
15979
- this.editSaved = true;
15980
- this.snackBar.open('Selection edit saved successfully.', 'OK', { duration: 1500 });
16112
+ this.recordingFileService.saveEditSelection(this.recordingFile.recordingFileId, sr, sf, ef).subscribe({ next: (value) => { },
16113
+ error: () => {
16114
+ this.dialog.open(MessageDialog, {
16115
+ data: {
16116
+ type: 'error',
16117
+ title: 'Save selection edit error',
16118
+ msg: "Could not save edit selection to WikiSpeech server!",
16119
+ advice: "Please check network connection and server state."
16120
+ }
16121
+ });
16122
+ }, complete: () => {
16123
+ // Or use returned selection value from server?
16124
+ this.savedEditSelection = s;
16125
+ this.editSaved = true;
16126
+ this.snackBar.open('Selection edit saved successfully.', 'OK', { duration: 1500 });
16127
+ }
15981
16128
  });
15982
16129
  }
15983
16130
  }
15984
16131
  }
15985
16132
  }
15986
- RecordingFileUI.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingFileUI, deps: [{ token: RecordingFileService }, { token: RecordingService }, { token: SessionService }, { token: i1$2.Router }, { token: i1$2.ActivatedRoute }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i1$4.MatDialog }, { token: i6.MatSnackBar }], target: i0.ɵɵFactoryTarget.Component });
16133
+ RecordingFileUI.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingFileUI, deps: [{ token: RecordingFileService }, { token: RecordingService }, { token: SessionService }, { token: i4$2.Router }, { token: i4$2.ActivatedRoute }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i1$3.MatDialog }, { token: i6.MatSnackBar }], target: i0.ɵɵFactoryTarget.Component });
15987
16134
  RecordingFileUI.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: RecordingFileUI, selector: "app-audiodisplayplayer", usesInheritance: true, ngImport: i0, template: `
15988
16135
  <h1>Recording file editing</h1>
15989
16136
  <p>On export or delivery the editing selection of the recording file is cut out. If no editing selection is applied the original file is exported.</p>
@@ -16028,7 +16175,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
16028
16175
 
16029
16176
  <button mat-raised-button color="accent" (click)="applySelection()" [disabled]="editSaved">{{this.applyButtonText()}}</button>
16030
16177
  `, styles: [":host{flex:2;display:flex;flex-direction:column;min-height:0;overflow:hidden;padding:20px;z-index:5;box-sizing:border-box;background-color:#fff}\n", ".ctrlview{display:flex;flex-direction:row}\n", "audio-display-control{flex:3}\n"] }]
16031
- }], ctorParameters: function () { return [{ type: RecordingFileService }, { type: RecordingService }, { type: SessionService }, { type: i1$2.Router }, { type: i1$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i1$4.MatDialog }, { type: i6.MatSnackBar }]; } });
16178
+ }], ctorParameters: function () { return [{ type: RecordingFileService }, { type: RecordingService }, { type: SessionService }, { type: i4$2.Router }, { type: i4$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i1$3.MatDialog }, { type: i6.MatSnackBar }]; } });
16032
16179
 
16033
16180
  class MediaUtils {
16034
16181
  static toMediaTime(timeInSeconds) {
@@ -16165,7 +16312,7 @@ RecordingList.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version:
16165
16312
  </mat-card-content>
16166
16313
  </mat-card>
16167
16314
 
16168
- `, isInline: true, styles: [".monospaced{font-family:monospace}.mat-cell,.mat-header-cell{padding-left:5px;padding-right:5px}.mat-card,.mat-card-header,.mat-card-content{width:auto}.flexForm{display:flex;flex-direction:column;width:auto}.flexFill{margin:0;width:100%;height:100%;min-width:100%;min-height:100%}\n", ":host{position:relative;margin:0;padding:0;background:lightgrey;width:100%;flex:1;overflow-y:auto;min-height:0px}\n", ".selected{font-weight:700}\n"], dependencies: [{ kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$2.MatCard, selector: "mat-card", exportAs: ["matCard"] }, { kind: "component", type: i3$2.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i3$2.MatCardContent, selector: "mat-card-content, [mat-card-content], [matCardContent]" }, { kind: "component", type: i4$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i4$2.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: ScrollIntoViewDirective, selector: "[scrollIntoViewToBottom]", inputs: ["scrollIntoViewToBottom"] }, { kind: "pipe", type: i1$1.DatePipe, name: "date" }] });
16315
+ `, isInline: true, styles: [".monospaced{font-family:monospace}.mat-cell,.mat-header-cell{padding-left:5px;padding-right:5px}.mat-card,.mat-card-header,.mat-card-content{width:auto}.flexForm{display:flex;flex-direction:column;width:auto}.flexFill{margin:0;width:100%;height:100%;min-width:100%;min-height:100%}\n", ":host{position:relative;margin:0;padding:0;background:lightgrey;width:100%;flex:1;overflow-y:auto;min-height:0px}\n", ".selected{font-weight:700}\n"], dependencies: [{ kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$2.MatCard, selector: "mat-card", exportAs: ["matCard"] }, { kind: "component", type: i3$2.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i3$2.MatCardContent, selector: "mat-card-content, [mat-card-content], [matCardContent]" }, { kind: "component", type: i4$3.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4$3.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4$3.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4$3.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i4$3.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4$3.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4$3.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4$3.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4$3.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4$3.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: ScrollIntoViewDirective, selector: "[scrollIntoViewToBottom]", inputs: ["scrollIntoViewToBottom"] }, { kind: "pipe", type: i1$1.DatePipe, name: "date" }] });
16169
16316
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingList, decorators: [{
16170
16317
  type: Component,
16171
16318
  args: [{ selector: 'app-recordinglist', template: `
@@ -16246,7 +16393,7 @@ class RecorderCombiPane extends ResponsiveComponent {
16246
16393
  this.recordingListComp.selectTop();
16247
16394
  }
16248
16395
  }
16249
- RecorderCombiPane.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecorderCombiPane, deps: [{ token: i1$3.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Component });
16396
+ RecorderCombiPane.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecorderCombiPane, deps: [{ token: i1$2.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Component });
16250
16397
  RecorderCombiPane.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: RecorderCombiPane, selector: "app-recordercombipane", inputs: { selectDisabled: "selectDisabled", selectedRecordingFile: "selectedRecordingFile", audioSignalCollapsed: "audioSignalCollapsed", displayAudioClip: "displayAudioClip", playStartAction: "playStartAction", playSelectionAction: "playSelectionAction", autoPlayOnSelectToggleAction: "autoPlayOnSelectToggleAction", playStopAction: "playStopAction" }, outputs: { selectedRecordingFileChanged: "selectedRecordingFileChanged" }, viewQueries: [{ propertyName: "recordingListComp", first: true, predicate: RecordingList, descendants: true }, { propertyName: "audioDisplay", first: true, predicate: AudioDisplay, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
16251
16398
  <div class="scrollList">
16252
16399
  <app-recordinglist [selectedRecordingFile]="selectedRecordingFile" [selectDisabled]="selectDisabled" (selectedRecordingFileChanged)="selectRecordingFile($event)"></app-recordinglist>
@@ -16275,7 +16422,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
16275
16422
  [playStopAction]="playStopAction"></app-audiodisplay>
16276
16423
  </div>
16277
16424
  `, styles: [".monospaced{font-family:monospace}.mat-cell,.mat-header-cell{padding-left:5px;padding-right:5px}.mat-card,.mat-card-header,.mat-card-content{width:auto}.flexForm{display:flex;flex-direction:column;width:auto}.flexFill{margin:0;width:100%;height:100%;min-width:100%;min-height:100%}\n", ":host{background-color:#ff0;position:relative;margin:0;padding:0;background:lightgrey;width:100%;flex:1;min-height:0px}\n", ".scrollList{margin:0;padding:0;background:lightgrey;width:100%;height:100%;overflow-y:auto}\n", ".collapsable{display:none;position:absolute;z-index:5}\n", ".collapsable.active{display:flex;position:absolute;bottom:0;height:90%;width:100%;overflow:hidden;padding:0;z-index:200;box-sizing:border-box;background-color:#0000}\n"] }]
16278
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }]; }, propDecorators: { recordingListComp: [{
16425
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }]; }, propDecorators: { recordingListComp: [{
16279
16426
  type: ViewChild,
16280
16427
  args: [RecordingList]
16281
16428
  }], selectDisabled: [{
@@ -16302,11 +16449,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
16302
16449
  }] } });
16303
16450
 
16304
16451
  class AudioRecorder extends BasicRecorder {
16305
- constructor(bpo, changeDetectorRef, renderer, route, dialog, sessionService, recFileService, uploader, config) {
16452
+ constructor(bpo, changeDetectorRef, renderer, dialog, sessionService, recFileService, uploader, config) {
16306
16453
  super(bpo, changeDetectorRef, dialog, sessionService, uploader, config);
16307
16454
  this.bpo = bpo;
16308
16455
  this.renderer = renderer;
16309
- this.route = route;
16310
16456
  this.recFileService = recFileService;
16311
16457
  this.uploader = uploader;
16312
16458
  this._project = null;
@@ -16351,38 +16497,17 @@ class AudioRecorder extends BasicRecorder {
16351
16497
  this.transportActions.nextAction.disabled = true;
16352
16498
  this.transportActions.pauseAction.disabled = true;
16353
16499
  this.playStartAction.disabled = true;
16354
- //this.audioLoaded=false;
16355
- let context = null;
16356
- try {
16357
- context = AudioContextProvider.audioContextInstance();
16358
- }
16359
- catch (err) {
16360
- this.status = 5 /* ERROR */;
16361
- let errMsg = 'Unknown error';
16362
- if (err instanceof Error) {
16363
- errMsg = err.message;
16364
- }
16365
- this.statusMsg = 'ERROR: ' + errMsg;
16366
- this.statusAlertType = 'error';
16367
- this.dialog.open(MessageDialog, {
16368
- data: {
16369
- type: 'error',
16370
- title: 'Error',
16371
- msg: errMsg,
16372
- advice: 'Please use a supported browser.',
16373
- }
16374
- });
16375
- return;
16376
- }
16377
- if (context) {
16378
- console.info("State of audio context: " + context.state);
16500
+ this.ac = new AudioCapture();
16501
+ if (this.ac) {
16502
+ this.transportActions.startAction.onAction = () => this.startItem();
16503
+ this.ac.listener = this;
16504
+ this.configureStreamCaptureStream();
16505
+ // Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
16506
+ //this.ac.listDevices();
16379
16507
  }
16380
16508
  else {
16381
- console.info("No audio context available!");
16382
- }
16383
- if (!context || !navigator.mediaDevices) {
16384
- this.status = 5 /* ERROR */;
16385
- let errMsg = 'Browser does not support Media streams!';
16509
+ this.transportActions.startAction.disabled = true;
16510
+ let errMsg = 'Browser does not support Media/Audio API!';
16386
16511
  this.statusMsg = 'ERROR: ' + errMsg;
16387
16512
  this.statusAlertType = 'error';
16388
16513
  this.dialog.open(MessageDialog, {
@@ -16395,36 +16520,10 @@ class AudioRecorder extends BasicRecorder {
16395
16520
  });
16396
16521
  return;
16397
16522
  }
16398
- else {
16399
- //this.controlAudioPlayer = new AudioPlayer(context, this);
16400
- this.ac = new AudioCapture(context);
16401
- if (this.ac) {
16402
- this.transportActions.startAction.onAction = () => this.startItem();
16403
- this.ac.listener = this;
16404
- this.configureStreamCaptureStream();
16405
- // Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
16406
- //this.ac.listDevices();
16407
- }
16408
- else {
16409
- this.transportActions.startAction.disabled = true;
16410
- let errMsg = 'Browser does not support Media/Audio API!';
16411
- this.statusMsg = 'ERROR: ' + errMsg;
16412
- this.statusAlertType = 'error';
16413
- this.dialog.open(MessageDialog, {
16414
- data: {
16415
- type: 'error',
16416
- title: 'Error',
16417
- msg: errMsg,
16418
- advice: 'Please use a supported browser.',
16419
- }
16420
- });
16421
- return;
16422
- }
16423
- this.transportActions.stopAction.onAction = () => this.stopItem();
16424
- this.transportActions.nextAction.onAction = () => this.stopItem();
16425
- //this.transportActions.pauseAction.onAction = () => this.pauseItem();
16426
- this.playStartAction.onAction = () => this.controlAudioPlayer?.start();
16427
- }
16523
+ this.transportActions.stopAction.onAction = () => this.stopItem();
16524
+ this.transportActions.nextAction.onAction = () => this.stopItem();
16525
+ //this.transportActions.pauseAction.onAction = () => this.pauseItem();
16526
+ this.playStartAction.onAction = () => this.controlAudioPlayer?.start();
16428
16527
  this.uploader.listener = (ue) => {
16429
16528
  this.uploadUpdate(ue);
16430
16529
  };
@@ -16533,6 +16632,9 @@ class AudioRecorder extends BasicRecorder {
16533
16632
  chCnt = ProjectUtil.audioChannelCount(project);
16534
16633
  console.info("Project requested recording channel count: " + chCnt);
16535
16634
  this.autoGainControlConfigs = project.autoGainControlConfigs;
16635
+ if (project.allowEchoCancellation !== undefined) {
16636
+ this.allowEchoCancellation = project.allowEchoCancellation;
16637
+ }
16536
16638
  if (project.chunkedRecording === true) {
16537
16639
  this.uploadChunkSizeSeconds = BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS;
16538
16640
  }
@@ -16733,7 +16835,7 @@ class AudioRecorder extends BasicRecorder {
16733
16835
  }
16734
16836
  else {
16735
16837
  //console.debug("Fetch audio and store to indexed db...");
16736
- this.audioFetchSubscription = this.recFileService.fetchRecordingFileIndDbAudioBuffer(this._controlAudioPlayer.context, this._persistentAudioStorageTarget, this._session.project, rf).subscribe({
16838
+ this.audioFetchSubscription = this.recFileService.fetchRecordingFileIndDbAudioBuffer(this._persistentAudioStorageTarget, this._session.project, rf).subscribe({
16737
16839
  next: (iab) => {
16738
16840
  //console.debug("Sessionmanager: Received inddb audio buffer: "+iab);
16739
16841
  nextIab = iab;
@@ -16776,7 +16878,7 @@ class AudioRecorder extends BasicRecorder {
16776
16878
  // Fetch chunked audio buffer from network
16777
16879
  let nextNetAb = null;
16778
16880
  //console.debug("Fetch chunked audio from network");
16779
- this.audioFetchSubscription = this.recFileService.fetchRecordingFileNetAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
16881
+ this.audioFetchSubscription = this.recFileService.fetchRecordingFileNetAudioBuffer(this._session.project, rf).subscribe({
16780
16882
  next: (netAb) => {
16781
16883
  //console.debug("Sessionmanager: Received net audio buffer: "+netAb);
16782
16884
  nextNetAb = netAb;
@@ -16821,7 +16923,7 @@ class AudioRecorder extends BasicRecorder {
16821
16923
  // Fetch chunked array audio buffer
16822
16924
  let nextAab = null;
16823
16925
  //console.debug("Fetch audio and store to (chunked) array buffer...");
16824
- this.audioFetchSubscription = this.recFileService.fetchRecordingFileArrayAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
16926
+ this.audioFetchSubscription = this.recFileService.fetchRecordingFileArrayAudioBuffer(this._session.project, rf).subscribe({
16825
16927
  next: (aab) => {
16826
16928
  nextAab = aab;
16827
16929
  },
@@ -16858,7 +16960,7 @@ class AudioRecorder extends BasicRecorder {
16858
16960
  });
16859
16961
  }
16860
16962
  else {
16861
- this.audioFetchSubscription = this.recFileService.fetchRecordingFileAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
16963
+ this.audioFetchSubscription = this.recFileService.fetchRecordingFileAudioBuffer(this._session.project, rf).subscribe({
16862
16964
  next: ab => {
16863
16965
  this.liveLevelDisplayState = State.READY;
16864
16966
  let fabDh = null;
@@ -16997,7 +17099,7 @@ class AudioRecorder extends BasicRecorder {
16997
17099
  this.transportActions.pauseAction.disabled = true;
16998
17100
  this.statusAlertType = 'info';
16999
17101
  this.statusMsg = 'Recorded.';
17000
- let ad = null;
17102
+ let ab = null;
17001
17103
  if (this.ac) {
17002
17104
  let adh = null;
17003
17105
  let as = null;
@@ -17029,7 +17131,7 @@ class AudioRecorder extends BasicRecorder {
17029
17131
  const sr = this.ac.currentSampleRate;
17030
17132
  const chFl = sr * RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
17031
17133
  //console.debug("stopped(): rfID: "+this._recordingFile?.recordingFileId+", net ab url: " + burl+", frames: "+this.ac.framesRecorded+", sample rate: "+sr);
17032
- let netAs = new NetAudioBuffer(this.ac.context, this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
17134
+ let netAs = new NetAudioBuffer(this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
17033
17135
  as = netAs;
17034
17136
  if (this.uploadSet) {
17035
17137
  this.uploadSet.onDone = (uploadSet) => {
@@ -17076,7 +17178,7 @@ class AudioRecorder extends BasicRecorder {
17076
17178
  const sr = this.ac.currentSampleRate;
17077
17179
  const chFl = sr * RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
17078
17180
  //console.debug("stopped(): rfID: "+this._recordingFile?.recordingFileId+", net ab url: " + burl+", frames: "+this.ac.framesRecorded+", sample rate: "+sr);
17079
- let netAs = new NetAudioBuffer(this.ac.context, this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
17181
+ let netAs = new NetAudioBuffer(this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
17080
17182
  as = netAs;
17081
17183
  if (this.uploadSet) {
17082
17184
  this.uploadSet.onDone = (uploadSet) => {
@@ -17095,7 +17197,7 @@ class AudioRecorder extends BasicRecorder {
17095
17197
  as = this.ac.audioBufferArray();
17096
17198
  }
17097
17199
  else {
17098
- let ab = this.ac.audioBuffer();
17200
+ ab = this.ac.audioBuffer();
17099
17201
  if (ab) {
17100
17202
  as = new AudioBufferSource(ab);
17101
17203
  }
@@ -17115,7 +17217,7 @@ class AudioRecorder extends BasicRecorder {
17115
17217
  RecordingFileUtils.setAudioData(rf, adh);
17116
17218
  this.recorderCombiPane.addRecFile(rf);
17117
17219
  // Upload if upload enabled and not in chunked upload mode
17118
- if (this.enableUploadRecordings && this._uploadChunkSizeSeconds === null && rf != null && ad != null) {
17220
+ if (this.enableUploadRecordings && this._uploadChunkSizeSeconds === null && AudioStorageType.MEM_ENTIRE === this._clientAudioStorageType && rf != null && ab != null) {
17119
17221
  let apiEndPoint = '';
17120
17222
  if (this.config && this.config.apiEndPoint) {
17121
17223
  apiEndPoint = this.config.apiEndPoint;
@@ -17130,7 +17232,7 @@ class AudioRecorder extends BasicRecorder {
17130
17232
  // TODO duplicate conversion for manual download
17131
17233
  this.processingRecording = true;
17132
17234
  let ww = new WavWriter();
17133
- ww.writeAsync(ad, (wavFile) => {
17235
+ ww.writeAsync(ab, (wavFile) => {
17134
17236
  this.postRecordingMultipart(wavFile, recUrl, rf);
17135
17237
  this.processingRecording = false;
17136
17238
  this.updateWakeLock();
@@ -17214,7 +17316,7 @@ class AudioRecorder extends BasicRecorder {
17214
17316
  }
17215
17317
  }
17216
17318
  }
17217
- AudioRecorder.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioRecorder, deps: [{ token: i1$3.BreakpointObserver }, { token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i1$2.ActivatedRoute }, { token: i1$4.MatDialog }, { token: SessionService }, { token: RecordingService }, { token: SpeechRecorderUploader }, { token: SPEECHRECORDER_CONFIG }], target: i0.ɵɵFactoryTarget.Component });
17319
+ AudioRecorder.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioRecorder, deps: [{ token: i1$2.BreakpointObserver }, { token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i1$3.MatDialog }, { token: SessionService }, { token: RecordingService }, { token: SpeechRecorderUploader }, { token: SPEECHRECORDER_CONFIG }], target: i0.ɵɵFactoryTarget.Component });
17218
17320
  AudioRecorder.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: AudioRecorder, selector: "app-audiorecorder", inputs: { projectName: "projectName", dataSaved: "dataSaved" }, host: { listeners: { "window:keypress": "onKeyPress($event)", "window:keydown": "onKeyDown($event)" } }, providers: [SessionService], viewQueries: [{ propertyName: "recorderCombiPane", first: true, predicate: RecorderCombiPane, descendants: true, static: true }, { propertyName: "liveLevelDisplay", first: true, predicate: LevelBar, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
17219
17321
  <app-warningbar [show]="isTestSession()" warningText="Test recording only!"></app-warningbar>
17220
17322
  <app-warningbar [show]="isDefaultAudioTestSession()"
@@ -17335,7 +17437,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
17335
17437
  </div>
17336
17438
  </div>
17337
17439
  `, styles: [":host{flex:2;background:lightgrey;display:flex;flex-direction:column;margin:0;padding:0;height:100%;min-height:0px;overflow:hidden}\n", ".ricontrols{padding:4px;box-sizing:border-box;height:100%}\n", ".dark{background:darkgray}\n", ".controlpanel{display:flex;flex-direction:row;align-content:center;align-items:center;margin:0;padding:20px;min-height:min-content}\n", ".startstop{width:100%;flex:1 0 30%;align-items:center;text-align:center;align-content:center}\n", ".startstopscreenxs{width:100%;flex:1 0 100%;align-items:center;text-align:center;align-content:center}\n", ".bigbutton{min-width:70px;min-height:50px;font-size:50px;border-radius:20px}\n", ".audioStatusDisplay{display:flex;flex-direction:row;height:100px;min-height:100px}\n", ".audioStatusDisplayXs{display:flex;flex-direction:column;height:125px;min-height:125px}\n"] }]
17338
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i1$2.ActivatedRoute }, { type: i1$4.MatDialog }, { type: SessionService }, { type: RecordingService }, { type: SpeechRecorderUploader }, { type: SpeechRecorderConfig, decorators: [{
17440
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i1$3.MatDialog }, { type: SessionService }, { type: RecordingService }, { type: SpeechRecorderUploader }, { type: SpeechRecorderConfig, decorators: [{
17339
17441
  type: Inject,
17340
17442
  args: [SPEECHRECORDER_CONFIG]
17341
17443
  }] }]; }, propDecorators: { projectName: [{
@@ -17366,11 +17468,7 @@ class AudioRecorderComponent extends RecorderComponent {
17366
17468
  this.uploader = uploader;
17367
17469
  }
17368
17470
  ngOnInit() {
17369
- //super.ngOnInit();
17370
- let audioContext = AudioContextProvider.audioContextInstance();
17371
- if (audioContext) {
17372
- this.controlAudioPlayer = new AudioPlayer(audioContext, this.ar);
17373
- }
17471
+ this.controlAudioPlayer = new AudioPlayer(this.ar);
17374
17472
  this.ar.controlAudioPlayer = this.controlAudioPlayer;
17375
17473
  //TODO Duplicate code in SpeechRecorderComponent
17376
17474
  window.addEventListener('beforeunload', (e) => {
@@ -17380,7 +17478,7 @@ class AudioRecorderComponent extends RecorderComponent {
17380
17478
  }
17381
17479
  else {
17382
17480
  // all this attempts to customize the message do not work anymore (for security reasons)!!
17383
- var message = "Please do not leave the page, until all recordings are uploaded!";
17481
+ const message = "Please do not leave the page, until all recordings are uploaded!";
17384
17482
  alert(message);
17385
17483
  e = e || window.event;
17386
17484
  if (e) {
@@ -17480,7 +17578,7 @@ class AudioRecorderComponent extends RecorderComponent {
17480
17578
  return this.dataSaved && !this.ar.isActive();
17481
17579
  }
17482
17580
  }
17483
- AudioRecorderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioRecorderComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1$2.Router }, { token: i0.ChangeDetectorRef }, { token: SessionService }, { token: ProjectService }, { token: SpeechRecorderUploader }], target: i0.ɵɵFactoryTarget.Component });
17581
+ AudioRecorderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioRecorderComponent, deps: [{ token: i4$2.ActivatedRoute }, { token: i4$2.Router }, { token: i0.ChangeDetectorRef }, { token: SessionService }, { token: ProjectService }, { token: SpeechRecorderUploader }], target: i0.ɵɵFactoryTarget.Component });
17484
17582
  AudioRecorderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: AudioRecorderComponent, selector: "app-audiorecorder-comp", providers: [SessionService], viewQueries: [{ propertyName: "ar", first: true, predicate: AudioRecorder, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
17485
17583
  <app-audiorecorder [projectName]="_project?.name" [dataSaved]="dataSaved"></app-audiorecorder>
17486
17584
  `, isInline: true, styles: [":host{flex:2;display:flex;height:100%;flex-direction:column;min-height:0}\n"], dependencies: [{ kind: "component", type: AudioRecorder, selector: "app-audiorecorder", inputs: ["projectName", "dataSaved"] }] });
@@ -17489,7 +17587,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
17489
17587
  args: [{ selector: 'app-audiorecorder-comp', providers: [SessionService], template: `
17490
17588
  <app-audiorecorder [projectName]="_project?.name" [dataSaved]="dataSaved"></app-audiorecorder>
17491
17589
  `, styles: [":host{flex:2;display:flex;height:100%;flex-direction:column;min-height:0}\n"] }]
17492
- }], ctorParameters: function () { return [{ type: i1$2.ActivatedRoute }, { type: i1$2.Router }, { type: i0.ChangeDetectorRef }, { type: SessionService }, { type: ProjectService }, { type: SpeechRecorderUploader }]; }, propDecorators: { ar: [{
17590
+ }], ctorParameters: function () { return [{ type: i4$2.ActivatedRoute }, { type: i4$2.Router }, { type: i0.ChangeDetectorRef }, { type: SessionService }, { type: ProjectService }, { type: SpeechRecorderUploader }]; }, propDecorators: { ar: [{
17493
17591
  type: ViewChild,
17494
17592
  args: [AudioRecorder, { static: true }]
17495
17593
  }] } });
@@ -17525,7 +17623,7 @@ class SpeechrecorderngModule {
17525
17623
  }
17526
17624
  SpeechrecorderngModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SpeechrecorderngModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
17527
17625
  SpeechrecorderngModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.12", ngImport: i0, type: SpeechrecorderngModule, declarations: [AudioSignal, Sonagram, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, Progress, SimpleTrafficLight, Recinstructions, Prompter, PromptContainer, PromptingContainer, Prompting, StatusDisplay,
17528
- ProgressDisplay, RecordingItemDisplay, RecordingItemControls, UploadStatus, TransportPanel, WakeLockIndicator, ReadyStateIndicator, ControlPanel, WarningBar, AudioRecorder, SessionManager, MessageDialog, SessionFinishedDialog, SpeechrecorderngComponent, AudioRecorderComponent, RecordingFileViewComponent, RecordingFileUI, ScrollIntoViewDirective, RecordingFileNaviComponent, RecordingFileMetaComponent, RecordingList, RecorderCombiPane, AudioRecorder], imports: [i1$2.RouterModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule, MatMenuModule], exports: [MessageDialog, SpeechrecorderngComponent, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, AudioRecorder] });
17626
+ ProgressDisplay, RecordingItemDisplay, RecordingItemControls, UploadStatus, TransportPanel, WakeLockIndicator, ReadyStateIndicator, ControlPanel, WarningBar, AudioRecorder, SessionManager, MessageDialog, SessionFinishedDialog, SpeechrecorderngComponent, AudioRecorderComponent, RecordingFileViewComponent, RecordingFileUI, ScrollIntoViewDirective, RecordingFileNaviComponent, RecordingFileMetaComponent, RecordingList, RecorderCombiPane, AudioRecorder], imports: [i4$2.RouterModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule, MatMenuModule], exports: [MessageDialog, SpeechrecorderngComponent, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, AudioRecorder] });
17529
17627
  SpeechrecorderngModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SpeechrecorderngModule, providers: [SessionService, ProjectService, ScriptService, RecordingService, RecordingFileService, SpeechRecorderUploader], imports: [RouterModule.forChild(SPR_ROUTES), CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule, MatMenuModule] });
17530
17628
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SpeechrecorderngModule, decorators: [{
17531
17629
  type: NgModule,
@@ -17538,7 +17636,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
17538
17636
  }]
17539
17637
  }] });
17540
17638
 
17541
- const VERSION = '3.4.4';
17639
+ const VERSION = '3.6.0';
17542
17640
 
17543
17641
  /*
17544
17642
  * Public API Surface of speechrecorderng