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
  }
@@ -947,7 +947,7 @@ class ArrayAudioBufferSourceNode extends AudioSourceNode {
947
947
  }
948
948
  };
949
949
  }
950
- fillBuffer(frameOffset) {
950
+ fillBuffer() {
951
951
  if (this._arrayAudioBuffer && this._audioInputStream && this._aisBufs) {
952
952
  let filled = this.filledFrames;
953
953
  let bufLen = 0;
@@ -1746,7 +1746,7 @@ const aswpStr = "\n" +
1746
1746
  "\n" +
1747
1747
  " let copied=0;\n" +
1748
1748
  " do{\n" +
1749
- " if(this.currentAudioBufferAvail==0){\n" +
1749
+ " if(this.currentAudioBufferAvail===0){\n" +
1750
1750
  " let nxtBuff=this.audioBuffers.shift();\n" +
1751
1751
  " if(nxtBuff){\n" +
1752
1752
  " this.currentAudioBuffer=nxtBuff;\n" +
@@ -1982,9 +1982,8 @@ class IndexedDbAudioBufferSourceNode extends AudioSourceNode {
1982
1982
  }
1983
1983
 
1984
1984
  class NetAudioBuffer extends BasicAudioSource {
1985
- constructor(_audioContext, _recFileService, _baseUrl, _channelCount, _sampleRate, _chunkFrameLen, _frameLen, _uuid = null, _orgFetchChunkFrameLen = _chunkFrameLen) {
1985
+ constructor(_recFileService, _baseUrl, _channelCount, _sampleRate, _chunkFrameLen, _frameLen, _uuid = null, _orgFetchChunkFrameLen = _chunkFrameLen) {
1986
1986
  super();
1987
- this._audioContext = _audioContext;
1988
1987
  this._recFileService = _recFileService;
1989
1988
  this._baseUrl = _baseUrl;
1990
1989
  this._channelCount = _channelCount;
@@ -2002,9 +2001,6 @@ class NetAudioBuffer extends BasicAudioSource {
2002
2001
  get recFileService() {
2003
2002
  return this._recFileService;
2004
2003
  }
2005
- get audioContext() {
2006
- return this._audioContext;
2007
- }
2008
2004
  get baseUrl() {
2009
2005
  return this._baseUrl;
2010
2006
  }
@@ -2042,8 +2038,8 @@ class NetAudioBuffer extends BasicAudioSource {
2042
2038
  toString() {
2043
2039
  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();
2044
2040
  }
2045
- static fromChunkAudioBuffer(aCtx, recordingsService, baseUrl, ab, frameLen, orgFetchChunkFrameLen = ab.length) {
2046
- let nab = new NetAudioBuffer(aCtx, recordingsService, baseUrl, ab.numberOfChannels, ab.sampleRate, ab.length, frameLen, null, orgFetchChunkFrameLen);
2041
+ static fromChunkAudioBuffer(recordingsService, baseUrl, ab, frameLen, orgFetchChunkFrameLen = ab.length) {
2042
+ let nab = new NetAudioBuffer(recordingsService, baseUrl, ab.numberOfChannels, ab.sampleRate, ab.length, frameLen, null, orgFetchChunkFrameLen);
2047
2043
  nab.ready();
2048
2044
  return nab;
2049
2045
  }
@@ -2086,7 +2082,7 @@ class NetRandomAccessAudioStream {
2086
2082
  }
2087
2083
  chunk(baseUrl, ci, cb, errCb) {
2088
2084
  let startFrame = ci * this._netAb.orgFetchChunkFrameLen;
2089
- this._netAb.recFileService.chunkAudioRequest(this._netAb.audioContext, baseUrl, startFrame, this._netAb.orgFetchChunkFrameLen).subscribe({
2085
+ this._netAb.recFileService.chunkAudioRequest(baseUrl, startFrame, this._netAb.orgFetchChunkFrameLen).subscribe({
2090
2086
  next: (chDl) => {
2091
2087
  if (chDl) {
2092
2088
  const ab = chDl.decodedAudioBuffer;
@@ -2493,6 +2489,87 @@ class NetAudioBufferSourceNode extends AudioSourceNode {
2493
2489
  }
2494
2490
  }
2495
2491
 
2492
+ class AudioContextProvider {
2493
+ static audioContextInstance() {
2494
+ var _a;
2495
+ if (!this._audioContext) {
2496
+ let debugFail = false;
2497
+ if (!window.AudioContext || typeof window.AudioContext !== 'function' || debugFail) {
2498
+ this._audioContext = null;
2499
+ throw new Error('Browser does not support Web Audio API!');
2500
+ }
2501
+ else {
2502
+ console.debug("Get new audio context...");
2503
+ this._audioContext = new window.AudioContext();
2504
+ console.debug("Created new audio context.");
2505
+ this._audioContext.addEventListener('statechange', () => {
2506
+ var _a;
2507
+ console.debug("Audio context state changed: " + ((_a = this._audioContext) === null || _a === void 0 ? void 0 : _a.state));
2508
+ });
2509
+ console.debug("Created new audio context with state: " + ((_a = this._audioContext) === null || _a === void 0 ? void 0 : _a.state));
2510
+ }
2511
+ }
2512
+ return this._audioContext;
2513
+ }
2514
+ // public static audioContextInstanceRunning(audioContext?:AudioContext):Promise<AudioContext>{
2515
+ //
2516
+ // return new Promise<AudioContext>((resolve,reject)=>{
2517
+ // let aCtx=audioContext?audioContext:AudioContextProvider.audioContextInstance();
2518
+ // if(aCtx) {
2519
+ // if(aCtx.state==='closed') {
2520
+ // reject(new Error('Audio context already closed.'));
2521
+ // }else if(aCtx.state==='running') {
2522
+ // resolve(aCtx);
2523
+ // }else{
2524
+ // aCtx.resume().then(() => {
2525
+ // if(aCtx) {
2526
+ // resolve(aCtx);
2527
+ // }else{
2528
+ // reject(new Error('Could not get audio context'));
2529
+ // }
2530
+ // }).catch(() => {
2531
+ // reject(new Error('Could not resume audio context'));
2532
+ // })
2533
+ // }
2534
+ // }else{
2535
+ // reject(new Error('Could not get audio context from browser'));
2536
+ // }
2537
+ // });
2538
+ // }
2539
+ // public static decodeAudioData(data:ArrayBuffer,audioContext?:AudioContext):Promise<AudioBuffer>{
2540
+ // return new Promise<AudioBuffer>((resolve,reject)=>{
2541
+ // // decodeAudioData requires an audio context in running state
2542
+ // AudioContextProvider.audioContextInstanceRunning(audioContext).then(
2543
+ // (aCtx)=>{
2544
+ // // Do not use Promise version, which does not work with Safari 13
2545
+ // aCtx.decodeAudioData(data,decodedData => {
2546
+ // resolve(decodedData);
2547
+ // },(reason) => {
2548
+ // reject(reason);
2549
+ // });
2550
+ // }
2551
+ // ).catch((reason)=>{
2552
+ // reject(reason);
2553
+ // })
2554
+ // })
2555
+ // }
2556
+ static decodeAudioData(data) {
2557
+ return new Promise((resolve, reject) => {
2558
+ if (!this._offlineAudioContext) {
2559
+ this._offlineAudioContext = new OfflineAudioContext(1, 44100, 44100);
2560
+ }
2561
+ // Do not use Promise version, which does not work with Safari 13
2562
+ this._offlineAudioContext.decodeAudioData(data, decodedData => {
2563
+ resolve(decodedData);
2564
+ }, (reason) => {
2565
+ reject(reason);
2566
+ });
2567
+ });
2568
+ }
2569
+ }
2570
+ AudioContextProvider._audioContext = null;
2571
+ AudioContextProvider._offlineAudioContext = null;
2572
+
2496
2573
  var EventType;
2497
2574
  (function (EventType) {
2498
2575
  EventType[EventType["CLOSED"] = 0] = "CLOSED";
@@ -2516,8 +2593,9 @@ class AudioPlayerEvent {
2516
2593
  }
2517
2594
  }
2518
2595
  class AudioPlayer {
2519
- constructor(context, listener) {
2596
+ constructor(listener) {
2520
2597
  this.running = false;
2598
+ this.context = null;
2521
2599
  this.ready = false;
2522
2600
  this._audioClip = null;
2523
2601
  this._audioSource = null;
@@ -2525,7 +2603,6 @@ class AudioPlayer {
2525
2603
  this.sourceAudioWorkletNode = null;
2526
2604
  this.playStartTime = null;
2527
2605
  this.timerVar = null;
2528
- this.context = context;
2529
2606
  this.listener = listener;
2530
2607
  this.bufSize = AudioPlayer.DEFAULT_BUFSIZE;
2531
2608
  this.n = navigator;
@@ -2542,15 +2619,23 @@ class AudioPlayer {
2542
2619
  this._stopAction = new Action('Stop');
2543
2620
  this._stopAction.disabled = true;
2544
2621
  this._stopAction.onAction = () => this.stop();
2545
- this.context.addEventListener('statechange', (ev) => {
2546
- if (this.context.state !== 'running') {
2547
- this.stop();
2548
- }
2549
- });
2550
2622
  }
2551
2623
  get autoPlayOnSelectToggleAction() {
2552
2624
  return this._autoPlayOnSelectToggleAction;
2553
2625
  }
2626
+ _audioContext() {
2627
+ if (!this.context) {
2628
+ this.context = AudioContextProvider.audioContextInstance();
2629
+ if (this.context) {
2630
+ this.context.addEventListener('statechange', (ev) => {
2631
+ if (this.context && this.context.state !== 'running') {
2632
+ this.stop();
2633
+ }
2634
+ });
2635
+ }
2636
+ }
2637
+ return this.context;
2638
+ }
2554
2639
  get startAction() {
2555
2640
  return this._startAction;
2556
2641
  }
@@ -2569,9 +2654,9 @@ class AudioPlayer {
2569
2654
  chs = audioDataHolder.numberOfChannels;
2570
2655
  if (chs > 0) {
2571
2656
  length = audioDataHolder.frameLen;
2572
- if (chs > this.context.destination.maxChannelCount) {
2573
- // TODO exception
2574
- }
2657
+ //if (chs > this.context.destination.maxChannelCount) {
2658
+ // // TODO exception
2659
+ //}
2575
2660
  }
2576
2661
  this.audioSource = audioDataHolder.audioSource;
2577
2662
  audioClip.addSelectionObserver((ac) => {
@@ -2591,16 +2676,11 @@ class AudioPlayer {
2591
2676
  set audioSource(value) {
2592
2677
  this.stop();
2593
2678
  this._audioSource = value;
2594
- if (this._audioSource && this.context) {
2595
- if (this._audioSource instanceof AudioBufferSource) {
2596
- this.ready = true;
2597
- this.updateStartActions();
2598
- if (this.listener) {
2599
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
2600
- }
2601
- }
2602
- else {
2603
- this._loadSourceWorkletAndInitStart();
2679
+ if (this._audioSource) {
2680
+ this.ready = true;
2681
+ this.updateStartActions();
2682
+ if (this.listener) {
2683
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
2604
2684
  }
2605
2685
  }
2606
2686
  else {
@@ -2612,24 +2692,27 @@ class AudioPlayer {
2612
2692
  }
2613
2693
  }
2614
2694
  _loadSourceWorkletAndInitStart() {
2615
- AudioSourceWorkletModuleLoader.loadModule(this.context).then(() => {
2616
- //console.debug("Player ready. ( by Player::_loadSourceWorkletAndInitStart()");
2617
- this.ready = true;
2618
- this.updateStartActions();
2619
- if (this.listener) {
2620
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
2621
- }
2622
- }).catch((error) => {
2623
- this.ready = false;
2624
- this.updateStartActions();
2625
- if (this.listener) {
2626
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
2627
- }
2628
- console.error('Could not add module ' + error);
2629
- });
2695
+ if (this.context) {
2696
+ AudioSourceWorkletModuleLoader.loadModule(this.context).then(() => {
2697
+ //console.debug("Player ready. ( by Player::_loadSourceWorkletAndInitStart()");
2698
+ this.ready = true;
2699
+ this.updateStartActions();
2700
+ if (this.listener) {
2701
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
2702
+ }
2703
+ }).catch((error) => {
2704
+ this.ready = false;
2705
+ this.updateStartActions();
2706
+ if (this.listener) {
2707
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
2708
+ }
2709
+ console.error('Could not add module ' + error);
2710
+ });
2711
+ }
2630
2712
  }
2631
2713
  _startAudioSourceWorkletNode() {
2632
- if (this.sourceAudioWorkletNode) {
2714
+ this._loadSourceWorkletAndInitStart();
2715
+ if (this.context && this.sourceAudioWorkletNode) {
2633
2716
  this.sourceAudioWorkletNode.onprocessorerror = (ev) => {
2634
2717
  let msg = 'Unknwon error';
2635
2718
  if (ev instanceof ErrorEvent) {
@@ -2656,16 +2739,25 @@ class AudioPlayer {
2656
2739
  }
2657
2740
  }
2658
2741
  start() {
2659
- if (!this._startAction.disabled && !this.running) {
2660
- if (this.context.state !== 'running') {
2661
- this.context.resume().then(() => {
2742
+ this._audioContext();
2743
+ if (this.context) {
2744
+ if (!this._startAction.disabled && !this.running) {
2745
+ if (this.context.state === 'suspended') {
2746
+ this.context.resume().then(() => {
2747
+ this._start();
2748
+ }).catch((reason) => {
2749
+ console.error(reason.message());
2750
+ throw reason;
2751
+ });
2752
+ }
2753
+ else if (this.context.state === 'closed') {
2754
+ const msg = 'Error: Cannot start playback. Audio context is already closed!';
2755
+ console.error(msg);
2756
+ throw new Error(msg);
2757
+ }
2758
+ else {
2662
2759
  this._start();
2663
- }).catch((reason) => {
2664
- console.error('Could not resume audio context: ' + reason);
2665
- });
2666
- }
2667
- else {
2668
- this._start();
2760
+ }
2669
2761
  }
2670
2762
  }
2671
2763
  }
@@ -2690,9 +2782,12 @@ class AudioPlayer {
2690
2782
  }
2691
2783
  }
2692
2784
  startSelectionDisabled() {
2693
- return !(this._audioClip && this.context && !this.startAction.disabled && this._audioClip.selection);
2785
+ return !(this._audioClip && !this.startAction.disabled && this._audioClip.selection);
2694
2786
  }
2695
2787
  _start(playSelection = false) {
2788
+ if (!this.context) {
2789
+ throw new Error("Could not get audio context!");
2790
+ }
2696
2791
  if (this._audioSource instanceof AudioBufferSource) {
2697
2792
  this.sourceBufferNode = this.context.createBufferSource();
2698
2793
  this.sourceBufferNode.buffer = this._audioSource.audioBuffer;
@@ -2723,68 +2818,90 @@ class AudioPlayer {
2723
2818
  }
2724
2819
  }
2725
2820
  else if (this._audioSource instanceof ArrayAudioBuffer || this._audioSource instanceof IndexedDbAudioBuffer || this._audioSource instanceof NetAudioBuffer) {
2726
- this.playStartTime = null;
2727
- if (this._audioSource instanceof ArrayAudioBuffer) {
2728
- const aabsn = new ArrayAudioBufferSourceNode(this.context);
2729
- aabsn.arrayAudioBuffer = this._audioSource;
2730
- this.sourceAudioWorkletNode = aabsn;
2731
- }
2732
- else if (this._audioSource instanceof IndexedDbAudioBuffer) {
2733
- const iasn = new IndexedDbAudioBufferSourceNode(this.context);
2734
- iasn.inddbAudioBuffer = this._audioSource;
2735
- this.sourceAudioWorkletNode = iasn;
2736
- }
2737
- else if (this._audioSource instanceof NetAudioBuffer) {
2738
- const nabsn = new NetAudioBufferSourceNode(this.context);
2739
- nabsn.netAudioBuffer = this._audioSource;
2740
- this.sourceAudioWorkletNode = nabsn;
2741
- }
2742
- if (this.sourceAudioWorkletNode) {
2743
- this.sourceAudioWorkletNode.onprocessorerror = (ev) => {
2744
- let msg = 'Unknwon error';
2745
- if (ev instanceof ErrorEvent) {
2746
- msg = ev.message;
2821
+ AudioSourceWorkletModuleLoader.loadModule(this.context).then(() => {
2822
+ this.playStartTime = null;
2823
+ if (this.context) {
2824
+ if (this._audioSource instanceof ArrayAudioBuffer) {
2825
+ const aabsn = new ArrayAudioBufferSourceNode(this.context);
2826
+ aabsn.arrayAudioBuffer = this._audioSource;
2827
+ this.sourceAudioWorkletNode = aabsn;
2747
2828
  }
2748
- console.error("Audio source worklet error: " + msg);
2749
- if (this.listener) {
2750
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.ERROR));
2829
+ else if (this._audioSource instanceof IndexedDbAudioBuffer) {
2830
+ const iasn = new IndexedDbAudioBufferSourceNode(this.context);
2831
+ iasn.inddbAudioBuffer = this._audioSource;
2832
+ this.sourceAudioWorkletNode = iasn;
2833
+ }
2834
+ else if (this._audioSource instanceof NetAudioBuffer) {
2835
+ const nabsn = new NetAudioBufferSourceNode(this.context);
2836
+ nabsn.netAudioBuffer = this._audioSource;
2837
+ this.sourceAudioWorkletNode = nabsn;
2838
+ }
2839
+ if (this.sourceAudioWorkletNode) {
2840
+ this.sourceAudioWorkletNode.onprocessorerror = (ev) => {
2841
+ let msg = 'Unknwon error';
2842
+ if (ev instanceof ErrorEvent) {
2843
+ msg = ev.message;
2844
+ }
2845
+ console.error("Audio source worklet error: " + msg);
2846
+ if (this.listener) {
2847
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.ERROR));
2848
+ }
2849
+ };
2850
+ this.sourceAudioWorkletNode.connect(this.context.destination); // this already starts playing
2851
+ this.sourceAudioWorkletNode.onended = () => this.onended();
2852
+ this.running = true;
2853
+ const ac = this._audioClip;
2854
+ let offset = 0;
2855
+ if (playSelection && ac && ac.selection) {
2856
+ const s = ac.selection;
2857
+ const sr = ac.audioDataHolder.sampleRate;
2858
+ offset = s.leftFrame / sr;
2859
+ const stopPosInsecs = s.rightFrame / sr;
2860
+ const dur = stopPosInsecs - offset;
2861
+ this.sourceAudioWorkletNode.start(0, offset, dur);
2862
+ }
2863
+ else {
2864
+ this.sourceAudioWorkletNode.start();
2865
+ }
2866
+ //this.playStartTime = this.context.currentTime - offset;
2867
+ this._startAction.disabled = true;
2868
+ this._startSelectionAction.disabled = true;
2869
+ this._stopAction.disabled = false;
2870
+ if (this.listener) {
2871
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
2872
+ }
2751
2873
  }
2752
- };
2753
- this.sourceAudioWorkletNode.connect(this.context.destination); // this already starts playing
2754
- this.sourceAudioWorkletNode.onended = () => this.onended();
2755
- this.running = true;
2756
- const ac = this._audioClip;
2757
- let offset = 0;
2758
- if (playSelection && ac && ac.selection) {
2759
- const s = ac.selection;
2760
- const sr = ac.audioDataHolder.sampleRate;
2761
- offset = s.leftFrame / sr;
2762
- const stopPosInsecs = s.rightFrame / sr;
2763
- const dur = stopPosInsecs - offset;
2764
- this.sourceAudioWorkletNode.start(0, offset, dur);
2765
- }
2766
- else {
2767
- this.sourceAudioWorkletNode.start();
2768
2874
  }
2769
- //this.playStartTime = this.context.currentTime - offset;
2770
- this._startAction.disabled = true;
2771
- this._startSelectionAction.disabled = true;
2772
- this._stopAction.disabled = false;
2875
+ }).catch((error) => {
2876
+ console.error(error.message);
2877
+ this.ready = false;
2878
+ this.updateStartActions();
2773
2879
  if (this.listener) {
2774
- this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
2880
+ this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
2775
2881
  }
2776
- }
2882
+ throw error;
2883
+ });
2777
2884
  }
2778
2885
  }
2779
2886
  startSelected() {
2887
+ this._audioContext();
2888
+ if (!this.context) {
2889
+ throw new Error("Could not get audio context!");
2890
+ }
2780
2891
  if (!this._startAction.disabled && !this.running) {
2781
- if (this.context.state !== 'running') {
2892
+ if (this.context.state === 'suspended') {
2782
2893
  this.context.resume().then(() => {
2783
2894
  this._start(true);
2784
2895
  }).catch((reason) => {
2785
- console.error('Could not resume audio context: ' + reason);
2896
+ console.error(reason.message);
2897
+ throw reason;
2786
2898
  });
2787
2899
  }
2900
+ else if (this.context.state === 'closed') {
2901
+ const msg = 'Error: Cannot start playback of selection. Audio context is already closed!';
2902
+ console.error(msg);
2903
+ throw new Error(msg);
2904
+ }
2788
2905
  else {
2789
2906
  this._start(true);
2790
2907
  }
@@ -2821,7 +2938,7 @@ class AudioPlayer {
2821
2938
  }
2822
2939
  get playPositionTime() {
2823
2940
  let ppt = null;
2824
- if (this.playStartTime !== null) {
2941
+ if (this.context && this.playStartTime !== null) {
2825
2942
  ppt = this.context.currentTime - this.playStartTime;
2826
2943
  }
2827
2944
  else if (this.sourceAudioWorkletNode) {
@@ -3163,8 +3280,10 @@ const awpStr = "class AudioCaptureInterceptorProcessor extends AudioWorkletProce
3163
3280
  "\n" +
3164
3281
  "registerProcessor('capture-interceptor',AudioCaptureInterceptorProcessor);\n";
3165
3282
  class AudioCapture {
3166
- constructor(context) {
3283
+ //private context:AudioContext|null=null;
3284
+ constructor() {
3167
3285
  this._maxAutoNetMemStoreSamples = AudioCapture.DEFAULT_MAX_NET_AUTO_MEM_STORE_SAMPLES;
3286
+ this.context = null;
3168
3287
  this._recUUID = null;
3169
3288
  this.agcStatus = null;
3170
3289
  this.bufferingNode = null;
@@ -3179,13 +3298,7 @@ class AudioCapture {
3179
3298
  this.persisted = true;
3180
3299
  this.persistError = null;
3181
3300
  this.inddbAudioBuffer = null;
3182
- this.context = context;
3183
3301
  this.n = navigator;
3184
- this.context.addEventListener('statechange', (ev) => {
3185
- if (this.context.state !== 'running') {
3186
- this.close();
3187
- }
3188
- });
3189
3302
  }
3190
3303
  get maxAutoNetMemStoreSamples() {
3191
3304
  return this._maxAutoNetMemStoreSamples;
@@ -3214,6 +3327,19 @@ class AudioCapture {
3214
3327
  get opened() {
3215
3328
  return this._opened;
3216
3329
  }
3330
+ _audioContext() {
3331
+ if (!this.context) {
3332
+ this.context = AudioContextProvider.audioContextInstance();
3333
+ if (this.context) {
3334
+ this.context.addEventListener('statechange', () => {
3335
+ if (this.context && this.context.state !== 'running') {
3336
+ this.close();
3337
+ }
3338
+ });
3339
+ }
3340
+ }
3341
+ return this.context;
3342
+ }
3217
3343
  initData() {
3218
3344
  if (!this._recUUID) {
3219
3345
  this._recUUID = UUID.generate();
@@ -3328,119 +3454,137 @@ class AudioCapture {
3328
3454
  }
3329
3455
  }
3330
3456
  addCaptureInterceptor() {
3331
- const awn = new AudioWorkletNode(this.context, 'capture-interceptor');
3332
- awn.onprocessorerror = (ev) => {
3333
- let msg = 'Unknwon error';
3334
- if (ev instanceof ErrorEvent) {
3335
- msg = ev.message;
3336
- }
3337
- console.error("Capture audio worklet error: " + msg);
3338
- if (this.listener) {
3339
- this.listener.error(msg);
3340
- }
3341
- };
3342
- let awnPt = awn.port;
3343
- if (awnPt) {
3344
- awnPt.onmessage = (ev) => {
3345
- if (this.capturing) {
3346
- let dt = ev.data;
3347
- let chs = dt.chs;
3348
- let adaLen = dt.data.length;
3349
- if (DEBUG_TRACE_LEVEL > 8) {
3350
- console.debug('Received data from worklet: ' + chs + ' ' + dt.len + ' Data chs: ' + adaLen);
3351
- }
3352
- let chunk = new Array(chs);
3353
- const samples = this.framesRecorded * chs;
3354
- if ((AudioStorageType.MEM_ENTIRE_AUTO_NET_CHUNKED === this.audioStorageType || AudioStorageType.MEM_CHUNKED_AUTO_NET_CHUNKED === this.audioStorageType) && this.data && samples > this._maxAutoNetMemStoreSamples) {
3355
- this.data = null;
3356
- }
3357
- //console.debug("Data initialized: "+(this.data!=null));
3358
- for (let ch = 0; ch < chs; ch++) {
3359
- //console.debug("Data ch initialized: "+(this.data !=null && this.data[ch] !=null));
3360
- if (ch < this.channelCount) {
3361
- if (dt.data[ch]) {
3362
- let fa = new Float32Array(dt.data[ch]);
3363
- if (this.data && this.data[ch]) {
3364
- this.data[ch].push(fa);
3365
- }
3366
- chunk[ch] = fa;
3367
- // Use samples of channel 0 to count frames (samples)
3368
- if (ch == 0) {
3369
- this.framesRecorded += fa.length;
3370
- }
3371
- }
3457
+ if (this.context) {
3458
+ const awn = new AudioWorkletNode(this.context, 'capture-interceptor');
3459
+ awn.onprocessorerror = (ev) => {
3460
+ let msg = 'Unknwon error';
3461
+ if (ev instanceof ErrorEvent) {
3462
+ msg = ev.message;
3463
+ }
3464
+ console.error("Capture audio worklet error: " + msg);
3465
+ if (this.listener) {
3466
+ this.listener.error(msg);
3467
+ }
3468
+ };
3469
+ let awnPt = awn.port;
3470
+ if (awnPt) {
3471
+ awnPt.onmessage = (ev) => {
3472
+ if (this.capturing) {
3473
+ let dt = ev.data;
3474
+ let chs = dt.chs;
3475
+ let adaLen = dt.data.length;
3476
+ if (DEBUG_TRACE_LEVEL > 8) {
3477
+ console.debug('Received data from worklet: ' + chs + ' ' + dt.len + ' Data chs: ' + adaLen);
3372
3478
  }
3373
- }
3374
- if (this.audioOutStream) {
3375
- try {
3376
- this.audioOutStream.write(chunk);
3377
- // // Random test error:
3378
- // if(Math.random()>0.98) {
3379
- // throw new Error('Test');
3380
- // }
3479
+ let chunk = new Array(chs);
3480
+ const samples = this.framesRecorded * chs;
3481
+ if ((AudioStorageType.MEM_ENTIRE_AUTO_NET_CHUNKED === this.audioStorageType || AudioStorageType.MEM_CHUNKED_AUTO_NET_CHUNKED === this.audioStorageType) && this.data && samples > this._maxAutoNetMemStoreSamples) {
3482
+ this.data = null;
3381
3483
  }
3382
- catch (err) {
3383
- if (err instanceof Error) {
3384
- this.persistError = err;
3385
- }
3386
- else {
3387
- this.persistError = new Error('Error handling recorded audio data');
3484
+ //console.debug("Data initialized: "+(this.data!=null));
3485
+ for (let ch = 0; ch < chs; ch++) {
3486
+ //console.debug("Data ch initialized: "+(this.data !=null && this.data[ch] !=null));
3487
+ if (ch < this.channelCount) {
3488
+ if (dt.data[ch]) {
3489
+ let fa = new Float32Array(dt.data[ch]);
3490
+ if (this.data && this.data[ch]) {
3491
+ this.data[ch].push(fa);
3492
+ }
3493
+ chunk[ch] = fa;
3494
+ // Use samples of channel 0 to count frames (samples)
3495
+ if (ch == 0) {
3496
+ this.framesRecorded += fa.length;
3497
+ }
3498
+ }
3388
3499
  }
3389
- console.error("Capture error: " + err);
3500
+ }
3501
+ if (this.audioOutStream) {
3390
3502
  try {
3391
- this.stop();
3392
- }
3393
- catch (err2) {
3394
- console.error("Capture next error (ignored): " + err2);
3503
+ this.audioOutStream.write(chunk);
3504
+ // // Random test error:
3505
+ // if(Math.random()>0.98) {
3506
+ // throw new Error('Test');
3507
+ // }
3395
3508
  }
3396
- finally {
3397
- if (this.listener) {
3398
- let errExpl = '';
3399
- if (err instanceof DOMException) {
3400
- errExpl = ': ' + err.name + ': ' + err.message;
3401
- }
3402
- this.listener.error("Could not handle recorded audio data" + errExpl, "Please try to record again.");
3509
+ catch (err) {
3510
+ if (err instanceof Error) {
3511
+ this.persistError = err;
3403
3512
  }
3404
3513
  else {
3405
- this.close();
3514
+ this.persistError = new Error('Error handling recorded audio data');
3515
+ }
3516
+ console.error("Capture error: " + err);
3517
+ try {
3518
+ this.stop();
3519
+ }
3520
+ catch (err2) {
3521
+ console.error("Capture next error (ignored): " + err2);
3522
+ }
3523
+ finally {
3524
+ if (this.listener) {
3525
+ let errExpl = '';
3526
+ if (err instanceof DOMException) {
3527
+ errExpl = ': ' + err.name + ': ' + err.message;
3528
+ }
3529
+ this.listener.error("Could not handle recorded audio data" + errExpl, "Please try to record again.");
3530
+ }
3531
+ else {
3532
+ this.close();
3533
+ }
3406
3534
  }
3407
3535
  }
3408
3536
  }
3537
+ if (AudioStorageType.DB_CHUNKED === this._audioStorageType && this._persistentAudioStorageTarget) {
3538
+ this.store();
3539
+ }
3409
3540
  }
3410
- if (AudioStorageType.DB_CHUNKED === this._audioStorageType && this._persistentAudioStorageTarget) {
3411
- this.store();
3412
- }
3413
- }
3414
- };
3415
- }
3416
- // Tried to fix that Safari does not record the second channel
3417
- // Does not help
3418
- //awn.channelCount=this.channelCount;
3419
- //awn.channelCountMode='explicit';
3420
- //console.debug('Channel count explicitly set to '+this.channelCount);
3421
- this.bufferingNode = awn;
3422
- //this.bufferingNode.channelCount=this.channelCount;
3423
- this._opened = true;
3424
- if (this.listener) {
3425
- this.listener.opened();
3541
+ };
3542
+ }
3543
+ // Tried to fix that Safari does not record the second channel
3544
+ // Does not help
3545
+ //awn.channelCount=this.channelCount;
3546
+ //awn.channelCountMode='explicit';
3547
+ //console.debug('Channel count explicitly set to '+this.channelCount);
3548
+ this.bufferingNode = awn;
3549
+ //this.bufferingNode.channelCount=this.channelCount;
3550
+ this._opened = true;
3551
+ if (this.listener) {
3552
+ this.listener.opened();
3553
+ }
3426
3554
  }
3427
3555
  }
3428
- open(channelCount, selDeviceId, autoGainControlConfigs) {
3556
+ open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation) {
3429
3557
  //console.debug("Capture open: ctx state: "+this.context.state);
3430
- if (this.context.state !== 'running') {
3558
+ this.context = this._audioContext();
3559
+ if (!this.context) {
3560
+ throw new Error("Could not get audio context!");
3561
+ }
3562
+ if (this.context.state === 'suspended') {
3431
3563
  //console.debug("Capture open: Resume context");
3432
3564
  this.context.resume().then(() => {
3433
3565
  //console.debug("Capture open (ctx resumed): ctx state: "+this.context.state);
3434
- this._open(channelCount, selDeviceId, autoGainControlConfigs);
3566
+ this._open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation);
3567
+ }).catch((err) => {
3568
+ console.error(err.message);
3569
+ throw err;
3435
3570
  });
3436
3571
  }
3572
+ else if (this.context.state === 'closed') {
3573
+ const msg = 'Error on start capture: The audio context is already closed.';
3574
+ console.error(msg);
3575
+ throw new Error(msg);
3576
+ }
3437
3577
  else {
3438
- this._open(channelCount, selDeviceId, autoGainControlConfigs);
3578
+ this._open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation);
3439
3579
  }
3440
3580
  }
3441
- _open(channelCount, selDeviceId, autoGainControlConfigs) {
3581
+ _open(channelCount, selDeviceId, autoGainControlConfigs, allowEchoCancellation) {
3442
3582
  this.channelCount = channelCount;
3443
3583
  this.framesRecorded = 0;
3584
+ this.context = this._audioContext();
3585
+ if (!this.context) {
3586
+ throw new Error("Could not get audio context!");
3587
+ }
3444
3588
  //var msc = new AudioStreamConstr();
3445
3589
  // var msc={};
3446
3590
  //msc.video = false;
@@ -3548,7 +3692,7 @@ class AudioCapture {
3548
3692
  audio: {
3549
3693
  deviceId: selDeviceId,
3550
3694
  channelCount: channelCount,
3551
- //echoCancellation: false
3695
+ echoCancellation: allowEchoCancellation ? undefined : false
3552
3696
  },
3553
3697
  video: false,
3554
3698
  };
@@ -3559,106 +3703,109 @@ class AudioCapture {
3559
3703
  console.debug("Audio capture, AGC: " + this.agcStatus);
3560
3704
  let ump = navigator.mediaDevices.getUserMedia(msc);
3561
3705
  ump.then((s) => {
3562
- this.stream = s;
3563
- let aTracks = s.getAudioTracks();
3564
- for (let i = 0; i < aTracks.length; i++) {
3565
- let aTrack = aTracks[i];
3566
- console.info("Track audio info: id: " + aTrack.id + " kind: " + aTrack.kind + " label: \"" + aTrack.label + "\"");
3567
- let mtrSts = aTrack.getSettings();
3568
- // Typescript lib.dom.ts MediaTrackSettings.channelCount is missing
3569
- // https://github.com/mdn/browser-compat-data/blob/5493d8f937e05b2ddbd41b99f5bdfad4a1f2ed85/api/MediaTrackSettings.json
3570
- //@ts-ignore
3571
- console.info("Track audio settings: Ch cnt: " + mtrSts.channelCount + ", AGC: " + mtrSts.autoGainControl + ", Echo cancell.: " + mtrSts.echoCancellation);
3572
- if (mtrSts.autoGainControl) {
3573
- this.agcStatus = mtrSts.autoGainControl;
3574
- }
3575
- }
3576
- let vTracks = s.getVideoTracks();
3577
- for (let i = 0; i < vTracks.length; i++) {
3578
- let vTrack = vTracks[i];
3579
- console.info("Track video info: id: " + vTrack.id + " kind: " + vTrack.kind + " label: " + vTrack.label);
3580
- }
3581
- this.mediaStream = this.context.createMediaStreamSource(s);
3582
- // stream channel count ( is always 2 !)
3583
- let streamChannelCount = this.mediaStream.channelCount;
3584
- console.info("Stream channel count: " + streamChannelCount);
3585
- // is not set!!
3586
- //this.currentSampleRate = this.mediaStream.sampleRate;
3587
- this.currentSampleRate = this.context.sampleRate;
3588
- console.info("Source audio node: channels: " + streamChannelCount + " samplerate: " + this.currentSampleRate);
3589
- if (this.audioOutStream) {
3590
- this.audioOutStream.setFormat(this.channelCount, this.currentSampleRate);
3591
- }
3592
- // W3C -> new name is createScriptProcessor
3593
- //
3594
- // Again deprecated, but AudioWorker not yet implemented in stable releases (June 2016)
3595
- // AudioWorker is now AudioWorkletProcessor ... (May 2017)
3596
- // Update 12-2020:
3597
- // The ScriptProcessorNode Interface - DEPRECATED
3598
- // Update 06-2021
3599
- // AudioWorkletProcessor is here to stay. Web Audio API has now Recommendation status !
3600
- if (this.context.audioWorklet) {
3601
- //const workletFileName = ('file-loader!./interceptor_worklet.js');
3602
- //const workletFileName = 'http://localhost:4200/assets/interceptor_worklet.js';
3603
- //console.log(awpStr);
3604
- if (AudioCapture.captureInterceptorModuleRegistered) {
3605
- // Required capture interceptor module already registered
3606
- this.addCaptureInterceptor();
3607
- }
3608
- else {
3609
- // Register capture interceptor module
3610
- let audioWorkletModuleBlob = new Blob([awpStr], { type: 'text/javascript' });
3611
- let audioWorkletModuleBlobUrl = window.URL.createObjectURL(audioWorkletModuleBlob);
3612
- this.context.audioWorklet.addModule(audioWorkletModuleBlobUrl).then(() => {
3613
- AudioCapture.captureInterceptorModuleRegistered = true;
3706
+ if (this.context) {
3707
+ this.stream = s;
3708
+ let aTracks = s.getAudioTracks();
3709
+ for (let i = 0; i < aTracks.length; i++) {
3710
+ let aTrack = aTracks[i];
3711
+ console.info("Track audio info: id: " + aTrack.id + " kind: " + aTrack.kind + " label: \"" + aTrack.label + "\"");
3712
+ let mtrSts = aTrack.getSettings();
3713
+ // Typescript lib.dom.ts MediaTrackSettings.channelCount is missing
3714
+ // https://github.com/mdn/browser-compat-data/blob/5493d8f937e05b2ddbd41b99f5bdfad4a1f2ed85/api/MediaTrackSettings.json
3715
+ //@ts-ignore
3716
+ console.info("Track audio settings: Ch cnt: " + mtrSts.channelCount + ", AGC: " + mtrSts.autoGainControl + ", Echo cancell.: " + mtrSts.echoCancellation);
3717
+ if (mtrSts.autoGainControl) {
3718
+ this.agcStatus = mtrSts.autoGainControl;
3719
+ }
3720
+ console.debug("Echo cancellation: " + mtrSts.echoCancellation);
3721
+ }
3722
+ let vTracks = s.getVideoTracks();
3723
+ for (let i = 0; i < vTracks.length; i++) {
3724
+ let vTrack = vTracks[i];
3725
+ console.info("Track video info: id: " + vTrack.id + " kind: " + vTrack.kind + " label: " + vTrack.label);
3726
+ }
3727
+ this.mediaStream = this.context.createMediaStreamSource(s);
3728
+ // stream channel count ( is always 2 !)
3729
+ let streamChannelCount = this.mediaStream.channelCount;
3730
+ console.info("Stream channel count: " + streamChannelCount);
3731
+ // is not set!!
3732
+ //this.currentSampleRate = this.mediaStream.sampleRate;
3733
+ this.currentSampleRate = this.context.sampleRate;
3734
+ console.info("Source audio node: channels: " + streamChannelCount + " samplerate: " + this.currentSampleRate);
3735
+ if (this.audioOutStream) {
3736
+ this.audioOutStream.setFormat(this.channelCount, this.currentSampleRate);
3737
+ }
3738
+ // W3C -> new name is createScriptProcessor
3739
+ //
3740
+ // Again deprecated, but AudioWorker not yet implemented in stable releases (June 2016)
3741
+ // AudioWorker is now AudioWorkletProcessor ... (May 2017)
3742
+ // Update 12-2020:
3743
+ // The ScriptProcessorNode Interface - DEPRECATED
3744
+ // Update 06-2021
3745
+ // AudioWorkletProcessor is here to stay. Web Audio API has now Recommendation status !
3746
+ if (this.context.audioWorklet) {
3747
+ //const workletFileName = ('file-loader!./interceptor_worklet.js');
3748
+ //const workletFileName = 'http://localhost:4200/assets/interceptor_worklet.js';
3749
+ //console.log(awpStr);
3750
+ if (AudioCapture.captureInterceptorModuleRegistered) {
3751
+ // Required capture interceptor module already registered
3614
3752
  this.addCaptureInterceptor();
3615
- }).catch((error) => {
3616
- console.log('Could not add module ' + error);
3617
- });
3753
+ }
3754
+ else {
3755
+ // Register capture interceptor module
3756
+ let audioWorkletModuleBlob = new Blob([awpStr], { type: 'text/javascript' });
3757
+ let audioWorkletModuleBlobUrl = window.URL.createObjectURL(audioWorkletModuleBlob);
3758
+ this.context.audioWorklet.addModule(audioWorkletModuleBlobUrl).then(() => {
3759
+ AudioCapture.captureInterceptorModuleRegistered = true;
3760
+ this.addCaptureInterceptor();
3761
+ }).catch((error) => {
3762
+ console.log('Could not add module ' + error);
3763
+ });
3764
+ }
3618
3765
  }
3619
- }
3620
- else if (this.context.createScriptProcessor) {
3621
- // The ScriptProcessorNode Interface - DEPRECATED Only as fallback
3622
- // TODO should we use streamChannelCount or channelCount here ?
3623
- let scriptProcessorNode = this.context.createScriptProcessor(AudioCapture.BUFFER_SIZE, streamChannelCount, streamChannelCount);
3624
- this.bufferingNode = scriptProcessorNode;
3625
- let c = 0;
3626
- if (scriptProcessorNode.onaudioprocess) {
3627
- scriptProcessorNode.onaudioprocess = (e) => {
3628
- if (this.capturing) {
3629
- let inBuffer = e.inputBuffer;
3630
- // only process requested count of channels
3631
- let currentBuffers = new Array(channelCount);
3632
- for (let ch = 0; ch < channelCount; ch++) {
3633
- let chSamples = inBuffer.getChannelData(ch);
3634
- let chSamplesCopy = chSamples.slice(0);
3635
- currentBuffers[ch] = chSamplesCopy.slice(0);
3636
- if (this.data) {
3637
- this.data[ch].push(chSamplesCopy);
3766
+ else if (this.context.createScriptProcessor) {
3767
+ // The ScriptProcessorNode Interface - DEPRECATED Only as fallback
3768
+ // TODO should we use streamChannelCount or channelCount here ?
3769
+ let scriptProcessorNode = this.context.createScriptProcessor(AudioCapture.BUFFER_SIZE, streamChannelCount, streamChannelCount);
3770
+ this.bufferingNode = scriptProcessorNode;
3771
+ let c = 0;
3772
+ if (scriptProcessorNode.onaudioprocess) {
3773
+ scriptProcessorNode.onaudioprocess = (e) => {
3774
+ if (this.capturing) {
3775
+ let inBuffer = e.inputBuffer;
3776
+ // only process requested count of channels
3777
+ let currentBuffers = new Array(channelCount);
3778
+ for (let ch = 0; ch < channelCount; ch++) {
3779
+ let chSamples = inBuffer.getChannelData(ch);
3780
+ let chSamplesCopy = chSamples.slice(0);
3781
+ currentBuffers[ch] = chSamplesCopy.slice(0);
3782
+ if (this.data) {
3783
+ this.data[ch].push(chSamplesCopy);
3784
+ }
3785
+ if (DEBUG_TRACE_LEVEL > 8) {
3786
+ console.debug("Process " + chSamplesCopy.length + " samples.");
3787
+ }
3788
+ this.framesRecorded += chSamplesCopy.length;
3638
3789
  }
3639
- if (DEBUG_TRACE_LEVEL > 8) {
3640
- console.debug("Process " + chSamplesCopy.length + " samples.");
3790
+ c++;
3791
+ if (this.audioOutStream) {
3792
+ this.audioOutStream.write(currentBuffers);
3641
3793
  }
3642
- this.framesRecorded += chSamplesCopy.length;
3643
- }
3644
- c++;
3645
- if (this.audioOutStream) {
3646
- this.audioOutStream.write(currentBuffers);
3647
3794
  }
3795
+ };
3796
+ this._opened = true;
3797
+ if (this.listener) {
3798
+ this.listener.opened();
3648
3799
  }
3649
- };
3650
- this._opened = true;
3651
- if (this.listener) {
3652
- this.listener.opened();
3800
+ }
3801
+ else {
3802
+ this.listener.error('Browser does not support audio processing (ScriptProcessor.onaudioprocess method not found)!');
3653
3803
  }
3654
3804
  }
3655
3805
  else {
3656
- this.listener.error('Browser does not support audio processing (ScriptProcessor.onaudioprocess method not found)!');
3806
+ this.listener.error('Browser does not support audio processing (neither AudioWorkletProcessor nor ScriptProcessor)!');
3657
3807
  }
3658
3808
  }
3659
- else {
3660
- this.listener.error('Browser does not support audio processing (neither AudioWorkletProcessor nor ScriptProcessor)!');
3661
- }
3662
3809
  }, (e) => {
3663
3810
  console.error(e + " Error name: " + e.name);
3664
3811
  if (this.listener) {
@@ -3679,36 +3826,42 @@ class AudioCapture {
3679
3826
  });
3680
3827
  }
3681
3828
  _start() {
3682
- this.initData();
3683
- if (this.audioOutStream) {
3684
- this.audioOutStream.nextStream();
3685
- }
3686
- this.capturing = true;
3687
- if (this.bufferingNode) {
3688
- this.mediaStream.connect(this.bufferingNode);
3689
- this.bufferingNode.connect(this.context.destination);
3690
- }
3691
- if (this.listener) {
3692
- this.listener.started();
3829
+ if (this.context) {
3830
+ this.initData();
3831
+ if (this.audioOutStream) {
3832
+ this.audioOutStream.nextStream();
3833
+ }
3834
+ this.capturing = true;
3835
+ if (this.bufferingNode) {
3836
+ this.mediaStream.connect(this.bufferingNode);
3837
+ this.bufferingNode.connect(this.context.destination);
3838
+ }
3839
+ if (this.listener) {
3840
+ this.listener.started();
3841
+ }
3693
3842
  }
3694
3843
  }
3695
3844
  start() {
3696
- const aSt = this.context.state;
3697
- if (aSt === 'running') {
3698
- this._start();
3699
- }
3700
- else {
3701
- console.debug("Capture start: audio context not running, state: " + aSt + ", resuming...");
3702
- this.context.resume().then(() => {
3703
- console.debug("Capture start: audio context resumed, starting...");
3845
+ if (this.context) {
3846
+ const aSt = this.context.state;
3847
+ if (aSt === 'running') {
3704
3848
  this._start();
3705
- });
3849
+ }
3850
+ else {
3851
+ console.debug("Capture start: audio context not running, state: " + aSt + ", resuming...");
3852
+ this.context.resume().then(() => {
3853
+ console.debug("Capture start: audio context resumed, starting...");
3854
+ this._start();
3855
+ });
3856
+ }
3706
3857
  }
3707
3858
  }
3708
3859
  stop() {
3709
3860
  if (this.disconnectStreams && this.bufferingNode) {
3710
3861
  this.mediaStream.disconnect(this.bufferingNode);
3711
- this.bufferingNode.disconnect(this.context.destination);
3862
+ if (this.context) {
3863
+ this.bufferingNode.disconnect(this.context.destination);
3864
+ }
3712
3865
  }
3713
3866
  try {
3714
3867
  if (this.audioOutStream) {
@@ -3831,7 +3984,7 @@ class AudioCapture {
3831
3984
  }
3832
3985
  audioBuffer() {
3833
3986
  let ab = null;
3834
- if (this.data) {
3987
+ if (this.context && this.data) {
3835
3988
  let frameLen = 0;
3836
3989
  let ch0Data = this.data[0];
3837
3990
  for (let ch0Chk of ch0Data) {
@@ -4533,7 +4686,7 @@ class Uploader {
4533
4686
  si += v.size;
4534
4687
  }
4535
4688
  else if (typeof v === 'string') {
4536
- // encode to UT-f8 to get upload size
4689
+ // encode to UTF-8 to get upload size
4537
4690
  si += this.te.encode().length;
4538
4691
  }
4539
4692
  });
@@ -4571,35 +4724,38 @@ class Uploader {
4571
4724
  // pipe(timeout()) is not the same as xhr.timeout
4572
4725
  let uploadedUpload = null;
4573
4726
  //console.debug("Post upload: "+ul)
4574
- this.http.post(ul.url, ul.data, { withCredentials: this.withCredentials }).pipe(timeout(timeoVal)).subscribe(data => {
4575
- uploadedUpload = ul;
4576
- //console.debug('Next method called for upload: '+uploadedUpload)
4577
- }, (err) => {
4578
- if (err.error instanceof Error) {
4579
- // A client-side or network error occurred. Handle it accordingly.
4580
- console.error('Upload error occurred:', err.error.message);
4581
- }
4582
- else {
4583
- // The backend returned an unsuccessful response code.
4584
- // The response body may contain clues as to what went wrong,
4585
- console.error(`Upload error: Server returned code ${err.status}`);
4586
- }
4587
- this.processError(ul);
4588
- }, () => {
4589
- //console.debug('Upload complete method called')
4590
- if (uploadedUpload) {
4591
- if (this.DEBUG_DELAY > 0) {
4592
- window.setTimeout(() => {
4593
- this.uploadDone(ul);
4594
- }, this.DEBUG_DELAY);
4727
+ this.http.post(ul.url, ul.data, { withCredentials: this.withCredentials }).pipe(timeout(timeoVal)).subscribe({
4728
+ next: (data) => {
4729
+ uploadedUpload = ul;
4730
+ //console.debug('Next method called for upload: '+uploadedUpload)
4731
+ },
4732
+ error: (err) => {
4733
+ if (err.error instanceof Error) {
4734
+ // A client-side or network error occurred. Handle it accordingly.
4735
+ console.error('Upload error occurred:', err.error.message);
4736
+ }
4737
+ else {
4738
+ // The backend returned an unsuccessful response code.
4739
+ // The response body may contain clues as to what went wrong,
4740
+ console.error(`Upload error: Server returned code ${err.status}`);
4741
+ }
4742
+ this.processError(ul);
4743
+ }, complete: () => {
4744
+ //console.debug('Upload complete method called')
4745
+ if (uploadedUpload) {
4746
+ if (this.DEBUG_DELAY > 0) {
4747
+ window.setTimeout(() => {
4748
+ this.uploadDone(ul);
4749
+ }, this.DEBUG_DELAY);
4750
+ }
4751
+ else {
4752
+ this.uploadDone(uploadedUpload);
4753
+ }
4595
4754
  }
4596
4755
  else {
4597
- this.uploadDone(uploadedUpload);
4756
+ console.error('Upload post complete, but upload not set in next method!');
4598
4757
  }
4599
4758
  }
4600
- else {
4601
- console.error('Upload post complete, but upload not set in next method!');
4602
- }
4603
4759
  });
4604
4760
  }
4605
4761
  processError(ul) {
@@ -4613,7 +4769,7 @@ class Uploader {
4613
4769
  // set retry timer
4614
4770
  this.retryTimerId = window.setTimeout(() => {
4615
4771
  this.retryTimerRunning = false;
4616
- //console.debug("Upload retry timer exprired. Continue processing...")
4772
+ //console.debug("Upload retry timer expired. Continue processing...")
4617
4773
  this.process();
4618
4774
  }, this.RETRY_DELAY);
4619
4775
  this.retryTimerRunning = true;
@@ -4707,12 +4863,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
4707
4863
  * Created by klausj on 17.06.2017.
4708
4864
  */
4709
4865
  class ProjectService {
4710
- constructor(http, platformLoaction, config) {
4866
+ constructor(http, platformLocation, config) {
4711
4867
  this.http = http;
4712
- this.platformLoaction = platformLoaction;
4868
+ this.platformLocation = platformLocation;
4713
4869
  this.config = config;
4714
4870
  this.withCredentials = false;
4715
- console.log("Base Href: " + platformLoaction.getBaseHrefFromDOM());
4871
+ console.log("Base Href: " + platformLocation.getBaseHrefFromDOM());
4716
4872
  let apiEndPoint = '';
4717
4873
  if (config && config.apiEndPoint) {
4718
4874
  apiEndPoint = config.apiEndPoint;
@@ -4797,14 +4953,17 @@ class SessionService {
4797
4953
  let wrapObs = new Observable(subscriber => {
4798
4954
  this._uploadCount++;
4799
4955
  let obs = this.http.patch(sesssUrl, body, { withCredentials: this.withCredentials });
4800
- obs.subscribe((value) => {
4801
- subscriber.next(value);
4802
- }, error => {
4803
- this._uploadCount--;
4804
- subscriber.error(error);
4805
- }, () => {
4806
- this._uploadCount--;
4807
- subscriber.complete();
4956
+ obs.subscribe({
4957
+ next: (value) => {
4958
+ subscriber.next(value);
4959
+ },
4960
+ error: error => {
4961
+ this._uploadCount--;
4962
+ subscriber.error(error);
4963
+ }, complete: () => {
4964
+ this._uploadCount--;
4965
+ subscriber.complete();
4966
+ }
4808
4967
  });
4809
4968
  });
4810
4969
  return wrapObs;
@@ -7423,7 +7582,7 @@ AudioClipUIContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", v
7423
7582
  <audio-signal [pointerPosition]="pointer" [selecting]="selecting" [selection]="selection" (pointerPositionEventEmitter)="pointerPositionChanged($event)" (selectingEventEmitter)="selectingChanged($event)" (selectedEventEmitter)="selectionChanged($event)"></audio-signal>
7424
7583
  <audio-sonagram [pointerPosition]="pointer" [selecting]="selecting" [selection]="selection" (pointerPositionEventEmitter)="pointerPositionChanged($event)" (selectingEventEmitter)="selectingChanged($event)" (selectedEventEmitter)="selectionChanged($event)"></audio-sonagram>
7425
7584
  </div>
7426
- `, 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" }] });
7585
+ `, 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" }] });
7427
7586
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AudioClipUIContainer, decorators: [{
7428
7587
  type: Component,
7429
7588
  args: [{ selector: 'app-audio', template: `
@@ -7433,7 +7592,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
7433
7592
  <audio-signal [pointerPosition]="pointer" [selecting]="selecting" [selection]="selection" (pointerPositionEventEmitter)="pointerPositionChanged($event)" (selectingEventEmitter)="selectingChanged($event)" (selectedEventEmitter)="selectionChanged($event)"></audio-signal>
7434
7593
  <audio-sonagram [pointerPosition]="pointer" [selecting]="selecting" [selection]="selection" (pointerPositionEventEmitter)="pointerPositionChanged($event)" (selectingEventEmitter)="selectingChanged($event)" (selectedEventEmitter)="selectionChanged($event)"></audio-sonagram>
7435
7594
  </div>
7436
- `, 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"] }]
7595
+ `, 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"] }]
7437
7596
  }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { canvasRef: [{
7438
7597
  type: ViewChild,
7439
7598
  args: ['divider', { static: true }]
@@ -7747,8 +7906,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
7747
7906
  }] } });
7748
7907
 
7749
7908
  class AudioDisplay {
7750
- constructor(route, ref, eRef) {
7751
- this.route = route;
7909
+ constructor(ref, eRef) {
7752
7910
  this.ref = ref;
7753
7911
  this.eRef = eRef;
7754
7912
  this._audioClip = null;
@@ -7811,7 +7969,7 @@ class AudioDisplay {
7811
7969
  this.status = 'ERROR';
7812
7970
  }
7813
7971
  }
7814
- 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 });
7972
+ 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 });
7815
7973
  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: `
7816
7974
 
7817
7975
  <audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
@@ -7842,7 +8000,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
7842
8000
  [zoomSelectedAction]="zoomSelectedAction"
7843
8001
  [zoomFitToPanelAction]="zoomFitToPanelAction"></audio-display-control>
7844
8002
  `, 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"] }]
7845
- }], ctorParameters: function () { return [{ type: i1$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { playStartAction: [{
8003
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { playStartAction: [{
7846
8004
  type: Input
7847
8005
  }], playStopAction: [{
7848
8006
  type: Input
@@ -7873,11 +8031,11 @@ class ResponsiveComponent {
7873
8031
  });
7874
8032
  }
7875
8033
  }
7876
- 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 });
8034
+ 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 });
7877
8035
  ResponsiveComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: ResponsiveComponent, ngImport: i0 });
7878
8036
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ResponsiveComponent, decorators: [{
7879
8037
  type: Directive
7880
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }]; } });
8038
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }]; } });
7881
8039
 
7882
8040
  class ScrollIntoViewDirective {
7883
8041
  constructor(elRef) {
@@ -8557,7 +8715,7 @@ class Prompting extends ResponsiveComponent {
8557
8715
  this.onPrevItem.emit();
8558
8716
  }
8559
8717
  }
8560
- 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 });
8718
+ 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 });
8561
8719
  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: `
8562
8720
 
8563
8721
  <app-simpletrafficlight [status]="startStopSignalState"></app-simpletrafficlight>
@@ -8606,7 +8764,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
8606
8764
 
8607
8765
 
8608
8766
  `, 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"] }]
8609
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }]; }, propDecorators: { simpleTrafficLight: [{
8767
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }]; }, propDecorators: { simpleTrafficLight: [{
8610
8768
  type: ViewChild,
8611
8769
  args: [SimpleTrafficLight, { static: true }]
8612
8770
  }], audioDisplay: [{
@@ -8657,7 +8815,7 @@ class SessionFinishedDialog {
8657
8815
  this.dialogRef.close();
8658
8816
  }
8659
8817
  }
8660
- 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 });
8818
+ 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 });
8661
8819
  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>
8662
8820
  <div mat-dialog-content>
8663
8821
 
@@ -8667,7 +8825,7 @@ SessionFinishedDialog.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0",
8667
8825
  <div mat-dialog-actions>
8668
8826
  <button mat-button (click)="closeDialog()">OK</button>
8669
8827
  </div>
8670
- `, 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"] }] });
8828
+ `, 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"] }] });
8671
8829
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SessionFinishedDialog, decorators: [{
8672
8830
  type: Component,
8673
8831
  args: [{
@@ -8684,7 +8842,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
8684
8842
  `
8685
8843
  }]
8686
8844
  }], ctorParameters: function () {
8687
- return [{ type: i1$4.MatDialogRef }, { type: undefined, decorators: [{
8845
+ return [{ type: i1$3.MatDialogRef }, { type: undefined, decorators: [{
8688
8846
  type: Inject,
8689
8847
  args: [MAT_DIALOG_DATA]
8690
8848
  }] }];
@@ -8699,7 +8857,7 @@ class MessageDialog {
8699
8857
  this.dialogRef.close();
8700
8858
  }
8701
8859
  }
8702
- 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 });
8860
+ 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 });
8703
8861
  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>
8704
8862
  <mat-icon *ngIf="data.type==='warning'" [style.color]="'yellow'">warning</mat-icon>{{data.title}}</h1>
8705
8863
  <div mat-dialog-content>
@@ -8711,7 +8869,7 @@ MessageDialog.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version:
8711
8869
  <div mat-dialog-actions>
8712
8870
  <button mat-button (click)="closeDialog()">OK</button>
8713
8871
  </div>
8714
- `, 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"] }] });
8872
+ `, 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"] }] });
8715
8873
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: MessageDialog, decorators: [{
8716
8874
  type: Component,
8717
8875
  args: [{
@@ -8730,7 +8888,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
8730
8888
  `
8731
8889
  }]
8732
8890
  }], ctorParameters: function () {
8733
- return [{ type: i1$4.MatDialogRef }, { type: undefined, decorators: [{
8891
+ return [{ type: i1$3.MatDialogRef }, { type: undefined, decorators: [{
8734
8892
  type: Inject,
8735
8893
  args: [MAT_DIALOG_DATA]
8736
8894
  }] }];
@@ -9022,7 +9180,7 @@ let BasicRecordingService = class BasicRecordingService {
9022
9180
  withCredentials: this.withCredentials
9023
9181
  });
9024
9182
  }
9025
- chunkAudioRequest(aCtx, baseAudioUrl, startFrame = 0, frameLength) {
9183
+ chunkAudioRequest(baseAudioUrl, startFrame = 0, frameLength) {
9026
9184
  let ausps = new URLSearchParams();
9027
9185
  ausps.set('startFrame', startFrame.toString());
9028
9186
  ausps.set('frameLength', frameLength.toString());
@@ -9033,67 +9191,69 @@ let BasicRecordingService = class BasicRecordingService {
9033
9191
  ausps.set('requestUUID', UUID.generate());
9034
9192
  }
9035
9193
  let obs = new Observable(observer => {
9036
- this.audioRequestByURL(baseAudioUrl, ausps).subscribe(resp => {
9037
- // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9038
- if (resp.body) {
9039
- //console.debug("chunkAudioRequest: observer.closed: "+observer.closed);
9040
- //console.debug("Audio file bytes: "+resp.body.byteLength);
9041
- // Check original audio format
9042
- let wr = new WavReader(resp.body);
9043
- const pcmFmt = wr.readFormat();
9044
- const orgFl = wr.frameLength();
9045
- // if(pcmFmt){
9046
- // console.debug("Original WAVE format of download chunk: "+pcmFmt);
9047
- // }else{
9048
- // console.error("Could not read WAVE format of original download chunk!");
9049
- // }
9050
- // if(orgFl){
9051
- // console.debug("Original frame length of download chunk: "+orgFl);
9052
- // }else{
9053
- // console.error("Could not read WAVE format of original download chunk!");
9054
- // }
9055
- if (pcmFmt && orgFl) {
9056
- aCtx.decodeAudioData(resp.body, ab => {
9057
- //console.debug("Decoded audio chunk frames: "+ab.length);
9058
- let chDl = new ChunkDownload(pcmFmt, orgFl, ab);
9059
- observer.next(chDl);
9060
- observer.complete();
9061
- }, error => {
9062
- //if(error instanceof HttpErrorResponse) {
9063
- // if (error.status == 404) {
9064
- // // Interpret not as an error, the file ist not recorded yet
9065
- // observer.next(null);
9066
- // observer.complete()
9067
- // } else {
9068
- // // all other states are errors
9069
- console.error("Recordings service chunkAudioRequest error decoding audio data: " + error.name + ": " + error.message);
9070
- observer.error(error);
9071
- // }
9072
- // }
9073
- });
9194
+ this.audioRequestByURL(baseAudioUrl, ausps).subscribe({
9195
+ next: resp => {
9196
+ // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9197
+ if (resp.body) {
9198
+ //console.debug("chunkAudioRequest: observer.closed: "+observer.closed);
9199
+ //console.debug("Audio file bytes: "+resp.body.byteLength);
9200
+ // Check original audio format
9201
+ let wr = new WavReader(resp.body);
9202
+ const pcmFmt = wr.readFormat();
9203
+ const orgFl = wr.frameLength();
9204
+ // if(pcmFmt){
9205
+ // console.debug("Original WAVE format of download chunk: "+pcmFmt);
9206
+ // }else{
9207
+ // console.error("Could not read WAVE format of original download chunk!");
9208
+ // }
9209
+ // if(orgFl){
9210
+ // console.debug("Original frame length of download chunk: "+orgFl);
9211
+ // }else{
9212
+ // console.error("Could not read WAVE format of original download chunk!");
9213
+ // }
9214
+ if (pcmFmt && orgFl) {
9215
+ AudioContextProvider.decodeAudioData(resp.body).then((ab) => {
9216
+ //console.debug("Decoded audio chunk frames: "+ab.length);
9217
+ let chDl = new ChunkDownload(pcmFmt, orgFl, ab);
9218
+ observer.next(chDl);
9219
+ observer.complete();
9220
+ }).catch(error => {
9221
+ //if(error instanceof HttpErrorResponse) {
9222
+ // if (error.status == 404) {
9223
+ // // Interpret not as an error, the file ist not recorded yet
9224
+ // observer.next(null);
9225
+ // observer.complete()
9226
+ // } else {
9227
+ // // all other states are errors
9228
+ console.error("Recordings service chunkAudioRequest error decoding audio data: " + error.name + ": " + error.message);
9229
+ observer.error(error);
9230
+ // }
9231
+ // }
9232
+ });
9233
+ }
9234
+ else {
9235
+ const errMsg = 'Could not parse audio header for format and/or frame length of download.';
9236
+ console.error(errMsg);
9237
+ observer.error(errMsg);
9238
+ }
9074
9239
  }
9075
9240
  else {
9076
- const errMsg = 'Could not parse audio header for format and/or frame length of download.';
9241
+ const errMsg = 'Fetching audio file: response has no body';
9077
9242
  console.error(errMsg);
9078
9243
  observer.error(errMsg);
9079
9244
  }
9245
+ }, error: (error) => {
9246
+ // all other states are errors
9247
+ //const errMsg='Fetching audio file HTTP error: '+error;
9248
+ //console.error(errMsg);
9249
+ observer.error(error);
9250
+ //observer.complete();
9080
9251
  }
9081
- else {
9082
- const errMsg = 'Fetching audio file: response has no body';
9083
- console.error(errMsg);
9084
- observer.error(errMsg);
9085
- }
9086
- }, (error) => {
9087
- // all other states are errors
9088
- //const errMsg='Fetching audio file HTTP error: '+error;
9089
- //console.error(errMsg);
9090
- observer.error(error);
9091
- //observer.complete();
9092
9252
  });
9093
9253
  });
9094
9254
  return obs;
9095
9255
  }
9096
- chunkAudioRequestToNetAudioBuffer(aCtx, baseAudioUrl, startFrame = 0, orgSampleRate, seconds, frames) {
9256
+ chunkAudioRequestToNetAudioBuffer(baseAudioUrl, startFrame = 0, orgSampleRate, seconds, frames) {
9097
9257
  //let audioUrl=baseAudioUrl+'?startFrame='+startFrame+'&frameLength='+frameLength;
9098
9258
  //let audioUrl=new URL(baseAudioUrl);
9099
9259
  // if(orgSampleRate!=null && frameLength%orgSampleRate>0){
@@ -9117,7 +9277,7 @@ let BasicRecordingService = class BasicRecordingService {
9117
9277
  if (resp.body) {
9118
9278
  //console.debug("chunkAudioRequestTonetAb: subscriber.closed: "+subscriber.closed);
9119
9279
  //console.debug("chunkAudioRequestTonetAb: Audio file bytes: "+resp.body.byteLength);
9120
- aCtx.decodeAudioData(resp.body, ab => {
9280
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9121
9281
  //console.debug("chunkAudioRequestTonetAb: Decoded audio chunk frames for netAb: "+ab.length);
9122
9282
  //console.debug("chunkAudioRequestTonetAb: Create netAb ab from chunk ab...");
9123
9283
  if (frames === null) {
@@ -9131,7 +9291,7 @@ let BasicRecordingService = class BasicRecordingService {
9131
9291
  //console.debug("Platform sr: "+ab.sampleRate+", file sr: "+orgSampleRate+", decoded/org frame length: "+fl+"/"+frames+", ab.length: "+ab.length);
9132
9292
  }
9133
9293
  }
9134
- let nab = NetAudioBuffer.fromChunkAudioBuffer(aCtx, this, baseAudioUrl, ab, fl, frameLength);
9294
+ let nab = NetAudioBuffer.fromChunkAudioBuffer(this, baseAudioUrl, ab, fl, frameLength);
9135
9295
  //let rp=new ReadyProvider();
9136
9296
  //nab.readyProvider=rp;
9137
9297
  //rp.ready();
@@ -9143,7 +9303,7 @@ let BasicRecordingService = class BasicRecordingService {
9143
9303
  subscriber.next(nab);
9144
9304
  subscriber.complete();
9145
9305
  }
9146
- }, error => {
9306
+ }).catch(error => {
9147
9307
  console.error('chunkAudioRequestToNetAb: error: ' + error);
9148
9308
  //if(error instanceof HttpErrorResponse) {
9149
9309
  subscriber.error(error);
@@ -9251,7 +9411,7 @@ class RecordingService extends BasicRecordingService {
9251
9411
  withCredentials: this.withCredentials
9252
9412
  });
9253
9413
  }
9254
- chunkAudioRequestToIndDb(aCtx, persistentAudioStorageTarget, inddbAudioBuffer, baseAudioUrl, startFrame = 0, orgSampleRate, seconds) {
9414
+ chunkAudioRequestToIndDb(persistentAudioStorageTarget, inddbAudioBuffer, baseAudioUrl, startFrame = 0, orgSampleRate, seconds) {
9255
9415
  //let audioUrl=baseAudioUrl+'?startFrame='+startFrame+'&frameLength='+frameLength;
9256
9416
  //let audioUrl=new URL(baseAudioUrl);
9257
9417
  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.
@@ -9270,7 +9430,7 @@ class RecordingService extends BasicRecordingService {
9270
9430
  if (resp.body) {
9271
9431
  //console.debug("chunkAudioRequestToIndDb: subscriber.closed: "+subscriber.closed);
9272
9432
  //console.debug("chunkAudioRequestToIndDb: Audio file bytes: "+resp.body.byteLength);
9273
- aCtx.decodeAudioData(resp.body, ab => {
9433
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9274
9434
  //console.debug("chunkAudioRequestToIndDb: Decoded audio chunk frames for inddb: "+ab.length);
9275
9435
  if (!inddbAudioBuffer) {
9276
9436
  //console.debug("chunkAudioRequestToIndDb: Create inddb ab from chunk ab...");
@@ -9314,7 +9474,7 @@ class RecordingService extends BasicRecordingService {
9314
9474
  }
9315
9475
  });
9316
9476
  }
9317
- }, error => {
9477
+ }).catch(error => {
9318
9478
  console.error('chunkAudioRequestToIndDb: error: ' + error);
9319
9479
  //if(error instanceof HttpErrorResponse) {
9320
9480
  subscriber.error(error);
@@ -9322,8 +9482,9 @@ class RecordingService extends BasicRecordingService {
9322
9482
  });
9323
9483
  }
9324
9484
  else {
9325
- console.error('chunkAudioRequestToIndDb: Fetching audio file: response has no body');
9326
- subscriber.error('chunkAudioRequestToIndDb: Fetching audio file: response has no body');
9485
+ const errMsg = 'chunkAudioRequestToIndDb: Fetching audio file: response has no body';
9486
+ console.error(errMsg);
9487
+ subscriber.error(new Error(errMsg));
9327
9488
  }
9328
9489
  },
9329
9490
  error: (error) => {
@@ -9335,13 +9496,13 @@ class RecordingService extends BasicRecordingService {
9335
9496
  });
9336
9497
  return obs;
9337
9498
  }
9338
- chunkedAudioRequestToArrayBuffer(aCtx, baseAudioUrl, orgSampleRate, seconds) {
9499
+ chunkedAudioRequestToArrayBuffer(baseAudioUrl, orgSampleRate, seconds) {
9339
9500
  let obs = new Observable(subscriber => {
9340
9501
  let arrayAudioBuffer = null;
9341
9502
  let startFrame = 0;
9342
9503
  let frameLength = orgSampleRate * Math.round(seconds); // Important: multiple of original sample rate to prevent numeric rounding errors on resampling.
9343
9504
  //console.debug("Chunk audio request startFrame 0");
9344
- let subscr = this.chunkAudioRequest(aCtx, baseAudioUrl, startFrame, frameLength).pipe(expand(value => {
9505
+ let subscr = this.chunkAudioRequest(baseAudioUrl, startFrame, frameLength).pipe(expand(value => {
9345
9506
  if (subscriber.closed) {
9346
9507
  subscr.unsubscribe();
9347
9508
  }
@@ -9360,7 +9521,7 @@ class RecordingService extends BasicRecordingService {
9360
9521
  startFrame += frameLength;
9361
9522
  //console.debug("Next start frame: "+startFrame);
9362
9523
  //console.debug("chunkedAudioRequest: expand() subscriber.closed: "+subscriber.closed);
9363
- return this.chunkAudioRequest(aCtx, baseAudioUrl, startFrame, frameLength);
9524
+ return this.chunkAudioRequest(baseAudioUrl, startFrame, frameLength);
9364
9525
  }
9365
9526
  }
9366
9527
  else {
@@ -9430,14 +9591,14 @@ class RecordingService extends BasicRecordingService {
9430
9591
  });
9431
9592
  return obs;
9432
9593
  }
9433
- chunkedInddbAudioRequest(aCtx, persistentAudioStorageTarget, baseAudioUrl, orgSampleRate, seconds) {
9594
+ chunkedInddbAudioRequest(persistentAudioStorageTarget, baseAudioUrl, orgSampleRate, seconds) {
9434
9595
  let obs = new Observable(subscriber => {
9435
9596
  let inddbAudioBuffer = null;
9436
9597
  let startFrame = 0;
9437
9598
  //let frameLength = DEFAULT_CHUNKED_DOWNLOAD_FRAMELENGTH;
9438
9599
  let frameLength = orgSampleRate * Math.round(seconds);
9439
9600
  //console.debug("chunkedInddbAudioRequest: Chunk audio request for inddb. startFrame: "+startFrame);
9440
- let subscr = this.chunkAudioRequestToIndDb(aCtx, persistentAudioStorageTarget, null, baseAudioUrl, startFrame, orgSampleRate, seconds).pipe(expand(iab => {
9601
+ let subscr = this.chunkAudioRequestToIndDb(persistentAudioStorageTarget, null, baseAudioUrl, startFrame, orgSampleRate, seconds).pipe(expand(iab => {
9441
9602
  // console.debug("chunkedInddbAudioRequest (pipe/expand): Got inddb ab: "+iab);
9442
9603
  if (subscriber.closed) {
9443
9604
  subscr.unsubscribe();
@@ -9458,7 +9619,7 @@ class RecordingService extends BasicRecordingService {
9458
9619
  startFrame += frameLength;
9459
9620
  //console.debug("Next start frame: "+startFrame);
9460
9621
  //console.debug("chunkedInddbAudioRequest: expand() subscriber.closed: "+subscriber.closed);
9461
- return this.chunkAudioRequestToIndDb(aCtx, persistentAudioStorageTarget, inddbAudioBuffer, baseAudioUrl, startFrame, orgSampleRate, seconds);
9622
+ return this.chunkAudioRequestToIndDb(persistentAudioStorageTarget, inddbAudioBuffer, baseAudioUrl, startFrame, orgSampleRate, seconds);
9462
9623
  }
9463
9624
  // } else {
9464
9625
  // return EMPTY;
@@ -9650,7 +9811,7 @@ class RecordingService extends BasicRecordingService {
9650
9811
  // //let recUrl=new URL(recUrlStr);
9651
9812
  // return this.chunkedInddbAudioRequest(aCtx,recUrlStr);
9652
9813
  // }
9653
- fetchRecordingFileAudioBuffer(aCtx, projectName, recordingFile) {
9814
+ fetchRecordingFileAudioBuffer(projectName, recordingFile) {
9654
9815
  let wobs = new Observable(observer => {
9655
9816
  let recFileId = recordingFile.recordingFileId;
9656
9817
  if (!recFileId) {
@@ -9658,36 +9819,38 @@ class RecordingService extends BasicRecordingService {
9658
9819
  }
9659
9820
  if (recordingFile.session && recFileId) {
9660
9821
  let obs = this.fetchAudiofile(projectName, recordingFile.session, recFileId);
9661
- obs.subscribe(resp => {
9662
- // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9663
- if (resp.body) {
9664
- aCtx.decodeAudioData(resp.body, ab => {
9665
- observer.next(ab);
9666
- observer.complete();
9667
- }, error => {
9668
- observer.error(error);
9669
- observer.complete();
9670
- });
9671
- }
9672
- else {
9673
- observer.error('Fetching audio file: response has no body');
9674
- }
9675
- }, (err) => {
9676
- if (err instanceof HttpErrorResponse) {
9677
- if (err.status == 404) {
9678
- // Interpret not as an error, the file ist not recorded yet
9679
- observer.next(null);
9680
- observer.complete();
9822
+ obs.subscribe({
9823
+ next: resp => {
9824
+ // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9825
+ if (resp.body) {
9826
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9827
+ observer.next(ab);
9828
+ observer.complete();
9829
+ }).catch(error => {
9830
+ observer.error(error);
9831
+ observer.complete();
9832
+ });
9833
+ }
9834
+ else {
9835
+ observer.error('Fetching audio file: response has no body');
9836
+ }
9837
+ }, error: (err) => {
9838
+ if (err instanceof HttpErrorResponse) {
9839
+ if (err.status == 404) {
9840
+ // Interpret not as an error, the file ist not recorded yet
9841
+ observer.next(null);
9842
+ observer.complete();
9843
+ }
9844
+ else {
9845
+ // all other states are errors
9846
+ observer.error(err);
9847
+ observer.complete();
9848
+ }
9681
9849
  }
9682
9850
  else {
9683
- // all other states are errors
9684
9851
  observer.error(err);
9685
- observer.complete();
9686
9852
  }
9687
9853
  }
9688
- else {
9689
- observer.error(err);
9690
- }
9691
9854
  });
9692
9855
  }
9693
9856
  else {
@@ -9704,49 +9867,50 @@ class RecordingService extends BasicRecordingService {
9704
9867
  }
9705
9868
  if (recordingFile.session && recFileId) {
9706
9869
  let obs = this.fetchAudiofile(projectName, recordingFile.session, recFileId);
9707
- obs.subscribe(resp => {
9708
- //console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
9709
- // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9710
- if (resp.body) {
9711
- aCtx.decodeAudioData(resp.body, ab => {
9712
- let abs = new AudioBufferSource(ab);
9713
- let adh = new AudioDataHolder(abs);
9714
- RecordingFileUtils.setAudioData(recordingFile, adh);
9715
- if (this.debugDelay > 0) {
9716
- window.setTimeout(() => {
9870
+ obs.subscribe({ next: resp => {
9871
+ //console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
9872
+ // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9873
+ if (resp.body) {
9874
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9875
+ let abs = new AudioBufferSource(ab);
9876
+ let adh = new AudioDataHolder(abs);
9877
+ RecordingFileUtils.setAudioData(recordingFile, adh);
9878
+ if (this.debugDelay > 0) {
9879
+ window.setTimeout(() => {
9880
+ observer.next(recordingFile);
9881
+ observer.complete();
9882
+ }, this.debugDelay);
9883
+ }
9884
+ else {
9717
9885
  observer.next(recordingFile);
9718
9886
  observer.complete();
9719
- }, this.debugDelay);
9887
+ }
9888
+ }).catch(error => {
9889
+ observer.error(error);
9890
+ observer.complete();
9891
+ });
9892
+ }
9893
+ else {
9894
+ observer.error('Fetching audio file: response has no body');
9895
+ }
9896
+ },
9897
+ error: (err) => {
9898
+ if (err instanceof HttpErrorResponse) {
9899
+ if (err.status == 404) {
9900
+ // Interpret not as an error, the file ist not recorded yet
9901
+ observer.next(null);
9902
+ observer.complete();
9720
9903
  }
9721
9904
  else {
9722
- observer.next(recordingFile);
9905
+ // all other states are errors
9906
+ observer.error(err);
9723
9907
  observer.complete();
9724
9908
  }
9725
- }, error => {
9726
- observer.error(error);
9727
- observer.complete();
9728
- });
9729
- }
9730
- else {
9731
- observer.error('Fetching audio file: response has no body');
9732
- }
9733
- }, (err) => {
9734
- if (err instanceof HttpErrorResponse) {
9735
- if (err.status == 404) {
9736
- // Interpret not as an error, the file ist not recorded yet
9737
- observer.next(null);
9738
- observer.complete();
9739
9909
  }
9740
9910
  else {
9741
- // all other states are errors
9742
9911
  observer.error(err);
9743
- observer.complete();
9744
9912
  }
9745
- }
9746
- else {
9747
- observer.error(err);
9748
- }
9749
- });
9913
+ } });
9750
9914
  }
9751
9915
  else {
9752
9916
  observer.error();
@@ -9754,7 +9918,7 @@ class RecordingService extends BasicRecordingService {
9754
9918
  });
9755
9919
  return wobs;
9756
9920
  }
9757
- fetchSprRecordingFileAudioBuffer(aCtx, projectName, recordingFile) {
9921
+ fetchSprRecordingFileAudioBuffer(projectName, recordingFile) {
9758
9922
  let wobs = new Observable(observer => {
9759
9923
  if (recordingFile.session) {
9760
9924
  let obs = this.fetchSprAudiofile(projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
@@ -9762,11 +9926,11 @@ class RecordingService extends BasicRecordingService {
9762
9926
  next: resp => {
9763
9927
  // Do not use Promise version, which does not work with Safari 13 (13.0.5)
9764
9928
  if (resp.body) {
9765
- aCtx.decodeAudioData(resp.body, ab => {
9929
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
9766
9930
  //RecordingFileUtils.setAudioData(recordingFile,new AudioDataHolder(ab,null));
9767
9931
  observer.next(ab);
9768
9932
  observer.complete();
9769
- }, error => {
9933
+ }).catch(error => {
9770
9934
  observer.error(error);
9771
9935
  observer.complete();
9772
9936
  });
@@ -9794,14 +9958,14 @@ class RecordingService extends BasicRecordingService {
9794
9958
  });
9795
9959
  return wobs;
9796
9960
  }
9797
- fetchSprRecordingFileArrayAudioBuffer(aCtx, projectName, recordingFile) {
9961
+ fetchSprRecordingFileArrayAudioBuffer(projectName, recordingFile) {
9798
9962
  let wobs = new Observable(observer => {
9799
9963
  if (recordingFile.session) {
9800
9964
  let baseUrl = this.sprAudioFileUrl(projectName, recordingFile);
9801
9965
  if (baseUrl) {
9802
9966
  if (recordingFile.samplerate) {
9803
9967
  let lengthInSeconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9804
- let obs = this.chunkedAudioRequestToArrayBuffer(aCtx, baseUrl, recordingFile.samplerate, lengthInSeconds);
9968
+ let obs = this.chunkedAudioRequestToArrayBuffer(baseUrl, recordingFile.samplerate, lengthInSeconds);
9805
9969
  //let obs = this.fetchSprAudiofileArrayBuffer(aCtx,projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
9806
9970
  let subscr = obs.subscribe({
9807
9971
  next: aab => {
@@ -9838,14 +10002,14 @@ class RecordingService extends BasicRecordingService {
9838
10002
  });
9839
10003
  return wobs;
9840
10004
  }
9841
- fetchRecordingFileArrayAudioBuffer(aCtx, projectName, recordingFile) {
10005
+ fetchRecordingFileArrayAudioBuffer(projectName, recordingFile) {
9842
10006
  let wobs = new Observable(observer => {
9843
10007
  if (recordingFile.session) {
9844
10008
  let baseUrl = this.audioFileUrl(projectName, recordingFile);
9845
10009
  if (baseUrl) {
9846
10010
  if (recordingFile.samplerate) {
9847
10011
  let lengthInSeconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9848
- let obs = this.chunkedAudioRequestToArrayBuffer(aCtx, baseUrl, recordingFile.samplerate, lengthInSeconds);
10012
+ let obs = this.chunkedAudioRequestToArrayBuffer(baseUrl, recordingFile.samplerate, lengthInSeconds);
9849
10013
  //let obs = this.fetchSprAudiofileArrayBuffer(aCtx,projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
9850
10014
  let subscr = obs.subscribe({
9851
10015
  next: aab => {
@@ -9882,14 +10046,14 @@ class RecordingService extends BasicRecordingService {
9882
10046
  });
9883
10047
  return wobs;
9884
10048
  }
9885
- fetchSprRecordingFileIndDbAudioBuffer(aCtx, persistentAudioStorageTarget, projectName, recordingFile) {
10049
+ fetchSprRecordingFileIndDbAudioBuffer(persistentAudioStorageTarget, projectName, recordingFile) {
9886
10050
  let wobs = new Observable(observer => {
9887
10051
  if (recordingFile.session) {
9888
10052
  let baseUrl = this.sprAudioFileUrl(projectName, recordingFile);
9889
10053
  if (baseUrl) {
9890
10054
  if (recordingFile.samplerate) {
9891
10055
  let lengthInSeconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9892
- let obs = this.chunkedInddbAudioRequest(aCtx, persistentAudioStorageTarget, baseUrl, recordingFile.samplerate, lengthInSeconds);
10056
+ let obs = this.chunkedInddbAudioRequest(persistentAudioStorageTarget, baseUrl, recordingFile.samplerate, lengthInSeconds);
9893
10057
  let subscr = obs.subscribe({
9894
10058
  next: aab => {
9895
10059
  //console.debug("fetchSprRecordingFileIndDbAudioBuffer: observer.closed: "+observer.closed);
@@ -9925,14 +10089,14 @@ class RecordingService extends BasicRecordingService {
9925
10089
  });
9926
10090
  return wobs;
9927
10091
  }
9928
- fetchRecordingFileIndDbAudioBuffer(aCtx, persistentAudioStorageTarget, projectName, recordingFile) {
10092
+ fetchRecordingFileIndDbAudioBuffer(persistentAudioStorageTarget, projectName, recordingFile) {
9929
10093
  let wobs = new Observable(observer => {
9930
10094
  if (recordingFile.session) {
9931
10095
  let baseUrl = this.audioFileUrl(projectName, recordingFile);
9932
10096
  if (baseUrl) {
9933
10097
  if (recordingFile.samplerate) {
9934
10098
  let lengthInSeconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9935
- let obs = this.chunkedInddbAudioRequest(aCtx, persistentAudioStorageTarget, baseUrl, recordingFile.samplerate, lengthInSeconds);
10099
+ let obs = this.chunkedInddbAudioRequest(persistentAudioStorageTarget, baseUrl, recordingFile.samplerate, lengthInSeconds);
9936
10100
  let subscr = obs.subscribe({
9937
10101
  next: aab => {
9938
10102
  //console.debug("fetchSprRecordingFileIndDbAudioBuffer: observer.closed: "+observer.closed);
@@ -9968,14 +10132,14 @@ class RecordingService extends BasicRecordingService {
9968
10132
  });
9969
10133
  return wobs;
9970
10134
  }
9971
- fetchSprRecordingFileNetAudioBuffer(aCtx, projectName, recordingFile) {
10135
+ fetchSprRecordingFileNetAudioBuffer(projectName, recordingFile) {
9972
10136
  let wobs = new Observable(observer => {
9973
10137
  if (recordingFile.session) {
9974
10138
  let baseUrl = this.sprAudioFileUrl(projectName, recordingFile);
9975
10139
  if (baseUrl) {
9976
10140
  let seconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
9977
10141
  if (recordingFile.samplerate) {
9978
- let obs = this.chunkAudioRequestToNetAudioBuffer(aCtx, baseUrl, 0, recordingFile.samplerate, seconds, recordingFile.frames);
10142
+ let obs = this.chunkAudioRequestToNetAudioBuffer(baseUrl, 0, recordingFile.samplerate, seconds, recordingFile.frames);
9979
10143
  let subscr = obs.subscribe({
9980
10144
  next: aab => {
9981
10145
  //console.debug("fetchSprRecordingFileIndDbAudioBuffer: observer.closed: "+observer.closed);
@@ -10016,14 +10180,14 @@ class RecordingService extends BasicRecordingService {
10016
10180
  });
10017
10181
  return wobs;
10018
10182
  }
10019
- fetchRecordingFileNetAudioBuffer(aCtx, projectName, recordingFile) {
10183
+ fetchRecordingFileNetAudioBuffer(projectName, recordingFile) {
10020
10184
  let wobs = new Observable(observer => {
10021
10185
  if (recordingFile.session) {
10022
10186
  let baseUrl = this.audioFileUrl(projectName, recordingFile);
10023
10187
  if (baseUrl) {
10024
10188
  let seconds = RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
10025
10189
  if (recordingFile.samplerate) {
10026
- let obs = this.chunkAudioRequestToNetAudioBuffer(aCtx, baseUrl, 0, recordingFile.samplerate, seconds, recordingFile.frames);
10190
+ let obs = this.chunkAudioRequestToNetAudioBuffer(baseUrl, 0, recordingFile.samplerate, seconds, recordingFile.frames);
10027
10191
  let subscr = obs.subscribe({
10028
10192
  next: aab => {
10029
10193
  //console.debug("fetchSprRecordingFileIndDbAudioBuffer: observer.closed: "+observer.closed);
@@ -10068,83 +10232,87 @@ class RecordingService extends BasicRecordingService {
10068
10232
  let wobs = new Observable(observer => {
10069
10233
  if (recordingFile.session) {
10070
10234
  let obs = this.fetchSprAudiofile(projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
10071
- obs.subscribe(resp => {
10072
- //console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
10073
- // Do not use Promise version, which does not work with Safari 13 (13.0.5)
10235
+ obs.subscribe({
10236
+ next: resp => {
10237
+ //console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
10238
+ // Do not use Promise version, which does not work with Safari 13 (13.0.5)
10239
+ if (resp.body) {
10240
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
10241
+ let abs = new AudioBufferSource(ab);
10242
+ RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(abs));
10243
+ if (this.debugDelay > 0) {
10244
+ window.setTimeout(() => {
10245
+ observer.next(recordingFile);
10246
+ observer.complete();
10247
+ }, this.debugDelay);
10248
+ }
10249
+ else {
10250
+ observer.next(recordingFile);
10251
+ observer.complete();
10252
+ }
10253
+ }).catch(error => {
10254
+ observer.error(error);
10255
+ observer.complete();
10256
+ });
10257
+ }
10258
+ else {
10259
+ observer.error('Fetching audio file: response has no body');
10260
+ }
10261
+ },
10262
+ error: (err) => {
10263
+ if (err instanceof HttpErrorResponse && err.status == 404) {
10264
+ // Interpret not as an error, the file ist not recorded yet
10265
+ observer.next(null);
10266
+ observer.complete();
10267
+ }
10268
+ else {
10269
+ // all other states are errors
10270
+ observer.error(err);
10271
+ }
10272
+ }
10273
+ });
10274
+ }
10275
+ else {
10276
+ observer.error();
10277
+ }
10278
+ });
10279
+ return wobs;
10280
+ }
10281
+ fetchRecordingFile(aCtx, projectName, sessId, itemcode, version) {
10282
+ let wobs = new Observable(observer => {
10283
+ let obs = this.fetchSprAudiofile(projectName, sessId, itemcode, version);
10284
+ obs.subscribe({ next: resp => {
10074
10285
  if (resp.body) {
10075
- aCtx.decodeAudioData(resp.body, ab => {
10286
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
10076
10287
  let abs = new AudioBufferSource(ab);
10077
- RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(abs));
10288
+ let adh = new AudioDataHolder(abs);
10289
+ let rf = new SprRecordingFile(sessId, itemcode, version, adh);
10078
10290
  if (this.debugDelay > 0) {
10079
10291
  window.setTimeout(() => {
10080
- observer.next(recordingFile);
10292
+ observer.next(rf);
10081
10293
  observer.complete();
10082
10294
  }, this.debugDelay);
10083
10295
  }
10084
10296
  else {
10085
- observer.next(recordingFile);
10297
+ observer.next(rf);
10086
10298
  observer.complete();
10087
10299
  }
10088
- }, error => {
10089
- observer.error(error);
10090
- observer.complete();
10091
- });
10300
+ }).catch((reason) => { observer.error(reason); });
10092
10301
  }
10093
10302
  else {
10094
- observer.error('Fetching audio file: response has no body');
10303
+ observer.error();
10095
10304
  }
10096
- }, (err) => {
10305
+ },
10306
+ error: (err) => {
10097
10307
  if (err instanceof HttpErrorResponse && err.status == 404) {
10098
10308
  // Interpret not as an error, the file ist not recorded yet
10099
10309
  observer.next(null);
10100
10310
  observer.complete();
10101
10311
  }
10102
10312
  else {
10103
- // all other states are errors
10313
+ // all other errors are real errors
10104
10314
  observer.error(err);
10105
10315
  }
10106
- });
10107
- }
10108
- else {
10109
- observer.error();
10110
- }
10111
- });
10112
- return wobs;
10113
- }
10114
- fetchRecordingFile(aCtx, projectName, sessId, itemcode, version) {
10115
- let wobs = new Observable(observer => {
10116
- let obs = this.fetchSprAudiofile(projectName, sessId, itemcode, version);
10117
- obs.subscribe(resp => {
10118
- // Do not use Promise version, which does not work with Safari 13
10119
- if (resp.body) {
10120
- aCtx.decodeAudioData(resp.body, ab => {
10121
- let abs = new AudioBufferSource(ab);
10122
- let adh = new AudioDataHolder(abs);
10123
- let rf = new SprRecordingFile(sessId, itemcode, version, adh);
10124
- if (this.debugDelay > 0) {
10125
- window.setTimeout(() => {
10126
- observer.next(rf);
10127
- observer.complete();
10128
- }, this.debugDelay);
10129
- }
10130
- else {
10131
- observer.next(rf);
10132
- observer.complete();
10133
- }
10134
- });
10135
- }
10136
- else {
10137
- observer.error();
10138
- }
10139
- }, (err) => {
10140
- if (err instanceof HttpErrorResponse && err.status == 404) {
10141
- // Interpret not as an error, the file ist not recorded yet
10142
- observer.next(null);
10143
- observer.complete();
10144
- }
10145
- else {
10146
- // all other errors are real errors
10147
- observer.error(err);
10148
10316
  }
10149
10317
  });
10150
10318
  });
@@ -10166,23 +10334,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
10166
10334
  }] }];
10167
10335
  } });
10168
10336
 
10169
- class AudioContextProvider {
10170
- static audioContextInstance() {
10171
- if (!this._audioContext) {
10172
- let debugFail = false;
10173
- if (!window.AudioContext || typeof window.AudioContext !== 'function' || debugFail) {
10174
- throw new Error('Browser does not support Web Audio API!');
10175
- this._audioContext = null;
10176
- }
10177
- else {
10178
- this._audioContext = new window.AudioContext();
10179
- }
10180
- }
10181
- return this._audioContext;
10182
- }
10183
- }
10184
- AudioContextProvider._audioContext = null;
10185
-
10186
10337
  class Item {
10187
10338
  constructor(_promptAsString, _training, _recording) {
10188
10339
  this._promptAsString = _promptAsString;
@@ -10605,7 +10756,7 @@ class UploadStatus {
10605
10756
  constructor() {
10606
10757
  this._awaitNewUpload = false;
10607
10758
  this.spinnerMode = 'determinate';
10608
- this._colorStatus = 'primary';
10759
+ this.colorStatus = 'primary';
10609
10760
  this._value = 100;
10610
10761
  this.displayValue = null;
10611
10762
  this.toolTipText = '';
@@ -10644,13 +10795,13 @@ class UploadStatus {
10644
10795
  set status(status) {
10645
10796
  this._status = status;
10646
10797
  if ('accent' === status) {
10647
- this._colorStatus = 'accent';
10798
+ this.colorStatus = 'accent';
10648
10799
  }
10649
10800
  else if ('warn' === status) {
10650
- this._colorStatus = 'warn';
10801
+ this.colorStatus = 'warn';
10651
10802
  }
10652
10803
  else {
10653
- this._colorStatus = 'primary';
10804
+ this.colorStatus = 'primary';
10654
10805
  }
10655
10806
  this._updateSpinner();
10656
10807
  }
@@ -10660,12 +10811,14 @@ class UploadStatus {
10660
10811
  }
10661
10812
  UploadStatus.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UploadStatus, deps: [], target: i0.ɵɵFactoryTarget.Component });
10662
10813
  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: `
10663
- <mat-progress-spinner [mode]="spinnerMode" [color]="status" [diameter]="30" [strokeWidth]="5" [value]="_value" [matTooltip]="toolTipText"></mat-progress-spinner>
10814
+ <mat-progress-spinner [mode]="spinnerMode" [color]="colorStatus" [diameter]="30" [strokeWidth]="5" [value]="_value"
10815
+ [matTooltip]="toolTipText"></mat-progress-spinner>
10664
10816
  `, 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"] }] });
10665
10817
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UploadStatus, decorators: [{
10666
10818
  type: Component,
10667
10819
  args: [{ selector: 'app-uploadstatus', template: `
10668
- <mat-progress-spinner [mode]="spinnerMode" [color]="status" [diameter]="30" [strokeWidth]="5" [value]="_value" [matTooltip]="toolTipText"></mat-progress-spinner>
10820
+ <mat-progress-spinner [mode]="spinnerMode" [color]="colorStatus" [diameter]="30" [strokeWidth]="5" [value]="_value"
10821
+ [matTooltip]="toolTipText"></mat-progress-spinner>
10669
10822
  `, styles: [":host{text-align:left}\n", "mat-progress-spinner{display:inline-block}\n"] }]
10670
10823
  }], propDecorators: { value: [{
10671
10824
  type: Input
@@ -10774,7 +10927,7 @@ class TransportPanel extends ResponsiveComponent {
10774
10927
  }
10775
10928
  }
10776
10929
  }
10777
- 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 });
10930
+ 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 });
10778
10931
  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: `
10779
10932
  <button id="bwdBtn" *ngIf="navigationEnabled" (click)="actions.bwdAction.perform()" [disabled]="bwdDisabled()"
10780
10933
  mat-raised-button>
@@ -10819,7 +10972,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
10819
10972
  </button>
10820
10973
 
10821
10974
  `, 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"] }]
10822
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }]; }, propDecorators: { readonly: [{
10975
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }]; }, propDecorators: { readonly: [{
10823
10976
  type: Input
10824
10977
  }], actions: [{
10825
10978
  type: Input
@@ -10891,7 +11044,7 @@ class ControlPanel extends ResponsiveComponent {
10891
11044
  return this._ready;
10892
11045
  }
10893
11046
  }
10894
- 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 });
11047
+ 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 });
10895
11048
  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: `
10896
11049
  <div *ngIf="!screenXs" style="flex-direction: row" >
10897
11050
  <app-sprstatusdisplay style="flex:0 0 0" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
@@ -10901,9 +11054,9 @@ ControlPanel.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version:
10901
11054
  [status]="uploadStatus" [awaitNewUpload]="processing"></app-uploadstatus>
10902
11055
  <app-readystateindicator [ready]="_ready"></app-readystateindicator>
10903
11056
  </div>
10904
- <div *ngIf="screenXs"style="flex-direction: column" >
11057
+ <div *ngIf="screenXs" style="flex-direction: column" >
10905
11058
  <div style="flex-direction: row" class="flexFill" >
10906
- <app-sprstatusdisplay style="flex:10 0 0;flex-align:left" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
11059
+ <app-sprstatusdisplay style="flex:10 0 0" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
10907
11060
  class="hidden-xs"></app-sprstatusdisplay>
10908
11061
  <app-uploadstatus style="flex:0 0 0" *ngIf="enableUploadRecordings" [value]="uploadProgress"
10909
11062
  [status]="uploadStatus" [awaitNewUpload]="processing"></app-uploadstatus>
@@ -10924,9 +11077,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
10924
11077
  [status]="uploadStatus" [awaitNewUpload]="processing"></app-uploadstatus>
10925
11078
  <app-readystateindicator [ready]="_ready"></app-readystateindicator>
10926
11079
  </div>
10927
- <div *ngIf="screenXs"style="flex-direction: column" >
11080
+ <div *ngIf="screenXs" style="flex-direction: column" >
10928
11081
  <div style="flex-direction: row" class="flexFill" >
10929
- <app-sprstatusdisplay style="flex:10 0 0;flex-align:left" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
11082
+ <app-sprstatusdisplay style="flex:10 0 0" [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"
10930
11083
  class="hidden-xs"></app-sprstatusdisplay>
10931
11084
  <app-uploadstatus style="flex:0 0 0" *ngIf="enableUploadRecordings" [value]="uploadProgress"
10932
11085
  [status]="uploadStatus" [awaitNewUpload]="processing"></app-uploadstatus>
@@ -10936,7 +11089,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
10936
11089
 
10937
11090
  </div>
10938
11091
  `, styles: ["div{align-content:center;align-items:center;margin:0;padding:20px;min-height:min-content}\n"] }]
10939
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }, { type: i1$4.MatDialog }]; }, propDecorators: { statusDisplay: [{
11092
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }, { type: i1$3.MatDialog }]; }, propDecorators: { statusDisplay: [{
10940
11093
  type: ViewChild,
10941
11094
  args: [StatusDisplay, { static: true }]
10942
11095
  }], transportPanel: [{
@@ -11591,7 +11744,7 @@ class RecordingItemControls extends ResponsiveComponent {
11591
11744
  // this.status = 'ERROR';
11592
11745
  }
11593
11746
  }
11594
- 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 });
11747
+ 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 });
11595
11748
  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: `
11596
11749
  <button matTooltip="Start playback" (click)="playStartAction?.perform()"
11597
11750
  [disabled]="playStartAction?.disabled"
@@ -11640,7 +11793,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
11640
11793
  [style.color]="(peakDbLvl > warnDbLevel)?'red':'black'">{{peakDbLvl | number:'1.1-1'}} dB </span></td></tr>
11641
11794
  <tr *ngIf="_agc"><td>AGC:</td><td><span matTooltip="Auto gain control">{{agcString}}</span></td></tr></table></div>
11642
11795
  `, 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"] }]
11643
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { audioSignalCollapsed: [{
11796
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { audioSignalCollapsed: [{
11644
11797
  type: Input
11645
11798
  }], enableDownload: [{
11646
11799
  type: Input
@@ -11721,7 +11874,7 @@ class RecordingItemDisplay extends ResponsiveComponent {
11721
11874
  let peakDBVal = levelInfo.powerLevelDB();
11722
11875
  if (this.peakDbLvl < peakDBVal) {
11723
11876
  this.peakDbLvl = peakDBVal;
11724
- // the event comes from outside of an Angular zone
11877
+ // the event comes from outside an Angular zone
11725
11878
  this.changeDetectorRef.detectChanges();
11726
11879
  }
11727
11880
  this.liveLevel.update(levelInfo);
@@ -11737,7 +11890,7 @@ class RecordingItemDisplay extends ResponsiveComponent {
11737
11890
  this.changeDetectorRef.detectChanges();
11738
11891
  }
11739
11892
  }
11740
- 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 });
11893
+ 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 });
11741
11894
  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: `
11742
11895
  <div [class]="{audioStatusDisplay:!screenXs,audioStatusDisplayXs:screenXs}">
11743
11896
  <audio-levelbar style="flex:1 0 1%" [streamingMode]="streamingMode" [displayLevelInfos]="_displayLevelInfos"></audio-levelbar>
@@ -11752,7 +11905,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
11752
11905
  <spr-recordingitemcontrols style="flex:0 0 0px" [audioLoaded]="displayAudioBuffer!==null" [playStartAction]="playStartAction" [playStopAction]="playStopAction" [peakDbLvl]="peakDbLvl" [agc]="_agc" (onShowRecordingDetails)="onShowRecordingDetails.emit()"></spr-recordingitemcontrols>
11753
11906
  </div>
11754
11907
  `, 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"] }]
11755
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { liveLevel: [{
11908
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { liveLevel: [{
11756
11909
  type: ViewChild,
11757
11910
  args: [LevelBar, { static: true }]
11758
11911
  }], streamingMode: [{
@@ -12056,6 +12209,7 @@ let BasicRecorder = class BasicRecorder extends ResponsiveComponent {
12056
12209
  this._wakeLock = false;
12057
12210
  this._selectedDeviceId = undefined;
12058
12211
  this._channelCount = 2;
12212
+ this._allowEchoCancellation = false;
12059
12213
  this._session = null;
12060
12214
  this._recordingFile = null;
12061
12215
  this.startedDate = null;
@@ -12097,6 +12251,12 @@ let BasicRecorder = class BasicRecorder extends ResponsiveComponent {
12097
12251
  this.streamLevelMeasure = new StreamLevelMeasure();
12098
12252
  this.selCaptureDeviceId = null;
12099
12253
  }
12254
+ get allowEchoCancellation() {
12255
+ return this._allowEchoCancellation;
12256
+ }
12257
+ set allowEchoCancellation(value) {
12258
+ this._allowEchoCancellation = value;
12259
+ }
12100
12260
  get maxAutoNetMemStoreSamples() {
12101
12261
  return this._maxAutoNetMemStoreSamples;
12102
12262
  }
@@ -12482,7 +12642,7 @@ let BasicRecorder = class BasicRecorder extends ResponsiveComponent {
12482
12642
  else {
12483
12643
  console.log("Open session with default audio device for " + this._channelCount + " channels");
12484
12644
  }
12485
- this.ac.open(this._channelCount, this._selectedDeviceId, this._autoGainControlConfigs);
12645
+ this.ac.open(this._channelCount, this._selectedDeviceId, this._autoGainControlConfigs, this._allowEchoCancellation);
12486
12646
  }
12487
12647
  else {
12488
12648
  this.ac.start();
@@ -12842,6 +13002,7 @@ class SessionManager extends BasicRecorder {
12842
13002
  this.bpo = bpo;
12843
13003
  this.renderer = renderer;
12844
13004
  this.recFileService = recFileService;
13005
+ this.offlineAudioContext = null;
12845
13006
  this.enableUploadRecordings = true;
12846
13007
  this.enableDownloadRecordings = false;
12847
13008
  this.status = 0 /* BLOCKED */;
@@ -12898,37 +13059,58 @@ class SessionManager extends BasicRecorder {
12898
13059
  this.transportActions.nextAction.disabled = true;
12899
13060
  this.transportActions.pauseAction.disabled = true;
12900
13061
  this.playStartAction.disabled = true;
12901
- let context = null;
12902
- try {
12903
- context = AudioContextProvider.audioContextInstance();
12904
- }
12905
- catch (err) {
12906
- this.status = 9 /* ERROR */;
12907
- let errMsg = 'Unknown error';
12908
- if (err instanceof Error) {
12909
- errMsg = err.message;
12910
- }
12911
- this.statusMsg = 'ERROR: ' + errMsg;
12912
- this.statusAlertType = 'error';
12913
- this.dialog.open(MessageDialog, {
12914
- data: {
12915
- type: 'error',
12916
- title: 'Error',
12917
- msg: errMsg,
12918
- advice: 'Please use a supported browser.',
12919
- }
12920
- });
12921
- return;
12922
- }
12923
- if (context) {
12924
- console.info("State of audio context: " + context.state);
13062
+ // let context:AudioContext|null=null;
13063
+ // try {
13064
+ // context = AudioContextProvider.audioContextInstance();
13065
+ // } catch (err) {
13066
+ // this.status = Status.ERROR;
13067
+ // let errMsg = 'Unknown error';
13068
+ // if(err instanceof Error){
13069
+ // errMsg=err.message;
13070
+ // }
13071
+ // this.statusMsg = 'ERROR: ' + errMsg;
13072
+ // this.statusAlertType = 'error';
13073
+ // this.dialog.open(MessageDialog, {
13074
+ // data: {
13075
+ // type: 'error',
13076
+ // title: 'Error',
13077
+ // msg: errMsg,
13078
+ // advice: 'Please use a supported browser.',
13079
+ // }
13080
+ // });
13081
+ // return;
13082
+ // }
13083
+ // if(context) {
13084
+ // console.info("State of audio context: " + context.state)
13085
+ // }else{
13086
+ // console.info("No audio context available!");
13087
+ // }
13088
+ // if (!context || !navigator.mediaDevices) {
13089
+ // this.status = Status.ERROR;
13090
+ // let errMsg = 'Browser does not support Media streams!';
13091
+ // this.statusMsg = 'ERROR: ' + errMsg;
13092
+ // this.statusAlertType = 'error';
13093
+ // this.dialog.open(MessageDialog, {
13094
+ // data: {
13095
+ // type: 'error',
13096
+ // title: 'Error',
13097
+ // msg: errMsg,
13098
+ // advice: 'Please use a supported browser.',
13099
+ // }
13100
+ // });
13101
+ // return;
13102
+ // } else {
13103
+ this.ac = new AudioCapture();
13104
+ if (this.ac) {
13105
+ this.transportActions.startAction.onAction = () => this.startItem();
13106
+ this.ac.listener = this;
13107
+ this.configureStreamCaptureStream();
13108
+ // Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
13109
+ //this.ac.listDevices();
12925
13110
  }
12926
13111
  else {
12927
- console.info("No audio context available!");
12928
- }
12929
- if (!context || !navigator.mediaDevices) {
12930
- this.status = 9 /* ERROR */;
12931
- let errMsg = 'Browser does not support Media streams!';
13112
+ this.transportActions.startAction.disabled = true;
13113
+ let errMsg = 'Browser does not support Media/Audio API!';
12932
13114
  this.statusMsg = 'ERROR: ' + errMsg;
12933
13115
  this.statusAlertType = 'error';
12934
13116
  this.dialog.open(MessageDialog, {
@@ -12941,38 +13123,13 @@ class SessionManager extends BasicRecorder {
12941
13123
  });
12942
13124
  return;
12943
13125
  }
12944
- else {
12945
- this.ac = new AudioCapture(context);
12946
- if (this.ac) {
12947
- this.transportActions.startAction.onAction = () => this.startItem();
12948
- this.ac.listener = this;
12949
- this.configureStreamCaptureStream();
12950
- // Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
12951
- //this.ac.listDevices();
12952
- }
12953
- else {
12954
- this.transportActions.startAction.disabled = true;
12955
- let errMsg = 'Browser does not support Media/Audio API!';
12956
- this.statusMsg = 'ERROR: ' + errMsg;
12957
- this.statusAlertType = 'error';
12958
- this.dialog.open(MessageDialog, {
12959
- data: {
12960
- type: 'error',
12961
- title: 'Error',
12962
- msg: errMsg,
12963
- advice: 'Please use a supported browser.',
12964
- }
12965
- });
12966
- return;
12967
- }
12968
- this.transportActions.stopAction.onAction = () => this.stopItem();
12969
- this.transportActions.nextAction.onAction = () => this.stopItem();
12970
- this.transportActions.pauseAction.onAction = () => this.pauseItem();
12971
- this.transportActions.fwdAction.onAction = () => this.nextItem();
12972
- this.transportActions.fwdNextAction.onAction = () => this.nextUnrecordedItem();
12973
- this.transportActions.bwdAction.onAction = () => this.prevItem();
12974
- this.playStartAction.onAction = () => { var _a; return (_a = this.controlAudioPlayer) === null || _a === void 0 ? void 0 : _a.start(); };
12975
- }
13126
+ this.transportActions.stopAction.onAction = () => this.stopItem();
13127
+ this.transportActions.nextAction.onAction = () => this.stopItem();
13128
+ this.transportActions.pauseAction.onAction = () => this.pauseItem();
13129
+ this.transportActions.fwdAction.onAction = () => this.nextItem();
13130
+ this.transportActions.fwdNextAction.onAction = () => this.nextUnrecordedItem();
13131
+ this.transportActions.bwdAction.onAction = () => this.prevItem();
13132
+ this.playStartAction.onAction = () => { var _a; return (_a = this.controlAudioPlayer) === null || _a === void 0 ? void 0 : _a.start(); };
12976
13133
  this.startStopSignalState = 4 /* OFF */;
12977
13134
  }
12978
13135
  onKeyPress(ke) {
@@ -13279,7 +13436,7 @@ class SessionManager extends BasicRecorder {
13279
13436
  }
13280
13437
  else {
13281
13438
  //console.debug("Fetch audio and store to indexed db...");
13282
- this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileIndDbAudioBuffer(this._controlAudioPlayer.context, this._persistentAudioStorageTarget, this._session.project, rf).subscribe({
13439
+ this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileIndDbAudioBuffer(this._persistentAudioStorageTarget, this._session.project, rf).subscribe({
13283
13440
  next: (iab) => {
13284
13441
  //console.debug("Sessionmanager: Received inddb audio buffer: "+iab);
13285
13442
  nextIab = iab;
@@ -13321,7 +13478,7 @@ class SessionManager extends BasicRecorder {
13321
13478
  // Fetch chunked audio buffer from network
13322
13479
  let nextNetAb = null;
13323
13480
  //console.debug("Fetch chunked audio from network");
13324
- this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileNetAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
13481
+ this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileNetAudioBuffer(this._session.project, rf).subscribe({
13325
13482
  next: (netAb) => {
13326
13483
  //console.debug("Sessionmanager: Received net audio buffer: "+netAb);
13327
13484
  nextNetAb = netAb;
@@ -13363,7 +13520,7 @@ class SessionManager extends BasicRecorder {
13363
13520
  // Fetch chunked array audio buffer
13364
13521
  let nextAab = null;
13365
13522
  //console.debug("Fetch audio and store to (chunked) array buffer...");
13366
- this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileArrayAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
13523
+ this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileArrayAudioBuffer(this._session.project, rf).subscribe({
13367
13524
  next: (aab) => {
13368
13525
  nextAab = aab;
13369
13526
  },
@@ -13401,7 +13558,7 @@ class SessionManager extends BasicRecorder {
13401
13558
  else {
13402
13559
  // Fetch regular audio buffer
13403
13560
  //console.debug("Fetch audio and store to audio buffer...");
13404
- this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
13561
+ this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileAudioBuffer(this._session.project, rf).subscribe({
13405
13562
  next: (ab) => {
13406
13563
  this.liveLevelDisplayState = State.READY;
13407
13564
  let fabDh = null;
@@ -13789,7 +13946,7 @@ class SessionManager extends BasicRecorder {
13789
13946
  const sr = this.ac.currentSampleRate;
13790
13947
  const chFl = sr * RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
13791
13948
  //console.debug("stopped(): rfID: "+this._recordingFile?.recordingFileId+", net ab url: " + burl+", frames: "+this.ac.framesRecorded+", sample rate: "+sr);
13792
- let netAb = new NetAudioBuffer(this.ac.context, this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
13949
+ let netAb = new NetAudioBuffer(this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
13793
13950
  as = netAb;
13794
13951
  if (this.uploadSet) {
13795
13952
  //let rp=new ReadyProvider();
@@ -13836,7 +13993,7 @@ class SessionManager extends BasicRecorder {
13836
13993
  const sr = this.ac.currentSampleRate;
13837
13994
  const chFl = sr * RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
13838
13995
  //console.debug("stopped(): rfID: "+this._recordingFile?.recordingFileId+", net ab url: " + burl+", frames: "+this.ac.framesRecorded+", sample rate: "+sr);
13839
- const netAb = new NetAudioBuffer(this.ac.context, this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
13996
+ const netAb = new NetAudioBuffer(this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
13840
13997
  as = netAb;
13841
13998
  if (this.uploadSet) {
13842
13999
  this.uploadSet.onDone = (uploadSet) => {
@@ -13874,8 +14031,8 @@ class SessionManager extends BasicRecorder {
13874
14031
  // TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
13875
14032
  // TODO duplicate conversion for manual download
13876
14033
  //console.log("Build wav writer...");
13877
- this.processingRecording = true;
13878
14034
  if (ab) {
14035
+ this.processingRecording = true;
13879
14036
  let ww = new WavWriter();
13880
14037
  //new REST API URL
13881
14038
  let apiEndPoint = '';
@@ -14011,7 +14168,7 @@ class SessionManager extends BasicRecorder {
14011
14168
  }
14012
14169
  }
14013
14170
  }
14014
- 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 });
14171
+ 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 });
14015
14172
  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: `
14016
14173
  <app-warningbar [show]="isTestSession()" warningText="Test recording only!"></app-warningbar>
14017
14174
  <app-warningbar [show]="isDefaultAudioTestSession()" warningText="This test uses default audio device! Regular sessions may require a particular audio device (microphone)!"></app-warningbar>
@@ -14115,7 +14272,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
14115
14272
  </div>
14116
14273
  `, 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"] }]
14117
14274
  }], ctorParameters: function () {
14118
- return [{ type: i1$3.BreakpointObserver }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i1$4.MatDialog }, { type: SessionService }, { type: RecordingService }, { type: SpeechRecorderUploader }, { type: SpeechRecorderConfig, decorators: [{
14275
+ return [{ type: i1$2.BreakpointObserver }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i1$3.MatDialog }, { type: SessionService }, { type: RecordingService }, { type: SpeechRecorderUploader }, { type: SpeechRecorderConfig, decorators: [{
14119
14276
  type: Inject,
14120
14277
  args: [SPEECHRECORDER_CONFIG]
14121
14278
  }] }];
@@ -14388,18 +14545,10 @@ class SpeechrecorderngComponent extends RecorderComponent {
14388
14545
  console.error(errMsg);
14389
14546
  }
14390
14547
  ngOnInit() {
14391
- try {
14392
- let audioContext = AudioContextProvider.audioContextInstance();
14393
- if (audioContext) {
14394
- this.controlAudioPlayer = new AudioPlayer(audioContext, this);
14395
- }
14396
- this.sm.controlAudioPlayer = this.controlAudioPlayer;
14397
- this.sm.statusAlertType = 'info';
14398
- this.sm.statusMsg = 'Player initialized.';
14399
- }
14400
- catch (err) {
14401
- this.handleError(err);
14402
- }
14548
+ this.controlAudioPlayer = new AudioPlayer(this);
14549
+ this.sm.controlAudioPlayer = this.controlAudioPlayer;
14550
+ this.sm.statusAlertType = 'info';
14551
+ this.sm.statusMsg = 'Player initialized.';
14403
14552
  }
14404
14553
  ngAfterViewInit() {
14405
14554
  // let wakeLockSupp=('wakeLock' in navigator);
@@ -14564,7 +14713,7 @@ class SpeechrecorderngComponent extends RecorderComponent {
14564
14713
  }
14565
14714
  else {
14566
14715
  // all this attempts to customize the message do not work anymore (for security reasons)!!
14567
- var message = "Please do not leave the page, until all recordings are uploaded!";
14716
+ const message = "Please do not leave the page, until all recordings are uploaded!";
14568
14717
  alert(message);
14569
14718
  e = e || window.event;
14570
14719
  if (e) {
@@ -14656,6 +14805,9 @@ class SpeechrecorderngComponent extends RecorderComponent {
14656
14805
  chCnt = ProjectUtil.audioChannelCount(project);
14657
14806
  console.info("Project requested recording channel count: " + chCnt);
14658
14807
  this.sm.autoGainControlConfigs = project.autoGainControlConfigs;
14808
+ if (project.allowEchoCancellation !== undefined) {
14809
+ this.sm.allowEchoCancellation = project.allowEchoCancellation;
14810
+ }
14659
14811
  if (project.chunkedRecording === true) {
14660
14812
  console.debug("Enable chunked upload: chunkSize: " + BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS);
14661
14813
  this.sm.uploadChunkSizeSeconds = BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS;
@@ -14688,7 +14840,7 @@ class SpeechrecorderngComponent extends RecorderComponent {
14688
14840
  projUrl = window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/wikispeech/rest/projects/?sessionId=' + this.sessionId;
14689
14841
  }
14690
14842
  if (projUrl) {
14691
- var pLoader = new XMLHttpRequest();
14843
+ const pLoader = new XMLHttpRequest();
14692
14844
  pLoader.open("GET", projUrl, true);
14693
14845
  pLoader.setRequestHeader('Accept', 'application/json');
14694
14846
  pLoader.responseType = "json";
@@ -14723,7 +14875,7 @@ class SpeechrecorderngComponent extends RecorderComponent {
14723
14875
  this.sm.statusMsg = 'ERROR: Recording.';
14724
14876
  }
14725
14877
  }
14726
- 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 });
14878
+ 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 });
14727
14879
  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: `
14728
14880
  <app-sprrecordingsession [projectName]="project?.name" [dataSaved]="dataSaved"></app-sprrecordingsession>
14729
14881
  `, 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"] }] });
@@ -14732,7 +14884,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
14732
14884
  args: [{ selector: 'app-speechrecorder', providers: [SessionService], template: `
14733
14885
  <app-sprrecordingsession [projectName]="project?.name" [dataSaved]="dataSaved"></app-sprrecordingsession>
14734
14886
  `, styles: [":host{flex:2;display:flex;flex-direction:column;min-height:0}\n"] }]
14735
- }], 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: [{
14887
+ }], 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: [{
14736
14888
  type: ViewChild,
14737
14889
  args: [SessionManager, { static: true }]
14738
14890
  }] } });
@@ -14752,10 +14904,8 @@ class AudioDisplayPlayer {
14752
14904
  this.ref = ref;
14753
14905
  this.eRef = eRef;
14754
14906
  this._audioUrl = null;
14755
- this.aCtx = null;
14756
14907
  this._audioClip = null;
14757
14908
  this.currentLoader = null;
14758
- //console.log("constructor: "+this.ac);
14759
14909
  this.parentE = this.eRef.nativeElement;
14760
14910
  this.playStartAction = new Action("Start");
14761
14911
  this.playSelectionAction = new Action("Play selected");
@@ -14763,26 +14913,19 @@ class AudioDisplayPlayer {
14763
14913
  this.status = "Player created.";
14764
14914
  }
14765
14915
  ngOnInit() {
14766
- //console.log("OnInit: "+this.ac);
14767
14916
  this.zoomSelectedAction = this.audioDisplayScrollPane.zoomSelectedAction;
14768
14917
  this.zoomFitToPanelAction = this.audioDisplayScrollPane.zoomFitToPanelAction;
14769
14918
  this.zoomOutAction = this.audioDisplayScrollPane.zoomOutAction;
14770
14919
  this.zoomInAction = this.audioDisplayScrollPane.zoomInAction;
14771
- try {
14772
- this.aCtx = AudioContextProvider.audioContextInstance();
14773
- if (this.aCtx) {
14774
- this.ap = new AudioPlayer(this.aCtx, this);
14775
- }
14776
- }
14777
- catch (err) {
14778
- if (err instanceof Error) {
14779
- this.status = err.message;
14780
- }
14781
- }
14920
+ this.ap = new AudioPlayer(this);
14782
14921
  }
14783
14922
  ngAfterViewInit() {
14784
- if (this.aCtx && this.ap) {
14785
- this.playStartAction.onAction = () => { var _a; return (_a = this.ap) === null || _a === void 0 ? void 0 : _a.start(); };
14923
+ if (this.ap) {
14924
+ this.playStartAction.onAction = () => {
14925
+ var _a;
14926
+ console.debug("Start action, player: " + this.ap);
14927
+ (_a = this.ap) === null || _a === void 0 ? void 0 : _a.start();
14928
+ };
14786
14929
  this.playSelectionAction.onAction = () => { var _a; return (_a = this.ap) === null || _a === void 0 ? void 0 : _a.startSelected(); };
14787
14930
  this.playStopAction.onAction = () => { var _a; return (_a = this.ap) === null || _a === void 0 ? void 0 : _a.stop(); };
14788
14931
  }
@@ -14847,15 +14990,12 @@ class AudioDisplayPlayer {
14847
14990
  //console.debug("Loaded");
14848
14991
  this.status = 'Audio file loaded.';
14849
14992
  //console.debug("Received data ", data.byteLength);
14850
- // Do not use Promise version, which does not work with Safari 13
14851
- if (this.aCtx) {
14852
- this.aCtx.decodeAudioData(data, (audioBuffer) => {
14853
- //console.debug("Audio Buffer Samplerate: ", audioBuffer.sampleRate)
14854
- let as = new AudioBufferSource(audioBuffer);
14855
- let adh = new AudioDataHolder(as);
14856
- this.audioClip = new AudioClip(adh);
14857
- });
14858
- }
14993
+ AudioContextProvider.decodeAudioData(data).then(audioBuffer => {
14994
+ //console.debug("Audio Buffer Samplerate: ", audioBuffer.sampleRate)
14995
+ let as = new AudioBufferSource(audioBuffer);
14996
+ let adh = new AudioDataHolder(as);
14997
+ this.audioClip = new AudioClip(adh);
14998
+ });
14859
14999
  }
14860
15000
  set audioData(audioData) {
14861
15001
  this.audioDisplayScrollPane.audioData = audioData;
@@ -14938,7 +15078,7 @@ class AudioDisplayPlayer {
14938
15078
  this.status = 'ERROR';
14939
15079
  }
14940
15080
  }
14941
- 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 });
15081
+ 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 });
14942
15082
  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: `
14943
15083
 
14944
15084
  <audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
@@ -14969,7 +15109,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
14969
15109
  [zoomSelectedAction]="zoomSelectedAction"
14970
15110
  [zoomFitToPanelAction]="zoomFitToPanelAction"></audio-display-control><p>{{status}}
14971
15111
  `, 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"] }]
14972
- }], ctorParameters: function () { return [{ type: i1$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { playStartAction: [{
15112
+ }], ctorParameters: function () { return [{ type: i4$2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { playStartAction: [{
14973
15113
  type: Input
14974
15114
  }], playStopAction: [{
14975
15115
  type: Input
@@ -15115,41 +15255,42 @@ class RecordingFileService extends BasicRecordingService {
15115
15255
  });
15116
15256
  }
15117
15257
  // TODO test
15118
- fetchAndApplyRecordingFile(aCtx, recordingFile) {
15258
+ fetchAndApplyRecordingFile(recordingFile) {
15119
15259
  let wobs = new Observable(observer => {
15120
15260
  if (recordingFile.recordingFileId) {
15121
15261
  let obs = this.fetchAudiofile(recordingFile.recordingFileId);
15122
- obs.subscribe(resp => {
15123
- // Do not use Promise version, which does not work with Safari 13
15124
- if (resp.body) {
15125
- aCtx.decodeAudioData(resp.body, ab => {
15126
- let as = new AudioBufferSource(ab);
15127
- RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(as));
15128
- if (this.debugDelay > 0) {
15129
- window.setTimeout(() => {
15262
+ obs.subscribe({ next: resp => {
15263
+ if (resp.body) {
15264
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
15265
+ let as = new AudioBufferSource(ab);
15266
+ RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(as));
15267
+ if (this.debugDelay > 0) {
15268
+ window.setTimeout(() => {
15269
+ observer.next(recordingFile);
15270
+ observer.complete();
15271
+ }, this.debugDelay);
15272
+ }
15273
+ else {
15130
15274
  observer.next(recordingFile);
15131
15275
  observer.complete();
15132
- }, this.debugDelay);
15133
- }
15134
- else {
15135
- observer.next(recordingFile);
15136
- observer.complete();
15137
- }
15138
- });
15139
- }
15140
- else {
15141
- observer.error('Received no audio data!');
15142
- }
15143
- }, (error) => {
15144
- if (error.status == 404) {
15145
- // Interpret not as an error, the file ist not recorded yet
15146
- observer.next(null);
15147
- observer.complete();
15148
- }
15149
- else {
15150
- // all other states are errors
15151
- observer.error(error);
15152
- observer.complete();
15276
+ }
15277
+ }).catch(reason => { observer.error(reason); });
15278
+ }
15279
+ else {
15280
+ observer.error('Received no audio data!');
15281
+ }
15282
+ },
15283
+ error: (error) => {
15284
+ if (error.status == 404) {
15285
+ // Interpret not as an error, the file ist not recorded yet
15286
+ observer.next(null);
15287
+ observer.complete();
15288
+ }
15289
+ else {
15290
+ // all other states are errors
15291
+ observer.error(error);
15292
+ observer.complete();
15293
+ }
15153
15294
  }
15154
15295
  });
15155
15296
  }
@@ -15163,82 +15304,40 @@ class RecordingFileService extends BasicRecordingService {
15163
15304
  let wobs = new Observable(observer => {
15164
15305
  let rf = null;
15165
15306
  let rfDescrObs = this.recordingFileDescrObserver(recordingFileId);
15166
- rfDescrObs.subscribe(value => {
15167
- rf = value;
15168
- }, (error) => {
15169
- observer.error(error);
15170
- }, () => {
15171
- let rfAudioObs = this.fetchAudiofile(recordingFileId);
15172
- rfAudioObs.subscribe(resp => {
15173
- // Do not use Promise version, which does not work with Safari 13
15174
- if (resp.body) {
15175
- aCtx.decodeAudioData(resp.body, ab => {
15176
- if (rf) {
15177
- let as = new AudioBufferSource(ab);
15178
- RecordingFileUtils.setAudioData(rf, new AudioDataHolder(as));
15179
- }
15180
- else {
15181
- observer.error('Recording file object null');
15182
- }
15183
- if (this.debugDelay > 0) {
15184
- window.setTimeout(() => {
15185
- observer.next(rf);
15186
- observer.complete();
15187
- }, this.debugDelay);
15307
+ rfDescrObs.subscribe({ next: value => {
15308
+ rf = value;
15309
+ }, error: (error) => {
15310
+ observer.error(error);
15311
+ }, complete: () => {
15312
+ let rfAudioObs = this.fetchAudiofile(recordingFileId);
15313
+ rfAudioObs.subscribe({
15314
+ next: resp => {
15315
+ // Do not use Promise version, which does not work with Safari 13
15316
+ if (resp.body) {
15317
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
15318
+ if (rf) {
15319
+ let as = new AudioBufferSource(ab);
15320
+ RecordingFileUtils.setAudioData(rf, new AudioDataHolder(as));
15321
+ }
15322
+ else {
15323
+ observer.error('Recording file object null');
15324
+ }
15325
+ if (this.debugDelay > 0) {
15326
+ window.setTimeout(() => {
15327
+ observer.next(rf);
15328
+ observer.complete();
15329
+ }, this.debugDelay);
15330
+ }
15331
+ else {
15332
+ observer.next(rf);
15333
+ observer.complete();
15334
+ }
15335
+ }).catch(reason => { observer.error(reason); });
15188
15336
  }
15189
15337
  else {
15190
- observer.next(rf);
15191
- observer.complete();
15192
- }
15193
- });
15194
- }
15195
- else {
15196
- observer.error('Received no audio data');
15197
- }
15198
- }, (error) => {
15199
- if (error.status == 404) {
15200
- // Interpret not as an error, the file ist not recorded yet
15201
- observer.next(null);
15202
- observer.complete();
15203
- }
15204
- else {
15205
- // all other states are errors
15206
- observer.error(error);
15207
- observer.complete();
15208
- }
15209
- });
15210
- });
15211
- });
15212
- return wobs;
15213
- }
15214
- fetchSprRecordingFile(aCtx, recordingFileId) {
15215
- let wobs = new Observable(observer => {
15216
- let rf = null;
15217
- let rfDescrObs = this.sprRecordingFileDescrObserver(recordingFileId);
15218
- rfDescrObs.subscribe(value => {
15219
- rf = value;
15220
- }, (error) => {
15221
- observer.error(error);
15222
- }, () => {
15223
- let sampleCnt = null;
15224
- if (rf && rf.channels && rf.frames) {
15225
- sampleCnt = rf.channels * rf.frames;
15226
- }
15227
- // TODO use download storage type depending on sample count of file
15228
- if (rf && rf.samplerate && sampleCnt != null && sampleCnt > this._maxAutoNetMemStoreSamples) {
15229
- const baseUrl = this.recoFileUrl(recordingFileId);
15230
- const obNetAb = this.chunkAudioRequestToNetAudioBuffer(aCtx, baseUrl, 0, rf === null || rf === void 0 ? void 0 : rf.samplerate, BasicRecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS, rf.frames);
15231
- obNetAb.subscribe({
15232
- next: (nab) => {
15233
- let adh = new AudioDataHolder(nab);
15234
- if (rf) {
15235
- RecordingFileUtils.setAudioData(rf, adh);
15236
- observer.next(rf);
15338
+ observer.error('Received no audio data');
15237
15339
  }
15238
15340
  },
15239
- complete: () => {
15240
- observer.complete();
15241
- },
15242
15341
  error: (error) => {
15243
15342
  if (error.status == 404) {
15244
15343
  // Interpret not as an error, the file ist not recorded yet
@@ -15253,47 +15352,97 @@ class RecordingFileService extends BasicRecordingService {
15253
15352
  }
15254
15353
  });
15255
15354
  }
15256
- else {
15257
- let rfAudioObs = this.fetchAudiofile(recordingFileId);
15258
- rfAudioObs.subscribe(resp => {
15259
- // Do not use Promise version, which does not work with Safari 13
15260
- if (resp.body) {
15261
- aCtx.decodeAudioData(resp.body, ab => {
15355
+ });
15356
+ });
15357
+ return wobs;
15358
+ }
15359
+ fetchSprRecordingFile(recordingFileId) {
15360
+ let wobs = new Observable(observer => {
15361
+ let rf = null;
15362
+ let rfDescrObs = this.sprRecordingFileDescrObserver(recordingFileId);
15363
+ rfDescrObs.subscribe({ next: value => {
15364
+ rf = value;
15365
+ },
15366
+ error: (error) => {
15367
+ observer.error(error);
15368
+ }, complete: () => {
15369
+ let sampleCnt = null;
15370
+ if (rf && rf.channels && rf.frames) {
15371
+ sampleCnt = rf.channels * rf.frames;
15372
+ }
15373
+ // TODO use download storage type depending on sample count of file
15374
+ if (rf && rf.samplerate && sampleCnt != null && sampleCnt > this._maxAutoNetMemStoreSamples) {
15375
+ const baseUrl = this.recoFileUrl(recordingFileId);
15376
+ const obNetAb = this.chunkAudioRequestToNetAudioBuffer(baseUrl, 0, rf === null || rf === void 0 ? void 0 : rf.samplerate, BasicRecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS, rf.frames);
15377
+ obNetAb.subscribe({
15378
+ next: (nab) => {
15379
+ let adh = new AudioDataHolder(nab);
15262
15380
  if (rf) {
15263
- let as = new AudioBufferSource(ab);
15264
- let adh = new AudioDataHolder(as);
15265
15381
  RecordingFileUtils.setAudioData(rf, adh);
15382
+ observer.next(rf);
15383
+ }
15384
+ },
15385
+ complete: () => {
15386
+ observer.complete();
15387
+ },
15388
+ error: (error) => {
15389
+ if (error.status == 404) {
15390
+ // Interpret not as an error, the file ist not recorded yet
15391
+ observer.next(null);
15392
+ observer.complete();
15266
15393
  }
15267
15394
  else {
15268
- observer.error('Recording file object null');
15395
+ // all other states are errors
15396
+ observer.error(error);
15397
+ observer.complete();
15269
15398
  }
15270
- if (this.debugDelay > 0) {
15271
- window.setTimeout(() => {
15272
- observer.next(rf);
15273
- observer.complete();
15274
- }, this.debugDelay);
15399
+ }
15400
+ });
15401
+ }
15402
+ else {
15403
+ let rfAudioObs = this.fetchAudiofile(recordingFileId);
15404
+ rfAudioObs.subscribe({ next: resp => {
15405
+ // Do not use Promise version, which does not work with Safari 13
15406
+ if (resp.body) {
15407
+ AudioContextProvider.decodeAudioData(resp.body).then(ab => {
15408
+ if (rf) {
15409
+ let as = new AudioBufferSource(ab);
15410
+ let adh = new AudioDataHolder(as);
15411
+ RecordingFileUtils.setAudioData(rf, adh);
15412
+ }
15413
+ else {
15414
+ observer.error('Recording file object null');
15415
+ }
15416
+ if (this.debugDelay > 0) {
15417
+ window.setTimeout(() => {
15418
+ observer.next(rf);
15419
+ observer.complete();
15420
+ }, this.debugDelay);
15421
+ }
15422
+ else {
15423
+ observer.next(rf);
15424
+ observer.complete();
15425
+ }
15426
+ }).catch(reason => { observer.error(reason); });
15275
15427
  }
15276
15428
  else {
15277
- observer.next(rf);
15429
+ observer.error('Received no audio data');
15430
+ }
15431
+ },
15432
+ error: (error) => {
15433
+ if (error.status == 404) {
15434
+ // Interpret not as an error, the file ist not recorded yet
15435
+ observer.next(null);
15278
15436
  observer.complete();
15279
15437
  }
15280
- });
15281
- }
15282
- else {
15283
- observer.error('Received no audio data');
15284
- }
15285
- }, (error) => {
15286
- if (error.status == 404) {
15287
- // Interpret not as an error, the file ist not recorded yet
15288
- observer.next(null);
15289
- observer.complete();
15290
- }
15291
- else {
15292
- // all other states are errors
15293
- observer.error(error);
15294
- observer.complete();
15295
- }
15296
- });
15438
+ else {
15439
+ // all other states are errors
15440
+ observer.error(error);
15441
+ observer.complete();
15442
+ }
15443
+ }
15444
+ });
15445
+ }
15297
15446
  }
15298
15447
  });
15299
15448
  });
@@ -15347,7 +15496,7 @@ RecordingFileNaviComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0
15347
15496
  <legend>Versions</legend>
15348
15497
  <mat-progress-spinner *ngIf="naviInfoLoading" mode="indeterminate" [diameter]="15"></mat-progress-spinner>
15349
15498
  <select *ngIf="!naviInfoLoading" [disabled]="versions==null || versions.length==1" (change)="selectVersionChange($event)">
15350
- <option *ngFor="let v of versions; let i = index" [selected]="v===version" value="{{v}}">{{v}}<span *ngIf="i==0"> (latest)</span></option>
15499
+ <option *ngFor="let v of versions; let i = index" [selected]="v===version" value="{{v}}">{{v}}<ng-container *ngIf="i==0"> (latest)</ng-container></option>
15351
15500
  </select>
15352
15501
  </fieldset>
15353
15502
  <fieldset>
@@ -15382,7 +15531,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
15382
15531
  <legend>Versions</legend>
15383
15532
  <mat-progress-spinner *ngIf="naviInfoLoading" mode="indeterminate" [diameter]="15"></mat-progress-spinner>
15384
15533
  <select *ngIf="!naviInfoLoading" [disabled]="versions==null || versions.length==1" (change)="selectVersionChange($event)">
15385
- <option *ngFor="let v of versions; let i = index" [selected]="v===version" value="{{v}}">{{v}}<span *ngIf="i==0"> (latest)</span></option>
15534
+ <option *ngFor="let v of versions; let i = index" [selected]="v===version" value="{{v}}">{{v}}<ng-container *ngIf="i==0"> (latest)</ng-container></option>
15386
15535
  </select>
15387
15536
  </fieldset>
15388
15537
  <fieldset>
@@ -15434,9 +15583,9 @@ class RecordingFileMetaComponent {
15434
15583
  constructor() {
15435
15584
  this.sessionId = null;
15436
15585
  this._recordingFile = null;
15437
- this.stateLoading = false;
15438
15586
  this.itemCode = null;
15439
15587
  this.uuid = null;
15588
+ this.stateLoading = false;
15440
15589
  }
15441
15590
  get recordingFile() {
15442
15591
  return this._recordingFile;
@@ -15545,7 +15694,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
15545
15694
  </mat-card-content>
15546
15695
  </mat-card>
15547
15696
  ` }]
15548
- }], propDecorators: { sessionId: [{
15697
+ }], ctorParameters: function () { return []; }, propDecorators: { sessionId: [{
15549
15698
  type: Input
15550
15699
  }], stateLoading: [{
15551
15700
  type: Input
@@ -15566,7 +15715,6 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15566
15715
  this.ref = ref;
15567
15716
  this.eRef = eRef;
15568
15717
  this.dialog = dialog;
15569
- //protected _recordingFileId: string | number = null;
15570
15718
  this.sessionId = null;
15571
15719
  this.sessionIdFromRoute = null;
15572
15720
  this.availRecFiles = null;
@@ -15575,9 +15723,11 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15575
15723
  this.recordingFileVersion = null;
15576
15724
  this.routedByQueryParam = false;
15577
15725
  this.posInList = null;
15578
- this.audioFetching = false;
15579
- this.naviInfoLoading = false;
15580
15726
  this.parentE = this.eRef.nativeElement;
15727
+ // TODO Should be initialized with false, but this causes in debug mode:
15728
+ // 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
15729
+ this.audioFetching = true;
15730
+ this.naviInfoLoading = false;
15581
15731
  this.firstAction = new Action('First');
15582
15732
  this.firstAction.onAction = () => {
15583
15733
  this.posInList = 0;
@@ -15745,10 +15895,9 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15745
15895
  this.recordingFile = null;
15746
15896
  this.posInList = null;
15747
15897
  this.updateActions();
15748
- let audioContext = AudioContextProvider.audioContextInstance();
15749
- if (audioContext) {
15750
- this.audioFetching = true;
15751
- this.recordingFileService.fetchSprRecordingFile(audioContext, rfId).subscribe(value => {
15898
+ this.audioFetching = true;
15899
+ this.recordingFileService.fetchSprRecordingFile(rfId).subscribe({
15900
+ next: value => {
15752
15901
  this.audioFetching = false;
15753
15902
  this.status = 'Audio file loaded.';
15754
15903
  let clip = null;
@@ -15786,11 +15935,11 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15786
15935
  }
15787
15936
  this.audioClip = clip;
15788
15937
  this.loadedRecfile();
15789
- }, error1 => {
15938
+ }, error: error1 => {
15790
15939
  this.audioFetching = false;
15791
15940
  this.status = 'Error loading audio file!';
15792
- });
15793
- }
15941
+ }
15942
+ });
15794
15943
  }
15795
15944
  loadedRecfile() {
15796
15945
  if (this.recordingFile && !this.sessionId) {
@@ -15816,7 +15965,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15816
15965
  this.lastAction.disabled = (this.posInList == null || itemCnt == null || this.posInList >= itemCnt - 1);
15817
15966
  }
15818
15967
  loadSession(sessionId) {
15819
- // load session and recording file meta data only when on init and when session changes
15968
+ // load session and recording file metadata only when on init and when session changes
15820
15969
  if (sessionId != this.sessionId) {
15821
15970
  // tell UI that we are working...
15822
15971
  this.naviInfoLoading = true;
@@ -15854,7 +16003,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15854
16003
  else {
15855
16004
  // rec file with itemcode already exists, add (push) this version ...
15856
16005
  exRfsForIc.push(rfd);
15857
- // .. and sort latest version (highest version number) to lowest index
16006
+ // ... and sort latest version (highest version number) to lowest index
15858
16007
  exRfsForIc.sort((rfd1, rfd2) => {
15859
16008
  return rfd2.version - rfd1.version;
15860
16009
  });
@@ -15908,7 +16057,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
15908
16057
  }
15909
16058
  }
15910
16059
  }
15911
- 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 });
16060
+ 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 });
15912
16061
  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: `
15913
16062
 
15914
16063
  <audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
@@ -15947,7 +16096,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
15947
16096
  <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>
15948
16097
  </div>
15949
16098
  `, 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"] }]
15950
- }], 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: [{
16099
+ }], 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: [{
15951
16100
  type: ViewChild,
15952
16101
  args: [AudioDisplayScrollPane]
15953
16102
  }] } });
@@ -16013,27 +16162,28 @@ class RecordingFileUI extends RecordingFileViewComponent {
16013
16162
  sf = s.startFrame;
16014
16163
  ef = s.endFrame;
16015
16164
  }
16016
- this.recordingFileService.saveEditSelection(this.recordingFile.recordingFileId, sr, sf, ef).subscribe((value) => {
16017
- }, () => {
16018
- this.dialog.open(MessageDialog, {
16019
- data: {
16020
- type: 'error',
16021
- title: 'Save selection edit error',
16022
- msg: "Could not save edit selection to WikiSpeech server!",
16023
- advice: "Please check network connection and server state."
16024
- }
16025
- });
16026
- }, () => {
16027
- // Or use returned selection value from server?
16028
- this.savedEditSelection = s;
16029
- this.editSaved = true;
16030
- this.snackBar.open('Selection edit saved successfully.', 'OK', { duration: 1500 });
16165
+ this.recordingFileService.saveEditSelection(this.recordingFile.recordingFileId, sr, sf, ef).subscribe({ next: (value) => { },
16166
+ error: () => {
16167
+ this.dialog.open(MessageDialog, {
16168
+ data: {
16169
+ type: 'error',
16170
+ title: 'Save selection edit error',
16171
+ msg: "Could not save edit selection to WikiSpeech server!",
16172
+ advice: "Please check network connection and server state."
16173
+ }
16174
+ });
16175
+ }, complete: () => {
16176
+ // Or use returned selection value from server?
16177
+ this.savedEditSelection = s;
16178
+ this.editSaved = true;
16179
+ this.snackBar.open('Selection edit saved successfully.', 'OK', { duration: 1500 });
16180
+ }
16031
16181
  });
16032
16182
  }
16033
16183
  }
16034
16184
  }
16035
16185
  }
16036
- 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 });
16186
+ 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 });
16037
16187
  RecordingFileUI.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: RecordingFileUI, selector: "app-audiodisplayplayer", usesInheritance: true, ngImport: i0, template: `
16038
16188
  <h1>Recording file editing</h1>
16039
16189
  <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>
@@ -16078,7 +16228,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
16078
16228
 
16079
16229
  <button mat-raised-button color="accent" (click)="applySelection()" [disabled]="editSaved">{{this.applyButtonText()}}</button>
16080
16230
  `, 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"] }]
16081
- }], 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 }]; } });
16231
+ }], 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 }]; } });
16082
16232
 
16083
16233
  class MediaUtils {
16084
16234
  static toMediaTime(timeInSeconds) {
@@ -16216,7 +16366,7 @@ RecordingList.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version:
16216
16366
  </mat-card-content>
16217
16367
  </mat-card>
16218
16368
 
16219
- `, 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" }] });
16369
+ `, 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" }] });
16220
16370
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RecordingList, decorators: [{
16221
16371
  type: Component,
16222
16372
  args: [{ selector: 'app-recordinglist', template: `
@@ -16297,7 +16447,7 @@ class RecorderCombiPane extends ResponsiveComponent {
16297
16447
  this.recordingListComp.selectTop();
16298
16448
  }
16299
16449
  }
16300
- 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 });
16450
+ 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 });
16301
16451
  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: `
16302
16452
  <div class="scrollList">
16303
16453
  <app-recordinglist [selectedRecordingFile]="selectedRecordingFile" [selectDisabled]="selectDisabled" (selectedRecordingFileChanged)="selectRecordingFile($event)"></app-recordinglist>
@@ -16326,7 +16476,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
16326
16476
  [playStopAction]="playStopAction"></app-audiodisplay>
16327
16477
  </div>
16328
16478
  `, 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"] }]
16329
- }], ctorParameters: function () { return [{ type: i1$3.BreakpointObserver }]; }, propDecorators: { recordingListComp: [{
16479
+ }], ctorParameters: function () { return [{ type: i1$2.BreakpointObserver }]; }, propDecorators: { recordingListComp: [{
16330
16480
  type: ViewChild,
16331
16481
  args: [RecordingList]
16332
16482
  }], selectDisabled: [{
@@ -16353,11 +16503,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
16353
16503
  }] } });
16354
16504
 
16355
16505
  class AudioRecorder extends BasicRecorder {
16356
- constructor(bpo, changeDetectorRef, renderer, route, dialog, sessionService, recFileService, uploader, config) {
16506
+ constructor(bpo, changeDetectorRef, renderer, dialog, sessionService, recFileService, uploader, config) {
16357
16507
  super(bpo, changeDetectorRef, dialog, sessionService, uploader, config);
16358
16508
  this.bpo = bpo;
16359
16509
  this.renderer = renderer;
16360
- this.route = route;
16361
16510
  this.recFileService = recFileService;
16362
16511
  this.uploader = uploader;
16363
16512
  this._project = null;
@@ -16402,38 +16551,17 @@ class AudioRecorder extends BasicRecorder {
16402
16551
  this.transportActions.nextAction.disabled = true;
16403
16552
  this.transportActions.pauseAction.disabled = true;
16404
16553
  this.playStartAction.disabled = true;
16405
- //this.audioLoaded=false;
16406
- let context = null;
16407
- try {
16408
- context = AudioContextProvider.audioContextInstance();
16409
- }
16410
- catch (err) {
16411
- this.status = 5 /* ERROR */;
16412
- let errMsg = 'Unknown error';
16413
- if (err instanceof Error) {
16414
- errMsg = err.message;
16415
- }
16416
- this.statusMsg = 'ERROR: ' + errMsg;
16417
- this.statusAlertType = 'error';
16418
- this.dialog.open(MessageDialog, {
16419
- data: {
16420
- type: 'error',
16421
- title: 'Error',
16422
- msg: errMsg,
16423
- advice: 'Please use a supported browser.',
16424
- }
16425
- });
16426
- return;
16427
- }
16428
- if (context) {
16429
- console.info("State of audio context: " + context.state);
16554
+ this.ac = new AudioCapture();
16555
+ if (this.ac) {
16556
+ this.transportActions.startAction.onAction = () => this.startItem();
16557
+ this.ac.listener = this;
16558
+ this.configureStreamCaptureStream();
16559
+ // Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
16560
+ //this.ac.listDevices();
16430
16561
  }
16431
16562
  else {
16432
- console.info("No audio context available!");
16433
- }
16434
- if (!context || !navigator.mediaDevices) {
16435
- this.status = 5 /* ERROR */;
16436
- let errMsg = 'Browser does not support Media streams!';
16563
+ this.transportActions.startAction.disabled = true;
16564
+ let errMsg = 'Browser does not support Media/Audio API!';
16437
16565
  this.statusMsg = 'ERROR: ' + errMsg;
16438
16566
  this.statusAlertType = 'error';
16439
16567
  this.dialog.open(MessageDialog, {
@@ -16446,36 +16574,10 @@ class AudioRecorder extends BasicRecorder {
16446
16574
  });
16447
16575
  return;
16448
16576
  }
16449
- else {
16450
- //this.controlAudioPlayer = new AudioPlayer(context, this);
16451
- this.ac = new AudioCapture(context);
16452
- if (this.ac) {
16453
- this.transportActions.startAction.onAction = () => this.startItem();
16454
- this.ac.listener = this;
16455
- this.configureStreamCaptureStream();
16456
- // Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
16457
- //this.ac.listDevices();
16458
- }
16459
- else {
16460
- this.transportActions.startAction.disabled = true;
16461
- let errMsg = 'Browser does not support Media/Audio API!';
16462
- this.statusMsg = 'ERROR: ' + errMsg;
16463
- this.statusAlertType = 'error';
16464
- this.dialog.open(MessageDialog, {
16465
- data: {
16466
- type: 'error',
16467
- title: 'Error',
16468
- msg: errMsg,
16469
- advice: 'Please use a supported browser.',
16470
- }
16471
- });
16472
- return;
16473
- }
16474
- this.transportActions.stopAction.onAction = () => this.stopItem();
16475
- this.transportActions.nextAction.onAction = () => this.stopItem();
16476
- //this.transportActions.pauseAction.onAction = () => this.pauseItem();
16477
- this.playStartAction.onAction = () => { var _a; return (_a = this.controlAudioPlayer) === null || _a === void 0 ? void 0 : _a.start(); };
16478
- }
16577
+ this.transportActions.stopAction.onAction = () => this.stopItem();
16578
+ this.transportActions.nextAction.onAction = () => this.stopItem();
16579
+ //this.transportActions.pauseAction.onAction = () => this.pauseItem();
16580
+ this.playStartAction.onAction = () => { var _a; return (_a = this.controlAudioPlayer) === null || _a === void 0 ? void 0 : _a.start(); };
16479
16581
  this.uploader.listener = (ue) => {
16480
16582
  this.uploadUpdate(ue);
16481
16583
  };
@@ -16584,6 +16686,9 @@ class AudioRecorder extends BasicRecorder {
16584
16686
  chCnt = ProjectUtil.audioChannelCount(project);
16585
16687
  console.info("Project requested recording channel count: " + chCnt);
16586
16688
  this.autoGainControlConfigs = project.autoGainControlConfigs;
16689
+ if (project.allowEchoCancellation !== undefined) {
16690
+ this.allowEchoCancellation = project.allowEchoCancellation;
16691
+ }
16587
16692
  if (project.chunkedRecording === true) {
16588
16693
  this.uploadChunkSizeSeconds = BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS;
16589
16694
  }
@@ -16784,7 +16889,7 @@ class AudioRecorder extends BasicRecorder {
16784
16889
  }
16785
16890
  else {
16786
16891
  //console.debug("Fetch audio and store to indexed db...");
16787
- this.audioFetchSubscription = this.recFileService.fetchRecordingFileIndDbAudioBuffer(this._controlAudioPlayer.context, this._persistentAudioStorageTarget, this._session.project, rf).subscribe({
16892
+ this.audioFetchSubscription = this.recFileService.fetchRecordingFileIndDbAudioBuffer(this._persistentAudioStorageTarget, this._session.project, rf).subscribe({
16788
16893
  next: (iab) => {
16789
16894
  //console.debug("Sessionmanager: Received inddb audio buffer: "+iab);
16790
16895
  nextIab = iab;
@@ -16827,7 +16932,7 @@ class AudioRecorder extends BasicRecorder {
16827
16932
  // Fetch chunked audio buffer from network
16828
16933
  let nextNetAb = null;
16829
16934
  //console.debug("Fetch chunked audio from network");
16830
- this.audioFetchSubscription = this.recFileService.fetchRecordingFileNetAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
16935
+ this.audioFetchSubscription = this.recFileService.fetchRecordingFileNetAudioBuffer(this._session.project, rf).subscribe({
16831
16936
  next: (netAb) => {
16832
16937
  //console.debug("Sessionmanager: Received net audio buffer: "+netAb);
16833
16938
  nextNetAb = netAb;
@@ -16872,7 +16977,7 @@ class AudioRecorder extends BasicRecorder {
16872
16977
  // Fetch chunked array audio buffer
16873
16978
  let nextAab = null;
16874
16979
  //console.debug("Fetch audio and store to (chunked) array buffer...");
16875
- this.audioFetchSubscription = this.recFileService.fetchRecordingFileArrayAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
16980
+ this.audioFetchSubscription = this.recFileService.fetchRecordingFileArrayAudioBuffer(this._session.project, rf).subscribe({
16876
16981
  next: (aab) => {
16877
16982
  nextAab = aab;
16878
16983
  },
@@ -16909,7 +17014,7 @@ class AudioRecorder extends BasicRecorder {
16909
17014
  });
16910
17015
  }
16911
17016
  else {
16912
- this.audioFetchSubscription = this.recFileService.fetchRecordingFileAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
17017
+ this.audioFetchSubscription = this.recFileService.fetchRecordingFileAudioBuffer(this._session.project, rf).subscribe({
16913
17018
  next: ab => {
16914
17019
  this.liveLevelDisplayState = State.READY;
16915
17020
  let fabDh = null;
@@ -17049,7 +17154,7 @@ class AudioRecorder extends BasicRecorder {
17049
17154
  this.transportActions.pauseAction.disabled = true;
17050
17155
  this.statusAlertType = 'info';
17051
17156
  this.statusMsg = 'Recorded.';
17052
- let ad = null;
17157
+ let ab = null;
17053
17158
  if (this.ac) {
17054
17159
  let adh = null;
17055
17160
  let as = null;
@@ -17081,7 +17186,7 @@ class AudioRecorder extends BasicRecorder {
17081
17186
  const sr = this.ac.currentSampleRate;
17082
17187
  const chFl = sr * RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
17083
17188
  //console.debug("stopped(): rfID: "+this._recordingFile?.recordingFileId+", net ab url: " + burl+", frames: "+this.ac.framesRecorded+", sample rate: "+sr);
17084
- let netAs = new NetAudioBuffer(this.ac.context, this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
17189
+ let netAs = new NetAudioBuffer(this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
17085
17190
  as = netAs;
17086
17191
  if (this.uploadSet) {
17087
17192
  this.uploadSet.onDone = (uploadSet) => {
@@ -17128,7 +17233,7 @@ class AudioRecorder extends BasicRecorder {
17128
17233
  const sr = this.ac.currentSampleRate;
17129
17234
  const chFl = sr * RecordingService.DEFAULT_CHUNKED_DOWNLOAD_SECONDS;
17130
17235
  //console.debug("stopped(): rfID: "+this._recordingFile?.recordingFileId+", net ab url: " + burl+", frames: "+this.ac.framesRecorded+", sample rate: "+sr);
17131
- let netAs = new NetAudioBuffer(this.ac.context, this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
17236
+ let netAs = new NetAudioBuffer(this.recFileService, burl, this.ac.channelCount, sr, chFl, this.ac.framesRecorded, rUUID, chFl);
17132
17237
  as = netAs;
17133
17238
  if (this.uploadSet) {
17134
17239
  this.uploadSet.onDone = (uploadSet) => {
@@ -17147,7 +17252,7 @@ class AudioRecorder extends BasicRecorder {
17147
17252
  as = this.ac.audioBufferArray();
17148
17253
  }
17149
17254
  else {
17150
- let ab = this.ac.audioBuffer();
17255
+ ab = this.ac.audioBuffer();
17151
17256
  if (ab) {
17152
17257
  as = new AudioBufferSource(ab);
17153
17258
  }
@@ -17167,7 +17272,7 @@ class AudioRecorder extends BasicRecorder {
17167
17272
  RecordingFileUtils.setAudioData(rf, adh);
17168
17273
  this.recorderCombiPane.addRecFile(rf);
17169
17274
  // Upload if upload enabled and not in chunked upload mode
17170
- if (this.enableUploadRecordings && this._uploadChunkSizeSeconds === null && rf != null && ad != null) {
17275
+ if (this.enableUploadRecordings && this._uploadChunkSizeSeconds === null && AudioStorageType.MEM_ENTIRE === this._clientAudioStorageType && rf != null && ab != null) {
17171
17276
  let apiEndPoint = '';
17172
17277
  if (this.config && this.config.apiEndPoint) {
17173
17278
  apiEndPoint = this.config.apiEndPoint;
@@ -17182,7 +17287,7 @@ class AudioRecorder extends BasicRecorder {
17182
17287
  // TODO duplicate conversion for manual download
17183
17288
  this.processingRecording = true;
17184
17289
  let ww = new WavWriter();
17185
- ww.writeAsync(ad, (wavFile) => {
17290
+ ww.writeAsync(ab, (wavFile) => {
17186
17291
  this.postRecordingMultipart(wavFile, recUrl, rf);
17187
17292
  this.processingRecording = false;
17188
17293
  this.updateWakeLock();
@@ -17267,7 +17372,7 @@ class AudioRecorder extends BasicRecorder {
17267
17372
  }
17268
17373
  }
17269
17374
  }
17270
- 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 });
17375
+ 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 });
17271
17376
  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: `
17272
17377
  <app-warningbar [show]="isTestSession()" warningText="Test recording only!"></app-warningbar>
17273
17378
  <app-warningbar [show]="isDefaultAudioTestSession()"
@@ -17389,7 +17494,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
17389
17494
  </div>
17390
17495
  `, 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"] }]
17391
17496
  }], ctorParameters: function () {
17392
- 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: [{
17497
+ return [{ type: i1$2.BreakpointObserver }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i1$3.MatDialog }, { type: SessionService }, { type: RecordingService }, { type: SpeechRecorderUploader }, { type: SpeechRecorderConfig, decorators: [{
17393
17498
  type: Inject,
17394
17499
  args: [SPEECHRECORDER_CONFIG]
17395
17500
  }] }];
@@ -17421,11 +17526,7 @@ class AudioRecorderComponent extends RecorderComponent {
17421
17526
  this.uploader = uploader;
17422
17527
  }
17423
17528
  ngOnInit() {
17424
- //super.ngOnInit();
17425
- let audioContext = AudioContextProvider.audioContextInstance();
17426
- if (audioContext) {
17427
- this.controlAudioPlayer = new AudioPlayer(audioContext, this.ar);
17428
- }
17529
+ this.controlAudioPlayer = new AudioPlayer(this.ar);
17429
17530
  this.ar.controlAudioPlayer = this.controlAudioPlayer;
17430
17531
  //TODO Duplicate code in SpeechRecorderComponent
17431
17532
  window.addEventListener('beforeunload', (e) => {
@@ -17435,7 +17536,7 @@ class AudioRecorderComponent extends RecorderComponent {
17435
17536
  }
17436
17537
  else {
17437
17538
  // all this attempts to customize the message do not work anymore (for security reasons)!!
17438
- var message = "Please do not leave the page, until all recordings are uploaded!";
17539
+ const message = "Please do not leave the page, until all recordings are uploaded!";
17439
17540
  alert(message);
17440
17541
  e = e || window.event;
17441
17542
  if (e) {
@@ -17535,7 +17636,7 @@ class AudioRecorderComponent extends RecorderComponent {
17535
17636
  return this.dataSaved && !this.ar.isActive();
17536
17637
  }
17537
17638
  }
17538
- 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 });
17639
+ 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 });
17539
17640
  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: `
17540
17641
  <app-audiorecorder [projectName]="_project?.name" [dataSaved]="dataSaved"></app-audiorecorder>
17541
17642
  `, 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"] }] });
@@ -17544,7 +17645,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
17544
17645
  args: [{ selector: 'app-audiorecorder-comp', providers: [SessionService], template: `
17545
17646
  <app-audiorecorder [projectName]="_project?.name" [dataSaved]="dataSaved"></app-audiorecorder>
17546
17647
  `, styles: [":host{flex:2;display:flex;height:100%;flex-direction:column;min-height:0}\n"] }]
17547
- }], ctorParameters: function () { return [{ type: i1$2.ActivatedRoute }, { type: i1$2.Router }, { type: i0.ChangeDetectorRef }, { type: SessionService }, { type: ProjectService }, { type: SpeechRecorderUploader }]; }, propDecorators: { ar: [{
17648
+ }], ctorParameters: function () { return [{ type: i4$2.ActivatedRoute }, { type: i4$2.Router }, { type: i0.ChangeDetectorRef }, { type: SessionService }, { type: ProjectService }, { type: SpeechRecorderUploader }]; }, propDecorators: { ar: [{
17548
17649
  type: ViewChild,
17549
17650
  args: [AudioRecorder, { static: true }]
17550
17651
  }] } });
@@ -17580,7 +17681,7 @@ class SpeechrecorderngModule {
17580
17681
  }
17581
17682
  SpeechrecorderngModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SpeechrecorderngModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
17582
17683
  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,
17583
- 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] });
17684
+ 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] });
17584
17685
  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] });
17585
17686
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: SpeechrecorderngModule, decorators: [{
17586
17687
  type: NgModule,
@@ -17593,7 +17694,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImpo
17593
17694
  }]
17594
17695
  }] });
17595
17696
 
17596
- const VERSION = '3.4.4';
17697
+ const VERSION = '3.6.0';
17597
17698
 
17598
17699
  /*
17599
17700
  * Public API Surface of speechrecorderng