speechrecorderng 3.0.0 → 3.3.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 (142) hide show
  1. package/esm2020/lib/action/action.mjs +2 -1
  2. package/esm2020/lib/audio/array_audio_buffer.mjs +65 -2
  3. package/esm2020/lib/audio/array_audio_buffer_input_stream.mjs +2 -2
  4. package/esm2020/lib/audio/array_audio_buffer_random_access_stream.mjs +16 -0
  5. package/esm2020/lib/audio/audio_data_holder.mjs +203 -48
  6. package/esm2020/lib/audio/audio_display.mjs +10 -34
  7. package/esm2020/lib/audio/audio_player.mjs +18 -45
  8. package/esm2020/lib/audio/capture/capture.mjs +293 -69
  9. package/esm2020/lib/audio/dsp/level_measure.mjs +211 -88
  10. package/esm2020/lib/audio/impl/wavformat.mjs +1 -1
  11. package/esm2020/lib/audio/impl/wavreader.mjs +134 -0
  12. package/esm2020/lib/audio/impl/wavwriter.mjs +10 -9
  13. package/esm2020/lib/audio/inddb_audio_buffer.mjs +508 -0
  14. package/esm2020/lib/audio/net_audio_buffer.mjs +297 -0
  15. package/esm2020/lib/audio/persistor.mjs +8 -2
  16. package/esm2020/lib/audio/playback/array_audio_buffer_source_node.mjs +15 -154
  17. package/esm2020/lib/audio/playback/audio_source_node.mjs +18 -0
  18. package/esm2020/lib/audio/playback/audio_source_worklet_module_loader.mjs +167 -0
  19. package/esm2020/lib/audio/playback/inddb_audio_buffer_source_node.mjs +167 -0
  20. package/esm2020/lib/audio/playback/net_audio_buffer_source_node.mjs +218 -0
  21. package/esm2020/lib/audio/playback/player.mjs +190 -171
  22. package/esm2020/lib/audio/ui/audio_canvas_layer_comp.mjs +35 -76
  23. package/esm2020/lib/audio/ui/audio_display_control.mjs +12 -24
  24. package/esm2020/lib/audio/ui/audio_display_scroll_pane.mjs +14 -45
  25. package/esm2020/lib/audio/ui/audiosignal.mjs +333 -267
  26. package/esm2020/lib/audio/ui/container.mjs +40 -57
  27. package/esm2020/lib/audio/ui/livelevel.mjs +53 -52
  28. package/esm2020/lib/audio/ui/scroll_pane_horizontal.mjs +5 -19
  29. package/esm2020/lib/audio/ui/sonagram.mjs +386 -339
  30. package/esm2020/lib/db/inddb.mjs +120 -0
  31. package/esm2020/lib/io/BinaryReader.mjs +85 -0
  32. package/esm2020/lib/io/stream.mjs +101 -1
  33. package/esm2020/lib/net/uploader.mjs +111 -5
  34. package/esm2020/lib/recorder_component.mjs +59 -1
  35. package/esm2020/lib/speechrecorder/project/project.mjs +10 -1
  36. package/esm2020/lib/speechrecorder/project/project.service.mjs +3 -3
  37. package/esm2020/lib/speechrecorder/recording.mjs +30 -6
  38. package/esm2020/lib/speechrecorder/recordings/basic_recording.service.mjs +213 -0
  39. package/esm2020/lib/speechrecorder/recordings/recordings.service.mjs +732 -65
  40. package/esm2020/lib/speechrecorder/script/script.service.mjs +3 -3
  41. package/esm2020/lib/speechrecorder/session/audiorecorder.mjs +358 -184
  42. package/esm2020/lib/speechrecorder/session/basicrecorder.mjs +181 -28
  43. package/esm2020/lib/speechrecorder/session/controlpanel.mjs +47 -129
  44. package/esm2020/lib/speechrecorder/session/item.mjs +13 -1
  45. package/esm2020/lib/speechrecorder/session/progress.mjs +26 -55
  46. package/esm2020/lib/speechrecorder/session/prompting.mjs +33 -176
  47. package/esm2020/lib/speechrecorder/session/recorder_combi_pane.mjs +6 -6
  48. package/esm2020/lib/speechrecorder/session/recording_file_cache.mjs +28 -15
  49. package/esm2020/lib/speechrecorder/session/recording_list.mjs +92 -55
  50. package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-meta.component.mjs +9 -13
  51. package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-navi.component.mjs +9 -18
  52. package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-u-i.component.mjs +10 -36
  53. package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-view.component.mjs +10 -37
  54. package/esm2020/lib/speechrecorder/session/recordingfile/recordingfile-service.mjs +80 -56
  55. package/esm2020/lib/speechrecorder/session/session.service.mjs +3 -3
  56. package/esm2020/lib/speechrecorder/session/session_finished_dialog.mjs +4 -4
  57. package/esm2020/lib/speechrecorder/session/sessionmanager.mjs +409 -165
  58. package/esm2020/lib/speechrecorder/session/warning_bar.mjs +6 -29
  59. package/esm2020/lib/speechrecorder/spruploader.mjs +3 -3
  60. package/esm2020/lib/speechrecorder/startstopsignal/ui/simpletrafficlight.mjs +6 -41
  61. package/esm2020/lib/speechrecorderng.component.mjs +42 -31
  62. package/esm2020/lib/speechrecorderng.module.mjs +5 -5
  63. package/esm2020/lib/spr.config.mjs +3 -3
  64. package/esm2020/lib/spr.module.version.mjs +2 -2
  65. package/esm2020/lib/ui/canvas_layer_comp.mjs +3 -3
  66. package/esm2020/lib/ui/message_dialog.mjs +7 -7
  67. package/esm2020/lib/ui/recordingitem_display.mjs +26 -59
  68. package/esm2020/lib/utils/scrollIntoViewToBottom.mjs +3 -3
  69. package/esm2020/lib/utils/ua-parser.mjs +28 -4
  70. package/esm2020/lib/utils/utils.mjs +29 -1
  71. package/fesm2015/speechrecorderng.mjs +12755 -9195
  72. package/fesm2015/speechrecorderng.mjs.map +1 -1
  73. package/fesm2020/speechrecorderng.mjs +12652 -9101
  74. package/fesm2020/speechrecorderng.mjs.map +1 -1
  75. package/{speechrecorderng.d.ts → index.d.ts} +0 -0
  76. package/lib/audio/array_audio_buffer.d.ts +17 -1
  77. package/lib/audio/array_audio_buffer_random_access_stream.d.ts +9 -0
  78. package/lib/audio/audio_data_holder.d.ts +69 -14
  79. package/lib/audio/audio_display.d.ts +1 -1
  80. package/lib/audio/audio_player.d.ts +3 -7
  81. package/lib/audio/capture/capture.d.ts +24 -4
  82. package/lib/audio/dsp/level_measure.d.ts +2 -23
  83. package/lib/audio/impl/wavformat.d.ts +3 -3
  84. package/lib/audio/impl/wavreader.d.ts +16 -0
  85. package/lib/audio/impl/wavwriter.d.ts +1 -4
  86. package/lib/audio/inddb_audio_buffer.d.ts +68 -0
  87. package/lib/audio/net_audio_buffer.d.ts +59 -0
  88. package/lib/audio/persistor.d.ts +3 -9
  89. package/lib/audio/playback/array_audio_buffer_source_node.d.ts +2 -8
  90. package/lib/audio/playback/audio_source_node.d.ts +10 -0
  91. package/lib/audio/playback/audio_source_worklet_module_loader.d.ts +4 -0
  92. package/lib/audio/playback/inddb_audio_buffer_source_node.d.ts +21 -0
  93. package/lib/audio/playback/net_audio_buffer_source_node.d.ts +27 -0
  94. package/lib/audio/playback/player.d.ts +19 -16
  95. package/lib/audio/ui/audio_canvas_layer_comp.d.ts +3 -3
  96. package/lib/audio/ui/audio_display_control.d.ts +3 -6
  97. package/lib/audio/ui/audio_display_scroll_pane.d.ts +1 -1
  98. package/lib/audio/ui/audiosignal.d.ts +4 -3
  99. package/lib/audio/ui/container.d.ts +1 -1
  100. package/lib/audio/ui/livelevel.d.ts +11 -4
  101. package/lib/audio/ui/scroll_pane_horizontal.d.ts +1 -1
  102. package/lib/audio/ui/sonagram.d.ts +4 -3
  103. package/lib/db/inddb.d.ts +21 -0
  104. package/lib/io/BinaryReader.d.ts +18 -0
  105. package/lib/io/stream.d.ts +18 -0
  106. package/lib/net/uploader.d.ts +20 -2
  107. package/lib/recorder_component.d.ts +5 -0
  108. package/lib/speechrecorder/project/project.d.ts +9 -0
  109. package/lib/speechrecorder/recording.d.ts +8 -2
  110. package/lib/speechrecorder/recordings/basic_recording.service.d.ts +27 -0
  111. package/lib/speechrecorder/recordings/recordings.service.d.ts +21 -6
  112. package/lib/speechrecorder/session/audiorecorder.d.ts +7 -18
  113. package/lib/speechrecorder/session/basicrecorder.d.ts +28 -4
  114. package/lib/speechrecorder/session/controlpanel.d.ts +7 -7
  115. package/lib/speechrecorder/session/item.d.ts +1 -0
  116. package/lib/speechrecorder/session/progress.d.ts +2 -1
  117. package/lib/speechrecorder/session/prompting.d.ts +5 -5
  118. package/lib/speechrecorder/session/recorder_combi_pane.d.ts +1 -1
  119. package/lib/speechrecorder/session/recording_file_cache.d.ts +7 -4
  120. package/lib/speechrecorder/session/recording_list.d.ts +2 -1
  121. package/lib/speechrecorder/session/recordingfile/recording-file-meta.component.d.ts +1 -1
  122. package/lib/speechrecorder/session/recordingfile/recording-file-navi.component.d.ts +1 -1
  123. package/lib/speechrecorder/session/recordingfile/recording-file-u-i.component.d.ts +1 -1
  124. package/lib/speechrecorder/session/recordingfile/recording-file-view.component.d.ts +1 -1
  125. package/lib/speechrecorder/session/recordingfile/recordingfile-service.d.ts +4 -5
  126. package/lib/speechrecorder/session/session_finished_dialog.d.ts +1 -1
  127. package/lib/speechrecorder/session/sessionmanager.d.ts +10 -10
  128. package/lib/speechrecorder/session/warning_bar.d.ts +1 -1
  129. package/lib/speechrecorder/startstopsignal/ui/simpletrafficlight.d.ts +1 -1
  130. package/lib/speechrecorderng.component.d.ts +2 -1
  131. package/lib/spr.module.version.d.ts +1 -1
  132. package/lib/ui/canvas_layer_comp.d.ts +1 -1
  133. package/lib/ui/message_dialog.d.ts +1 -1
  134. package/lib/ui/recordingitem_display.d.ts +3 -2
  135. package/lib/utils/scrollIntoViewToBottom.d.ts +1 -1
  136. package/lib/utils/ua-parser.d.ts +4 -1
  137. package/lib/utils/utils.d.ts +6 -0
  138. package/package.json +5 -4
  139. package/esm2020/lib/math/utils.mjs +0 -14
  140. package/esm2020/lib/utils/css_utils.mjs +0 -7
  141. package/lib/math/utils.d.ts +0 -3
  142. package/lib/utils/css_utils.d.ts +0 -3
@@ -0,0 +1,167 @@
1
+ import { AsyncEditFloat32ArrayInputStream } from "../../io/stream";
2
+ import { IndexedDbAudioInputStream } from "../inddb_audio_buffer";
3
+ import { ArrayAudioBufferSourceNode } from "./array_audio_buffer_source_node";
4
+ import { EMPTY, expand, Observable } from "rxjs";
5
+ import { AudioSourceNode } from "./audio_source_node";
6
+ export class IndexedDbAudioBufferSourceNode extends AudioSourceNode {
7
+ constructor(context) {
8
+ super(context, 'audio-source-worklet');
9
+ this._bufferFillSeconds = AudioSourceNode.DEFAULT_BUFFER_FILL_SECONDS;
10
+ this.bufferFillFrames = 0;
11
+ this._streamReadFrameLen = AudioSourceNode.DEFAULT_STREAM_READ_FRAME_LEN * 8; // Much overhead fetching small buffers from indexed db, use larger buffer (8192).
12
+ this._inddbAudioBuffer = null;
13
+ this._audioInputStream = null;
14
+ this._aisBufs = null;
15
+ this._active = false;
16
+ this._endOfStream = false;
17
+ this.filledFrames = 0;
18
+ this.channelCountMode = 'explicit';
19
+ this.port.onmessage = (msgEv) => {
20
+ if (msgEv.data) {
21
+ let evType = msgEv.data.eventType;
22
+ if (evType) {
23
+ if ('bufferNotification' === evType) {
24
+ this.filledFrames = msgEv.data.filledFrames;
25
+ if (!this._endOfStream) {
26
+ this.fillBufferObs().subscribe();
27
+ }
28
+ }
29
+ else if ('ended' === evType) {
30
+ //console.debug("Inddb audio source ended playback.");
31
+ let drainTime = 0;
32
+ if (this._inddbAudioBuffer?.sampleRate) {
33
+ drainTime = ArrayAudioBufferSourceNode.QUANTUM_FRAME_LEN / this._inddbAudioBuffer.sampleRate;
34
+ }
35
+ //let dstAny:any=this.context.destination;
36
+ //console.debug('Destination node tail-time: '+dstAny['tail-time']);
37
+ window.setTimeout(() => {
38
+ this.onended?.call(this);
39
+ }, drainTime * 1000);
40
+ }
41
+ }
42
+ }
43
+ };
44
+ }
45
+ fillBufferObs(frameOffset) {
46
+ let obs = new Observable(subscriber => {
47
+ if (frameOffset) {
48
+ subscriber.error(new Error("Starting playback from position not equal zero not supported yet."));
49
+ }
50
+ else {
51
+ let filled = this.filledFrames;
52
+ let bufLen = 0;
53
+ if (this._audioInputStream && this._aisBufs) {
54
+ this._audioInputStream.readObs(this._aisBufs).pipe(expand((read) => {
55
+ if (read && this._aisBufs) {
56
+ let trBuffers = new Array(this.channelCount);
57
+ for (let ch = 0; ch < this.channelCount; ch++) {
58
+ let adCh = this._aisBufs[ch];
59
+ let adChCopy = new Float32Array(read);
60
+ bufLen = adChCopy.length;
61
+ if (read === adCh.length) {
62
+ adChCopy.set(adCh);
63
+ }
64
+ else {
65
+ // Note: slice() does not work here, since it returns a shallow copy.
66
+ for (let i = 0; i < read; i++) {
67
+ adChCopy[i] = adCh[i];
68
+ }
69
+ }
70
+ trBuffers[ch] = adChCopy.buffer;
71
+ }
72
+ this.port.postMessage({
73
+ cmd: 'data',
74
+ chs: this.channelCount,
75
+ audioData: trBuffers
76
+ }, trBuffers);
77
+ filled += read;
78
+ //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Sent "+read+" frames to audio source worklet. Filled: "+filled+", to fill: "+this.bufferFillFrames);
79
+ if (this._audioInputStream && filled < this.bufferFillFrames) {
80
+ //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Next inddb audio input stream readObs");
81
+ return this._audioInputStream.readObs(this._aisBufs);
82
+ }
83
+ else {
84
+ //console.debug("Return EMPTY");
85
+ return EMPTY;
86
+ }
87
+ }
88
+ else {
89
+ //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Return EMPTY (read: "+read+")");
90
+ this._endOfStream = true;
91
+ this.port.postMessage({
92
+ cmd: 'endOfStream'
93
+ });
94
+ return EMPTY;
95
+ }
96
+ })).subscribe(subscriber);
97
+ }
98
+ }
99
+ });
100
+ return obs;
101
+ }
102
+ get inddbAudioBuffer() {
103
+ return this._inddbAudioBuffer;
104
+ }
105
+ set inddbAudioBuffer(value) {
106
+ this._inddbAudioBuffer = value;
107
+ if (this._inddbAudioBuffer?.channelCount) {
108
+ this.channelCount = this._inddbAudioBuffer?.channelCount;
109
+ this.bufferFillFrames = this._inddbAudioBuffer.sampleRate * this._bufferFillSeconds;
110
+ }
111
+ }
112
+ get bufferFillSeconds() {
113
+ return this._bufferFillSeconds;
114
+ }
115
+ set bufferFillSeconds(value) {
116
+ this._bufferFillSeconds = value;
117
+ }
118
+ start(when, offset, duration) {
119
+ if (when) {
120
+ throw Error("when parameter currently not supported by IndexedDbAudioBufferSourceNode class");
121
+ }
122
+ if (this._inddbAudioBuffer) {
123
+ let arrAis = new IndexedDbAudioInputStream(this._inddbAudioBuffer);
124
+ if (offset === undefined && duration === undefined) {
125
+ this._audioInputStream = arrAis;
126
+ }
127
+ else {
128
+ let offsetFrames = 0;
129
+ let durationFrames = undefined;
130
+ if (offset !== undefined) {
131
+ offsetFrames = Math.floor(offset * this._inddbAudioBuffer.sampleRate);
132
+ }
133
+ if (duration !== undefined) {
134
+ durationFrames = Math.floor(duration * this._inddbAudioBuffer.sampleRate);
135
+ }
136
+ //console.debug("Create AsyncEditFloat32ArrayInputStream: offsetFrames:"+offsetFrames+", durationFrames:"+durationFrames);
137
+ this._audioInputStream = new AsyncEditFloat32ArrayInputStream(arrAis, offsetFrames, durationFrames);
138
+ }
139
+ let chs = this._inddbAudioBuffer.channelCount;
140
+ this._aisBufs = new Array(chs);
141
+ for (let ch = 0; ch < chs; ch++) {
142
+ this._aisBufs[ch] = new Float32Array(this._streamReadFrameLen);
143
+ }
144
+ this.fillBufferObs().subscribe({
145
+ complete: () => {
146
+ //console.debug("IndexedDbAudioBufferSourceNode::start: Async play buffer fill completed. Sending start command to audio worklet.");
147
+ if (this._active) {
148
+ this.port.postMessage({ cmd: 'start' });
149
+ if (offset) {
150
+ this._playStartTime = this.context.currentTime - offset;
151
+ }
152
+ else {
153
+ this._playStartTime = this.context.currentTime;
154
+ }
155
+ }
156
+ }
157
+ });
158
+ this._active = true;
159
+ }
160
+ }
161
+ stop() {
162
+ this._active = false;
163
+ this.port.postMessage({ cmd: 'stop' });
164
+ this.onended?.call(this);
165
+ }
166
+ }
167
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZGJfYXVkaW9fYnVmZmVyX3NvdXJjZV9ub2RlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvc3BlZWNocmVjb3JkZXJuZy9zcmMvbGliL2F1ZGlvL3BsYXliYWNrL2luZGRiX2F1ZGlvX2J1ZmZlcl9zb3VyY2Vfbm9kZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsZ0NBQWdDLEVBQStCLE1BQU0saUJBQWlCLENBQUM7QUFDL0YsT0FBTyxFQUF1Qix5QkFBeUIsRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBQ3RGLE9BQU8sRUFBQywwQkFBMEIsRUFBQyxNQUFNLGtDQUFrQyxDQUFDO0FBQzVFLE9BQU8sRUFBQyxLQUFLLEVBQUUsTUFBTSxFQUFPLFVBQVUsRUFBQyxNQUFNLE1BQU0sQ0FBQztBQUNwRCxPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFFcEQsTUFBTSxPQUFPLDhCQUErQixTQUFRLGVBQWU7SUFZakUsWUFBWSxPQUFxQjtRQUUvQixLQUFLLENBQUMsT0FBTyxFQUFFLHNCQUFzQixDQUFDLENBQUM7UUFaakMsdUJBQWtCLEdBQUcsZUFBZSxDQUFDLDJCQUEyQixDQUFDO1FBQ2pFLHFCQUFnQixHQUFHLENBQUMsQ0FBQztRQUNyQix3QkFBbUIsR0FBQyxlQUFlLENBQUMsNkJBQTZCLEdBQUcsQ0FBQyxDQUFDLENBQUUsa0ZBQWtGO1FBQzFKLHNCQUFpQixHQUEyQixJQUFJLENBQUM7UUFDakQsc0JBQWlCLEdBQW1DLElBQUksQ0FBQztRQUN6RCxhQUFRLEdBQXFCLElBQUksQ0FBQztRQUNsQyxZQUFPLEdBQUMsS0FBSyxDQUFDO1FBQ2QsaUJBQVksR0FBQyxLQUFLLENBQUM7UUFDbkIsaUJBQVksR0FBRyxDQUFDLENBQUM7UUFLdkIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLFVBQVUsQ0FBQztRQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFD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OlsiaW1wb3J0IHtBc3luY0VkaXRGbG9hdDMyQXJyYXlJbnB1dFN0cmVhbSwgQXN5bmNGbG9hdDMyQXJyYXlJbnB1dFN0cmVhbX0gZnJvbSBcIi4uLy4uL2lvL3N0cmVhbVwiO1xyXG5pbXBvcnQge0luZGV4ZWREYkF1ZGlvQnVmZmVyLCBJbmRleGVkRGJBdWRpb0lucHV0U3RyZWFtfSBmcm9tIFwiLi4vaW5kZGJfYXVkaW9fYnVmZmVyXCI7XHJcbmltcG9ydCB7QXJyYXlBdWRpb0J1ZmZlclNvdXJjZU5vZGV9IGZyb20gXCIuL2FycmF5X2F1ZGlvX2J1ZmZlcl9zb3VyY2Vfbm9kZVwiO1xyXG5pbXBvcnQge0VNUFRZLCBleHBhbmQsIG1hcCwgT2JzZXJ2YWJsZX0gZnJvbSBcInJ4anNcIjtcclxuaW1wb3J0IHtBdWRpb1NvdXJjZU5vZGV9IGZyb20gXCIuL2F1ZGlvX3NvdXJjZV9ub2RlXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgSW5kZXhlZERiQXVkaW9CdWZmZXJTb3VyY2VOb2RlIGV4dGVuZHMgQXVkaW9Tb3VyY2VOb2RlIHtcclxuXHJcbiAgcHJpdmF0ZSBfYnVmZmVyRmlsbFNlY29uZHMgPSBBdWRpb1NvdXJjZU5vZGUuREVGQVVMVF9CVUZGRVJfRklMTF9TRUNPTkRTO1xyXG4gIHByaXZhdGUgYnVmZmVyRmlsbEZyYW1lcyA9IDA7XHJcbiAgcHJpdmF0ZSBfc3RyZWFtUmVhZEZyYW1lTGVuPUF1ZGlvU291cmNlTm9kZS5ERUZBVUxUX1NUUkVBTV9SRUFEX0ZSQU1FX0xFTiAqIDg7ICAvLyBNdWNoIG92ZXJoZWFkIGZldGNoaW5nIHNtYWxsIGJ1ZmZlcnMgZnJvbSBpbmRleGVkIGRiLCB1c2UgbGFyZ2VyIGJ1ZmZlciAoODE5MikuXHJcbiAgcHJpdmF0ZSBfaW5kZGJBdWRpb0J1ZmZlcjpJbmRleGVkRGJBdWRpb0J1ZmZlcnxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBfYXVkaW9JbnB1dFN0cmVhbTpBc3luY0Zsb2F0MzJBcnJheUlucHV0U3RyZWFtfG51bGw9bnVsbDtcclxuICBwcml2YXRlIF9haXNCdWZzOkZsb2F0MzJBcnJheVtdfG51bGw9bnVsbDtcclxuICBwcml2YXRlIF9hY3RpdmU9ZmFsc2U7XHJcbiAgcHJpdmF0ZSBfZW5kT2ZTdHJlYW09ZmFsc2U7XHJcbiAgcHJpdmF0ZSBmaWxsZWRGcmFtZXMgPSAwO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihjb250ZXh0OiBBdWRpb0NvbnRleHQpIHtcclxuXHJcbiAgICBzdXBlcihjb250ZXh0LCAnYXVkaW8tc291cmNlLXdvcmtsZXQnKTtcclxuICAgIHRoaXMuY2hhbm5lbENvdW50TW9kZSA9ICdleHBsaWNpdCc7XHJcbiAgICB0aGlzLnBvcnQub25tZXNzYWdlID0gKG1zZ0V2OiBNZXNzYWdlRXZlbnQpID0+IHtcclxuICAgICAgaWYgKG1zZ0V2LmRhdGEpIHtcclxuICAgICAgICBsZXQgZXZUeXBlID0gbXNnRXYuZGF0YS5ldmVudFR5cGU7XHJcbiAgICAgICAgaWYgKGV2VHlwZSkge1xyXG4gICAgICAgICAgaWYgKCdidWZmZXJOb3RpZmljYXRpb24nID09PSBldlR5cGUpIHtcclxuICAgICAgICAgICAgdGhpcy5maWxsZWRGcmFtZXMgPSBtc2dFdi5kYXRhLmZpbGxlZEZyYW1lcztcclxuICAgICAgICAgICAgaWYoIXRoaXMuX2VuZE9mU3RyZWFtKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5maWxsQnVmZmVyT2JzKCkuc3Vic2NyaWJlKCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSBpZiAoJ2VuZGVkJyA9PT0gZXZUeXBlKSB7XHJcbiAgICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkluZGRiIGF1ZGlvIHNvdXJjZSBlbmRlZCBwbGF5YmFjay5cIik7XHJcbiAgICAgICAgICAgIGxldCBkcmFpblRpbWUgPSAwO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5faW5kZGJBdWRpb0J1ZmZlcj8uc2FtcGxlUmF0ZSkge1xyXG4gICAgICAgICAgICAgIGRyYWluVGltZSA9IEFycmF5QXVkaW9CdWZmZXJTb3VyY2VOb2RlLlFVQU5UVU1fRlJBTUVfTEVOIC8gdGhpcy5faW5kZGJBdWRpb0J1ZmZlci5zYW1wbGVSYXRlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIC8vbGV0IGRzdEFueTphbnk9dGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uO1xyXG4gICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoJ0Rlc3RpbmF0aW9uIG5vZGUgdGFpbC10aW1lOiAnK2RzdEFueVsndGFpbC10aW1lJ10pO1xyXG4gICAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgdGhpcy5vbmVuZGVkPy5jYWxsKHRoaXMpO1xyXG4gICAgICAgICAgICB9LCBkcmFpblRpbWUgKiAxMDAwKTtcclxuXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGZpbGxCdWZmZXJPYnMoZnJhbWVPZmZzZXQ/Om51bWJlcik6T2JzZXJ2YWJsZTxudW1iZXJ8bnVsbD4ge1xyXG5cclxuICAgICAgbGV0IG9icyA9IG5ldyBPYnNlcnZhYmxlPG51bWJlciB8IG51bGw+KHN1YnNjcmliZXIgPT4ge1xyXG4gICAgICAgIGlmKGZyYW1lT2Zmc2V0KXtcclxuICAgICAgICAgIHN1YnNjcmliZXIuZXJyb3IobmV3IEVycm9yKFwiU3RhcnRpbmcgcGxheWJhY2sgZnJvbSBwb3NpdGlvbiBub3QgZXF1YWwgemVybyBub3Qgc3VwcG9ydGVkIHlldC5cIikpO1xyXG4gICAgICAgIH1lbHNlIHtcclxuICAgICAgICAgIGxldCBmaWxsZWQgPSB0aGlzLmZpbGxlZEZyYW1lcztcclxuICAgICAgICAgIGxldCBidWZMZW4gPSAwO1xyXG4gICAgICAgICAgaWYgKHRoaXMuX2F1ZGlvSW5wdXRTdHJlYW0gJiYgdGhpcy5fYWlzQnVmcykge1xyXG4gICAgICAgICAgICB0aGlzLl9hdWRpb0lucHV0U3RyZWFtLnJlYWRPYnModGhpcy5fYWlzQnVmcykucGlwZShcclxuICAgICAgICAgICAgICBleHBhbmQoKHJlYWQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgaWYgKHJlYWQgJiYgdGhpcy5fYWlzQnVmcykge1xyXG4gICAgICAgICAgICAgICAgICAgIGxldCB0ckJ1ZmZlcnMgPSBuZXcgQXJyYXk8YW55Pih0aGlzLmNoYW5uZWxDb3VudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgY2ggPSAwOyBjaCA8IHRoaXMuY2hhbm5lbENvdW50OyBjaCsrKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICBsZXQgYWRDaCA9IHRoaXMuX2Fpc0J1ZnNbY2hdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgbGV0IGFkQ2hDb3B5ID0gbmV3IEZsb2F0MzJBcnJheShyZWFkKTtcclxuICAgICAgICAgICAgICAgICAgICAgIGJ1ZkxlbiA9IGFkQ2hDb3B5Lmxlbmd0aDtcclxuICAgICAgICAgICAgICAgICAgICAgIGlmKHJlYWQ9PT1hZENoLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBhZENoQ29weS5zZXQoYWRDaCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gTm90ZTogc2xpY2UoKSBkb2VzIG5vdCB3b3JrIGhlcmUsIHNpbmNlIGl0IHJldHVybnMgYSBzaGFsbG93IGNvcHkuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcihsZXQgaT0wO2k8cmVhZDtpKyspe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGFkQ2hDb3B5W2ldPWFkQ2hbaV07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgIHRyQnVmZmVyc1tjaF0gPSBhZENoQ29weS5idWZmZXI7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICBjbWQ6ICdkYXRhJyxcclxuICAgICAgICAgICAgICAgICAgICAgIGNoczogdGhpcy5jaGFubmVsQ291bnQsXHJcbiAgICAgICAgICAgICAgICAgICAgICBhdWRpb0RhdGE6IHRyQnVmZmVyc1xyXG4gICAgICAgICAgICAgICAgICAgIH0sIHRyQnVmZmVycyk7XHJcbiAgICAgICAgICAgICAgICAgICAgZmlsbGVkICs9IHJlYWQ7XHJcbiAgICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiSW5kZXhlZERiQXVkaW9CdWZmZXJTb3VyY2VOb2RlOjpmaWxsQnVmZmVyT2JzOiBTZW50IFwiK3JlYWQrXCIgZnJhbWVzIHRvIGF1ZGlvIHNvdXJjZSB3b3JrbGV0LiBGaWxsZWQ6IFwiK2ZpbGxlZCtcIiwgdG8gZmlsbDogXCIrdGhpcy5idWZmZXJGaWxsRnJhbWVzKTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5fYXVkaW9JbnB1dFN0cmVhbSAmJiBmaWxsZWQgPCB0aGlzLmJ1ZmZlckZpbGxGcmFtZXMpIHtcclxuICAgICAgICAgICAgICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIkluZGV4ZWREYkF1ZGlvQnVmZmVyU291cmNlTm9kZTo6ZmlsbEJ1ZmZlck9iczogTmV4dCBpbmRkYiBhdWRpbyBpbnB1dCBzdHJlYW0gcmVhZE9ic1wiKTtcclxuICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9hdWRpb0lucHV0U3RyZWFtLnJlYWRPYnModGhpcy5fYWlzQnVmcyk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgIC8vY29uc29sZS5kZWJ1ZyhcIlJldHVybiBFTVBUWVwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBFTVBUWTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiSW5kZXhlZERiQXVkaW9CdWZmZXJTb3VyY2VOb2RlOjpmaWxsQnVmZmVyT2JzOiBSZXR1cm4gRU1QVFkgKHJlYWQ6IFwiK3JlYWQrXCIpXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2VuZE9mU3RyZWFtPXRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wb3J0LnBvc3RNZXNzYWdlKHtcclxuICAgICAgICAgICAgICAgICAgICAgIGNtZDogJ2VuZE9mU3RyZWFtJ1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBFTVBUWTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgKS5zdWJzY3JpYmUoc3Vic2NyaWJlcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgICAgcmV0dXJuIG9icztcclxuICB9XHJcblxyXG5cclxuICBnZXQgaW5kZGJBdWRpb0J1ZmZlcigpOiBJbmRleGVkRGJBdWRpb0J1ZmZlciB8IG51bGwge1xyXG4gICAgcmV0dXJuIHRoaXMuX2luZGRiQXVkaW9CdWZmZXJcclxuICB9XHJcblxyXG4gIHNldCBpbmRkYkF1ZGlvQnVmZmVyKHZhbHVlOiBJbmRleGVkRGJBdWRpb0J1ZmZlciB8IG51bGwpIHtcclxuICAgIHRoaXMuX2luZGRiQXVkaW9CdWZmZXIgPSB2YWx1ZTtcclxuICAgIGlmICh0aGlzLl9pbmRkYkF1ZGlvQnVmZmVyPy5jaGFubmVsQ291bnQpIHtcclxuICAgICAgdGhpcy5jaGFubmVsQ291bnQgPSB0aGlzLl9pbmRkYkF1ZGlvQnVmZmVyPy5jaGFubmVsQ291bnQ7XHJcbiAgICAgIHRoaXMuYnVmZmVyRmlsbEZyYW1lcyA9IHRoaXMuX2luZGRiQXVkaW9CdWZmZXIuc2FtcGxlUmF0ZSAqIHRoaXMuX2J1ZmZlckZpbGxTZWNvbmRzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0IGJ1ZmZlckZpbGxTZWNvbmRzKCk6IG51bWJlciB7XHJcbiAgICByZXR1cm4gdGhpcy5fYnVmZmVyRmlsbFNlY29uZHM7XHJcbiAgfVxyXG5cclxuICBzZXQgYnVmZmVyRmlsbFNlY29uZHModmFsdWU6IG51bWJlcikge1xyXG4gICAgdGhpcy5fYnVmZmVyRmlsbFNlY29uZHMgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIHN0YXJ0KHdoZW4/OiBudW1iZXIgfCB1bmRlZmluZWQsb2Zmc2V0PzogbnVtYmVyIHwgdW5kZWZpbmVkLGR1cmF0aW9uPzogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XHJcbiAgICBpZiAod2hlbikge1xyXG4gICAgICB0aHJvdyBFcnJvcihcIndoZW4gcGFyYW1ldGVyIGN1cnJlbnRseSBub3Qgc3VwcG9ydGVkIGJ5IEluZGV4ZWREYkF1ZGlvQnVmZmVyU291cmNlTm9kZSBjbGFzc1wiKVxyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLl9pbmRkYkF1ZGlvQnVmZmVyKSB7XHJcbiAgICAgIGxldCBhcnJBaXM9bmV3IEluZGV4ZWREYkF1ZGlvSW5wdXRTdHJlYW0odGhpcy5faW5kZGJBdWRpb0J1ZmZlcik7XHJcbiAgICAgIGlmKG9mZnNldD09PXVuZGVmaW5lZCAmJiBkdXJhdGlvbj09PXVuZGVmaW5lZCl7XHJcbiAgICAgICAgdGhpcy5fYXVkaW9JbnB1dFN0cmVhbSA9IGFyckFpcztcclxuICAgICAgfWVsc2V7XHJcbiAgICAgICAgbGV0IG9mZnNldEZyYW1lcz0wO1xyXG4gICAgICAgIGxldCBkdXJhdGlvbkZyYW1lcz11bmRlZmluZWQ7XHJcbiAgICAgICAgaWYob2Zmc2V0IT09dW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICBvZmZzZXRGcmFtZXM9TWF0aC5mbG9vcihvZmZzZXQgKiB0aGlzLl9pbmRkYkF1ZGlvQnVmZmVyLnNhbXBsZVJhdGUpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZihkdXJhdGlvbiE9PXVuZGVmaW5lZCl7XHJcbiAgICAgICAgICBkdXJhdGlvbkZyYW1lcz1NYXRoLmZsb29yKGR1cmF0aW9uICogdGhpcy5faW5kZGJBdWRpb0J1ZmZlci5zYW1wbGVSYXRlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiQ3JlYXRlIEFzeW5jRWRpdEZsb2F0MzJBcnJheUlucHV0U3RyZWFtOiBvZmZzZXRGcmFtZXM6XCIrb2Zmc2V0RnJhbWVzK1wiLCBkdXJhdGlvbkZyYW1lczpcIitkdXJhdGlvbkZyYW1lcyk7XHJcbiAgICAgICAgdGhpcy5fYXVkaW9JbnB1dFN0cmVhbT1uZXcgQXN5bmNFZGl0RmxvYXQzMkFycmF5SW5wdXRTdHJlYW0oYXJyQWlzLG9mZnNldEZyYW1lcyxkdXJhdGlvbkZyYW1lcyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxldCBjaHM9dGhpcy5faW5kZGJBdWRpb0J1ZmZlci5jaGFubmVsQ291bnQ7XHJcbiAgICAgIHRoaXMuX2Fpc0J1ZnM9bmV3IEFycmF5PEZsb2F0MzJBcnJheT4oY2hzKTtcclxuICAgICAgZm9yKGxldCBjaD0wO2NoPGNocztjaCsrKXtcclxuICAgICAgICB0aGlzLl9haXNCdWZzW2NoXT1uZXcgRmxvYXQzMkFycmF5KHRoaXMuX3N0cmVhbVJlYWRGcmFtZUxlbik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuZmlsbEJ1ZmZlck9icygpLnN1YnNjcmliZSh7XHJcbiAgICAgICAgY29tcGxldGU6ICgpPT57XHJcbiAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJJbmRleGVkRGJBdWRpb0J1ZmZlclNvdXJjZU5vZGU6OnN0YXJ0OiBBc3luYyBwbGF5IGJ1ZmZlciBmaWxsIGNvbXBsZXRlZC4gU2VuZGluZyBzdGFydCBjb21tYW5kIHRvIGF1ZGlvIHdvcmtsZXQuXCIpO1xyXG4gICAgICAgICAgaWYodGhpcy5fYWN0aXZlKSB7XHJcbiAgICAgICAgICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZSh7Y21kOiAnc3RhcnQnfSk7XHJcbiAgICAgICAgICAgIGlmIChvZmZzZXQpIHtcclxuICAgICAgICAgICAgICB0aGlzLl9wbGF5U3RhcnRUaW1lID0gdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lIC0gb2Zmc2V0O1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIHRoaXMuX3BsYXlTdGFydFRpbWUgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pXHJcbiAgICB0aGlzLl9hY3RpdmU9dHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHN0b3AoKSB7XHJcbiAgICB0aGlzLl9hY3RpdmU9ZmFsc2U7XHJcbiAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe2NtZDogJ3N0b3AnfSk7XHJcbiAgICB0aGlzLm9uZW5kZWQ/LmNhbGwodGhpcyk7XHJcbiAgfVxyXG5cclxufVxyXG5cclxuIl19
@@ -0,0 +1,218 @@
1
+ import { AsyncEditFloat32ArrayInputStream } from "../../io/stream";
2
+ import { ArrayAudioBufferSourceNode } from "./array_audio_buffer_source_node";
3
+ import { EMPTY, expand, Observable } from "rxjs";
4
+ import { AudioSourceNode } from "./audio_source_node";
5
+ import { NetAudioInputStream } from "../net_audio_buffer";
6
+ export class NetAudioBufferSourceNode extends AudioSourceNode {
7
+ constructor(context) {
8
+ super(context, 'audio-source-worklet');
9
+ this._bufferFillSeconds = AudioSourceNode.DEFAULT_BUFFER_FILL_SECONDS;
10
+ this.bufferFillFrames = 0;
11
+ this._streamReadFrameLen = AudioSourceNode.DEFAULT_STREAM_READ_FRAME_LEN * 8; // Much overhead fetching small buffers from indexed db, use larger buffer (8192).
12
+ this._netAudioBuffer = null;
13
+ this._audioInputStream = null;
14
+ this._aisBufs = null;
15
+ this._active = false;
16
+ this.stalled = false;
17
+ this._endOfStream = false;
18
+ this.readDataSubscription = null;
19
+ this.filledFrames = 0;
20
+ this.stalledStartTime = null;
21
+ this.stalledTime = 0;
22
+ this.stopEndTime = null;
23
+ this.channelCountMode = 'explicit';
24
+ this.port.onmessage = (msgEv) => {
25
+ if (msgEv.data) {
26
+ let evType = msgEv.data.eventType;
27
+ if (evType) {
28
+ if ('bufferNotification' === evType) {
29
+ this.filledFrames = msgEv.data.filledFrames;
30
+ //console.debug("IndexedDbAudioBufferSourceNode: Buffer notification: filled frames: " + this.filledFrames);
31
+ if (!this._endOfStream) {
32
+ this.fillBufferObs().subscribe();
33
+ }
34
+ }
35
+ else if ('ended' === evType) {
36
+ //console.debug("Inddb audio source ended playback.");
37
+ let drainTime = 0;
38
+ if (this._netAudioBuffer?.sampleRate) {
39
+ drainTime = ArrayAudioBufferSourceNode.QUANTUM_FRAME_LEN / this._netAudioBuffer.sampleRate;
40
+ }
41
+ //let dstAny:any=this.context.destination;
42
+ //console.debug('Destination node tail-time: '+dstAny['tail-time']);
43
+ window.setTimeout(() => {
44
+ this.stopEndTime = this.context.currentTime;
45
+ this._active = false;
46
+ this.onended?.call(this);
47
+ }, drainTime * 1000);
48
+ }
49
+ else if ('stalled' === evType) {
50
+ console.debug('Playback stalled...');
51
+ this.stalled = true;
52
+ this.stalledStartTime = this.context.currentTime;
53
+ }
54
+ else if ('resumed' === evType) {
55
+ console.debug('Playback resumed after stall.');
56
+ this.stalled = false;
57
+ if (this.stalledStartTime != null) {
58
+ this.stalledTime += this.context.currentTime - this.stalledStartTime;
59
+ this.stalledStartTime = null;
60
+ }
61
+ }
62
+ }
63
+ }
64
+ };
65
+ }
66
+ fillBufferObs(frameOffset) {
67
+ return new Observable(subscriber => {
68
+ if (frameOffset) {
69
+ subscriber.error(new Error("Starting playback from position not equal zero not supported yet."));
70
+ }
71
+ else {
72
+ let filled = this.filledFrames;
73
+ let bufLen = 0;
74
+ if (this._audioInputStream && this._aisBufs && (this.readDataSubscription == null || this.readDataSubscription?.closed)) {
75
+ this.readDataSubscription = this._audioInputStream.readObs(this._aisBufs).pipe(expand((read) => {
76
+ if (read && this._aisBufs) {
77
+ let trBuffers = new Array(this.channelCount);
78
+ for (let ch = 0; ch < this.channelCount; ch++) {
79
+ let adCh = this._aisBufs[ch];
80
+ let adChCopy = new Float32Array(read);
81
+ bufLen = adChCopy.length;
82
+ if (read === adCh.length) {
83
+ adChCopy.set(adCh);
84
+ }
85
+ else {
86
+ // Note: slice() does not work here, since it returns a shallow copy.
87
+ for (let i = 0; i < read; i++) {
88
+ adChCopy[i] = adCh[i];
89
+ }
90
+ }
91
+ trBuffers[ch] = adChCopy.buffer;
92
+ }
93
+ this.port.postMessage({
94
+ cmd: 'data',
95
+ chs: this.channelCount,
96
+ audioData: trBuffers
97
+ }, trBuffers);
98
+ filled += read;
99
+ //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Sent "+read+" frames to audio source worklet. Filled: "+filled+", to fill: "+this.bufferFillFrames);
100
+ if (this._audioInputStream && filled < this.bufferFillFrames) {
101
+ //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Next inddb audio input stream readObs");
102
+ return this._audioInputStream.readObs(this._aisBufs);
103
+ }
104
+ else {
105
+ if (this.stalled) {
106
+ this.port.postMessage({
107
+ cmd: 'continue'
108
+ });
109
+ }
110
+ return EMPTY;
111
+ }
112
+ }
113
+ else {
114
+ //console.debug("IndexedDbAudioBufferSourceNode::fillBufferObs: Return EMPTY (read: "+read+")");
115
+ this._endOfStream = true;
116
+ this.port.postMessage({
117
+ cmd: 'endOfStream'
118
+ });
119
+ return EMPTY;
120
+ }
121
+ })).subscribe(subscriber);
122
+ }
123
+ }
124
+ });
125
+ }
126
+ get netAudioBuffer() {
127
+ return this._netAudioBuffer;
128
+ }
129
+ set netAudioBuffer(value) {
130
+ this._netAudioBuffer = value;
131
+ if (this._netAudioBuffer?.channelCount) {
132
+ this.channelCount = this._netAudioBuffer?.channelCount;
133
+ this.bufferFillFrames = this._netAudioBuffer.sampleRate * this._bufferFillSeconds;
134
+ }
135
+ }
136
+ get bufferFillSeconds() {
137
+ return this._bufferFillSeconds;
138
+ }
139
+ set bufferFillSeconds(value) {
140
+ this._bufferFillSeconds = value;
141
+ }
142
+ start(when, offset, duration) {
143
+ if (when) {
144
+ throw Error("when parameter currently not supported by IndexedDbAudioBufferSourceNode class");
145
+ }
146
+ this._playStartTime = null;
147
+ this.stopEndTime = null;
148
+ this.stalledTime = 0;
149
+ this.stalledStartTime = null;
150
+ if (this._netAudioBuffer) {
151
+ let arrAis = new NetAudioInputStream(this._netAudioBuffer);
152
+ if (offset === undefined && duration === undefined) {
153
+ this._audioInputStream = arrAis;
154
+ }
155
+ else {
156
+ let offsetFrames = 0;
157
+ let durationFrames = undefined;
158
+ if (offset !== undefined) {
159
+ offsetFrames = Math.floor(offset * this._netAudioBuffer.sampleRate);
160
+ }
161
+ if (duration !== undefined) {
162
+ durationFrames = Math.floor(duration * this._netAudioBuffer.sampleRate);
163
+ }
164
+ //console.error("Playback selection not supported yet!");
165
+ this._audioInputStream = new AsyncEditFloat32ArrayInputStream(arrAis, offsetFrames, durationFrames);
166
+ }
167
+ let chs = this._netAudioBuffer.channelCount;
168
+ this._aisBufs = new Array(chs);
169
+ for (let ch = 0; ch < chs; ch++) {
170
+ this._aisBufs[ch] = new Float32Array(this._streamReadFrameLen);
171
+ }
172
+ this.fillBufferObs().subscribe({
173
+ complete: () => {
174
+ //console.debug("IndexedDbAudioBufferSourceNode::start: Async play buffer fill completed. Sending start command to audio worklet.");
175
+ if (this._active) {
176
+ this.port.postMessage({ cmd: 'start' });
177
+ if (offset) {
178
+ this._playStartTime = this.context.currentTime - offset;
179
+ }
180
+ else {
181
+ this._playStartTime = this.context.currentTime;
182
+ }
183
+ }
184
+ }
185
+ });
186
+ this._active = true;
187
+ }
188
+ }
189
+ stop() {
190
+ this._active = false;
191
+ this.port.postMessage({ cmd: 'stop' });
192
+ this.onended?.call(this);
193
+ }
194
+ get playPositionTime() {
195
+ let ppt = null;
196
+ if (this._playStartTime !== null) {
197
+ if (this._active) {
198
+ if (this.stalledStartTime == null) {
199
+ ppt = this.context.currentTime - this._playStartTime - this.stalledTime;
200
+ }
201
+ else {
202
+ ppt = this.stalledStartTime - this._playStartTime - this.stalledTime;
203
+ }
204
+ }
205
+ else {
206
+ if (this.stopEndTime != null) {
207
+ // if(this._netAudioBuffer?.frameLen !=null && this._netAudioBuffer.sampleRate) {
208
+ // ppt = this._netAudioBuffer?.frameLen / this._netAudioBuffer?.sampleRate;
209
+ // }else{
210
+ ppt = this.stopEndTime - this._playStartTime - this.stalledTime;
211
+ //}
212
+ }
213
+ }
214
+ }
215
+ return ppt;
216
+ }
217
+ }
218
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0X2F1ZGlvX2J1ZmZlcl9zb3VyY2Vfbm9kZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3NwZWVjaHJlY29yZGVybmcvc3JjL2xpYi9hdWRpby9wbGF5YmFjay9uZXRfYXVkaW9fYnVmZmVyX3NvdXJjZV9ub2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxnQ0FBZ0MsRUFBK0IsTUFBTSxpQkFBaUIsQ0FBQztBQUMvRixPQUFPLEVBQUMsMEJBQTBCLEVBQUMsTUFBTSxrQ0FBa0MsQ0FBQztBQUM1RSxPQUFPLEVBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQWUsTUFBTSxNQUFNLENBQUM7QUFDN0QsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQ3BELE9BQU8sRUFBaUIsbUJBQW1CLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUV4RSxNQUFNLE9BQU8sd0JBQXlCLFNBQVEsZUFBZTtJQW1CM0QsWUFBWSxPQUFxQjtRQUUvQixLQUFLLENBQUMsT0FBTyxFQUFFLHNCQUFzQixDQUFDLENBQUM7UUFuQmpDLHVCQUFrQixHQUFHLGVBQWUsQ0FBQywyQkFBMkIsQ0FBQztRQUNqRSxxQkFBZ0IsR0FBRyxDQUFDLENBQUM7UUFDckIsd0JBQW1CLEdBQUMsZUFBZSxDQUFDLDZCQUE2QixHQUFHLENBQUMsQ0FBQyxDQUFFLGtGQUFrRjtRQUMxSixvQkFBZSxHQUFxQixJQUFJLENBQUM7UUFDekMsc0JBQWlCLEdBQW1DLElBQUksQ0FBQztRQUN6RCxhQUFRLEdBQXFCLElBQUksQ0FBQztRQUNsQyxZQUFPLEdBQUMsS0FBSyxDQUFDO1FBQ2QsWUFBTyxHQUFDLEtBQUssQ0FBQztRQUNkLGlCQUFZLEdBQUMsS0FBSyxDQUFDO1FBQ25CLHlCQUFvQixHQUFtQixJQUFJLENBQUM7UUFDNUMsaUJBQVksR0FBRyxDQUFDLENBQUM7UUFFakIscUJBQWdC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QUFDO1FBQ3JDLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFRCxJQUFJLGdCQUFnQjtRQUNsQixJQUFJLEdBQUcsR0FBYSxJQUFJLENBQUM7UUFDekIsSUFBRyxJQUFJLENBQUMsY0FBYyxLQUFHLElBQUksRUFBRTtZQUM3QixJQUFHLElBQUksQ0FBQyxPQUFPLEVBQUU7Z0JBQ2YsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLElBQUksSUFBSSxFQUFFO29CQUNqQyxHQUFHLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDO2lCQUN6RTtxQkFBTTtvQkFDTCxHQUFHLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQztpQkFDdEU7YUFDRjtpQkFBSTtnQkFDSCxJQUFHLElBQUksQ0FBQyxXQUFXLElBQUUsSUFBSSxFQUFDO29CQUN4QixpRkFBaUY7b0JBQ2pGLDZFQUE2RTtvQkFDN0UsU0FBUztvQkFDUCxHQUFHLEdBQUcsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUM7b0JBQ2xFLEdBQUc7aUJBQ0o7YUFDRjtTQUNGO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0NBRUYiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FzeW5jRWRpdEZsb2F0MzJBcnJheUlucHV0U3RyZWFtLCBBc3luY0Zsb2F0MzJBcnJheUlucHV0U3RyZWFtfSBmcm9tIFwiLi4vLi4vaW8vc3RyZWFtXCI7XHJcbmltcG9ydCB7QXJyYXlBdWRpb0J1ZmZlclNvdXJjZU5vZGV9IGZyb20gXCIuL2FycmF5X2F1ZGlvX2J1ZmZlcl9zb3VyY2Vfbm9kZVwiO1xyXG5pbXBvcnQge0VNUFRZLCBleHBhbmQsIE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbn0gZnJvbSBcInJ4anNcIjtcclxuaW1wb3J0IHtBdWRpb1NvdXJjZU5vZGV9IGZyb20gXCIuL2F1ZGlvX3NvdXJjZV9ub2RlXCI7XHJcbmltcG9ydCB7TmV0QXVkaW9CdWZmZXIsIE5ldEF1ZGlvSW5wdXRTdHJlYW19IGZyb20gXCIuLi9uZXRfYXVkaW9fYnVmZmVyXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgTmV0QXVkaW9CdWZmZXJTb3VyY2VOb2RlIGV4dGVuZHMgQXVkaW9Tb3VyY2VOb2RlIHtcclxuXHJcbiAgcHJpdmF0ZSBfYnVmZmVyRmlsbFNlY29uZHMgPSBBdWRpb1NvdXJjZU5vZGUuREVGQVVMVF9CVUZGRVJfRklMTF9TRUNPTkRTO1xyXG4gIHByaXZhdGUgYnVmZmVyRmlsbEZyYW1lcyA9IDA7XHJcbiAgcHJpdmF0ZSBfc3RyZWFtUmVhZEZyYW1lTGVuPUF1ZGlvU291cmNlTm9kZS5ERUZBVUxUX1NUUkVBTV9SRUFEX0ZSQU1FX0xFTiAqIDg7ICAvLyBNdWNoIG92ZXJoZWFkIGZldGNoaW5nIHNtYWxsIGJ1ZmZlcnMgZnJvbSBpbmRleGVkIGRiLCB1c2UgbGFyZ2VyIGJ1ZmZlciAoODE5MikuXHJcbiAgcHJpdmF0ZSBfbmV0QXVkaW9CdWZmZXI6TmV0QXVkaW9CdWZmZXJ8bnVsbD1udWxsO1xyXG4gIHByaXZhdGUgX2F1ZGlvSW5wdXRTdHJlYW06QXN5bmNGbG9hdDMyQXJyYXlJbnB1dFN0cmVhbXxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBfYWlzQnVmczpGbG9hdDMyQXJyYXlbXXxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBfYWN0aXZlPWZhbHNlO1xyXG4gIHByaXZhdGUgc3RhbGxlZD1mYWxzZTtcclxuICBwcml2YXRlIF9lbmRPZlN0cmVhbT1mYWxzZTtcclxuICBwcml2YXRlIHJlYWREYXRhU3Vic2NyaXB0aW9uOlN1YnNjcmlwdGlvbnxudWxsPW51bGw7XHJcbiAgcHJpdmF0ZSBmaWxsZWRGcmFtZXMgPSAwO1xyXG5cclxuICBwcml2YXRlIHN0YWxsZWRTdGFydFRpbWU6bnVtYmVyfG51bGw9bnVsbDtcclxuICBwcml2YXRlIHN0YWxsZWRUaW1lOm51bWJlcj0wO1xyXG5cclxuICBwcml2YXRlIHN0b3BFbmRUaW1lOm51bWJlcnxudWxsPW51bGw7XHJcblxyXG4gIGNvbnN0cnVjdG9yKGNvbnRleHQ6IEF1ZGlvQ29udGV4dCkge1xyXG5cclxuICAgIHN1cGVyKGNvbnRleHQsICdhdWRpby1zb3VyY2Utd29ya2xldCcpO1xyXG4gICAgdGhpcy5jaGFubmVsQ291bnRNb2RlID0gJ2V4cGxpY2l0JztcclxuICAgIHRoaXMucG9ydC5vbm1lc3NhZ2UgPSAobXNnRXY6IE1lc3NhZ2VFdmVudCkgPT4ge1xyXG4gICAgICBpZiAobXNnRXYuZGF0YSkge1xyXG4gICAgICAgIGxldCBldlR5cGUgPSBtc2dFdi5kYXRhLmV2ZW50VHlwZTtcclxuICAgICAgICBpZiAoZXZUeXBlKSB7XHJcbiAgICAgICAgICBpZiAoJ2J1ZmZlck5vdGlmaWNhdGlvbicgPT09IGV2VHlwZSkge1xyXG4gICAgICAgICAgICB0aGlzLmZpbGxlZEZyYW1lcyA9IG1zZ0V2LmRhdGEuZmlsbGVkRnJhbWVzO1xyXG4gICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJJbmRleGVkRGJBdWRpb0J1ZmZlclNvdXJjZU5vZGU6IEJ1ZmZlciBub3RpZmljYXRpb246IGZpbGxlZCBmcmFtZXM6IFwiICsgdGhpcy5maWxsZWRGcmFtZXMpO1xyXG4gICAgICAgICAgICBpZighdGhpcy5fZW5kT2ZTdHJlYW0pIHtcclxuICAgICAgICAgICAgICB0aGlzLmZpbGxCdWZmZXJPYnMoKS5zdWJzY3JpYmUoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIGlmICgnZW5kZWQnID09PSBldlR5cGUpIHtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiSW5kZGIgYXVkaW8gc291cmNlIGVuZGVkIHBsYXliYWNrLlwiKTtcclxuICAgICAgICAgICAgbGV0IGRyYWluVGltZSA9IDA7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLl9uZXRBdWRpb0J1ZmZlcj8uc2FtcGxlUmF0ZSkge1xyXG4gICAgICAgICAgICAgIGRyYWluVGltZSA9IEFycmF5QXVkaW9CdWZmZXJTb3VyY2VOb2RlLlFVQU5UVU1fRlJBTUVfTEVOIC8gdGhpcy5fbmV0QXVkaW9CdWZmZXIuc2FtcGxlUmF0ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAvL2xldCBkc3RBbnk6YW55PXRoaXMuY29udGV4dC5kZXN0aW5hdGlvbjtcclxuICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKCdEZXN0aW5hdGlvbiBub2RlIHRhaWwtdGltZTogJytkc3RBbnlbJ3RhaWwtdGltZSddKTtcclxuICAgICAgICAgICAgd2luZG93LnNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHRoaXMuc3RvcEVuZFRpbWU9dGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lO1xyXG4gICAgICAgICAgICAgIHRoaXMuX2FjdGl2ZT1mYWxzZTtcclxuICAgICAgICAgICAgICB0aGlzLm9uZW5kZWQ/LmNhbGwodGhpcyk7XHJcbiAgICAgICAgICAgIH0sIGRyYWluVGltZSAqIDEwMDApO1xyXG5cclxuICAgICAgICAgIH1lbHNlIGlmICgnc3RhbGxlZCcgPT09IGV2VHlwZSkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmRlYnVnKCdQbGF5YmFjayBzdGFsbGVkLi4uJyk7XHJcbiAgICAgICAgICAgIHRoaXMuc3RhbGxlZD10cnVlO1xyXG4gICAgICAgICAgICB0aGlzLnN0YWxsZWRTdGFydFRpbWU9dGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lO1xyXG4gICAgICAgICAgfWVsc2UgaWYgKCdyZXN1bWVkJyA9PT0gZXZUeXBlKSB7XHJcbiAgICAgICAgICAgIGNvbnNvbGUuZGVidWcoJ1BsYXliYWNrIHJlc3VtZWQgYWZ0ZXIgc3RhbGwuJyk7XHJcbiAgICAgICAgICAgIHRoaXMuc3RhbGxlZD1mYWxzZTtcclxuICAgICAgICAgICAgaWYodGhpcy5zdGFsbGVkU3RhcnRUaW1lIT1udWxsKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5zdGFsbGVkVGltZSArPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgLSB0aGlzLnN0YWxsZWRTdGFydFRpbWU7XHJcbiAgICAgICAgICAgICAgdGhpcy5zdGFsbGVkU3RhcnRUaW1lID0gbnVsbDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBmaWxsQnVmZmVyT2JzKGZyYW1lT2Zmc2V0PzpudW1iZXIpOk9ic2VydmFibGU8bnVtYmVyfG51bGw+IHtcclxuXHJcbiAgICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZTxudW1iZXIgfCBudWxsPihzdWJzY3JpYmVyID0+IHtcclxuICAgICAgICBpZihmcmFtZU9mZnNldCl7XHJcbiAgICAgICAgICBzdWJzY3JpYmVyLmVycm9yKG5ldyBFcnJvcihcIlN0YXJ0aW5nIHBsYXliYWNrIGZyb20gcG9zaXRpb24gbm90IGVxdWFsIHplcm8gbm90IHN1cHBvcnRlZCB5ZXQuXCIpKTtcclxuICAgICAgICB9ZWxzZSB7XHJcbiAgICAgICAgICBsZXQgZmlsbGVkID0gdGhpcy5maWxsZWRGcmFtZXM7XHJcbiAgICAgICAgICBsZXQgYnVmTGVuID0gMDtcclxuICAgICAgICAgIGlmICh0aGlzLl9hdWRpb0lucHV0U3RyZWFtICYmIHRoaXMuX2Fpc0J1ZnMgJiYgKHRoaXMucmVhZERhdGFTdWJzY3JpcHRpb249PW51bGwgfHwgdGhpcy5yZWFkRGF0YVN1YnNjcmlwdGlvbj8uY2xvc2VkKSkge1xyXG4gICAgICAgICAgICB0aGlzLnJlYWREYXRhU3Vic2NyaXB0aW9uPXRoaXMuX2F1ZGlvSW5wdXRTdHJlYW0ucmVhZE9icyh0aGlzLl9haXNCdWZzKS5waXBlKFxyXG4gICAgICAgICAgICAgIGV4cGFuZCgocmVhZCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICBpZiAocmVhZCAmJiB0aGlzLl9haXNCdWZzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbGV0IHRyQnVmZmVycyA9IG5ldyBBcnJheTxhbnk+KHRoaXMuY2hhbm5lbENvdW50KTtcclxuICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBjaCA9IDA7IGNoIDwgdGhpcy5jaGFubmVsQ291bnQ7IGNoKyspIHtcclxuICAgICAgICAgICAgICAgICAgICAgIGxldCBhZENoID0gdGhpcy5fYWlzQnVmc1tjaF07XHJcbiAgICAgICAgICAgICAgICAgICAgICBsZXQgYWRDaENvcHkgPSBuZXcgRmxvYXQzMkFycmF5KHJlYWQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgYnVmTGVuID0gYWRDaENvcHkubGVuZ3RoO1xyXG4gICAgICAgICAgICAgICAgICAgICAgaWYocmVhZD09PWFkQ2gubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGFkQ2hDb3B5LnNldChhZENoKTtcclxuICAgICAgICAgICAgICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBOb3RlOiBzbGljZSgpIGRvZXMgbm90IHdvcmsgaGVyZSwgc2luY2UgaXQgcmV0dXJucyBhIHNoYWxsb3cgY29weS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgZm9yKGxldCBpPTA7aTxyZWFkO2krKyl7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgYWRDaENvcHlbaV09YWRDaFtpXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgdHJCdWZmZXJzW2NoXSA9IGFkQ2hDb3B5LmJ1ZmZlcjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wb3J0LnBvc3RNZXNzYWdlKHtcclxuICAgICAgICAgICAgICAgICAgICAgIGNtZDogJ2RhdGEnLFxyXG4gICAgICAgICAgICAgICAgICAgICAgY2hzOiB0aGlzLmNoYW5uZWxDb3VudCxcclxuICAgICAgICAgICAgICAgICAgICAgIGF1ZGlvRGF0YTogdHJCdWZmZXJzXHJcbiAgICAgICAgICAgICAgICAgICAgfSwgdHJCdWZmZXJzKTtcclxuICAgICAgICAgICAgICAgICAgICBmaWxsZWQgKz0gcmVhZDtcclxuICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJJbmRleGVkRGJBdWRpb0J1ZmZlclNvdXJjZU5vZGU6OmZpbGxCdWZmZXJPYnM6IFNlbnQgXCIrcmVhZCtcIiBmcmFtZXMgdG8gYXVkaW8gc291cmNlIHdvcmtsZXQuIEZpbGxlZDogXCIrZmlsbGVkK1wiLCB0byBmaWxsOiBcIit0aGlzLmJ1ZmZlckZpbGxGcmFtZXMpO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLl9hdWRpb0lucHV0U3RyZWFtICYmIGZpbGxlZCA8IHRoaXMuYnVmZmVyRmlsbEZyYW1lcykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmRlYnVnKFwiSW5kZXhlZERiQXVkaW9CdWZmZXJTb3VyY2VOb2RlOjpmaWxsQnVmZmVyT2JzOiBOZXh0IGluZGRiIGF1ZGlvIGlucHV0IHN0cmVhbSByZWFkT2JzXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2F1ZGlvSW5wdXRTdHJlYW0ucmVhZE9icyh0aGlzLl9haXNCdWZzKTtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgaWYodGhpcy5zdGFsbGVkKXtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wb3J0LnBvc3RNZXNzYWdlKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICBjbWQ6ICdjb250aW51ZSdcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEVNUFRZO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJJbmRleGVkRGJBdWRpb0J1ZmZlclNvdXJjZU5vZGU6OmZpbGxCdWZmZXJPYnM6IFJldHVybiBFTVBUWSAocmVhZDogXCIrcmVhZCtcIilcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fZW5kT2ZTdHJlYW09dHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe1xyXG4gICAgICAgICAgICAgICAgICAgICAgY21kOiAnZW5kT2ZTdHJlYW0nXHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEVNUFRZO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICApLnN1YnNjcmliZShzdWJzY3JpYmVyKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuXHJcblxyXG4gIGdldCBuZXRBdWRpb0J1ZmZlcigpOiBOZXRBdWRpb0J1ZmZlciB8IG51bGwge1xyXG4gICAgcmV0dXJuIHRoaXMuX25ldEF1ZGlvQnVmZmVyXHJcbiAgfVxyXG5cclxuICBzZXQgbmV0QXVkaW9CdWZmZXIodmFsdWU6IE5ldEF1ZGlvQnVmZmVyIHwgbnVsbCkge1xyXG4gICAgdGhpcy5fbmV0QXVkaW9CdWZmZXIgPSB2YWx1ZTtcclxuICAgIGlmICh0aGlzLl9uZXRBdWRpb0J1ZmZlcj8uY2hhbm5lbENvdW50KSB7XHJcbiAgICAgIHRoaXMuY2hhbm5lbENvdW50ID0gdGhpcy5fbmV0QXVkaW9CdWZmZXI/LmNoYW5uZWxDb3VudDtcclxuICAgICAgdGhpcy5idWZmZXJGaWxsRnJhbWVzID0gdGhpcy5fbmV0QXVkaW9CdWZmZXIuc2FtcGxlUmF0ZSAqIHRoaXMuX2J1ZmZlckZpbGxTZWNvbmRzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0IGJ1ZmZlckZpbGxTZWNvbmRzKCk6IG51bWJlciB7XHJcbiAgICByZXR1cm4gdGhpcy5fYnVmZmVyRmlsbFNlY29uZHM7XHJcbiAgfVxyXG5cclxuICBzZXQgYnVmZmVyRmlsbFNlY29uZHModmFsdWU6IG51bWJlcikge1xyXG4gICAgdGhpcy5fYnVmZmVyRmlsbFNlY29uZHMgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIHN0YXJ0KHdoZW4/OiBudW1iZXIgfCB1bmRlZmluZWQsb2Zmc2V0PzogbnVtYmVyIHwgdW5kZWZpbmVkLGR1cmF0aW9uPzogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XHJcbiAgICBpZiAod2hlbikge1xyXG4gICAgICB0aHJvdyBFcnJvcihcIndoZW4gcGFyYW1ldGVyIGN1cnJlbnRseSBub3Qgc3VwcG9ydGVkIGJ5IEluZGV4ZWREYkF1ZGlvQnVmZmVyU291cmNlTm9kZSBjbGFzc1wiKVxyXG4gICAgfVxyXG4gICAgdGhpcy5fcGxheVN0YXJ0VGltZT1udWxsO1xyXG4gICAgdGhpcy5zdG9wRW5kVGltZT1udWxsO1xyXG4gICAgdGhpcy5zdGFsbGVkVGltZT0wO1xyXG4gICAgdGhpcy5zdGFsbGVkU3RhcnRUaW1lPW51bGw7XHJcblxyXG4gICAgaWYgKHRoaXMuX25ldEF1ZGlvQnVmZmVyKSB7XHJcbiAgICAgIGxldCBhcnJBaXM9bmV3IE5ldEF1ZGlvSW5wdXRTdHJlYW0odGhpcy5fbmV0QXVkaW9CdWZmZXIpO1xyXG4gICAgICBpZihvZmZzZXQ9PT11bmRlZmluZWQgJiYgZHVyYXRpb249PT11bmRlZmluZWQpe1xyXG4gICAgICAgIHRoaXMuX2F1ZGlvSW5wdXRTdHJlYW0gPSBhcnJBaXM7XHJcbiAgICAgIH1lbHNle1xyXG4gICAgICAgIGxldCBvZmZzZXRGcmFtZXM9MDtcclxuICAgICAgICBsZXQgZHVyYXRpb25GcmFtZXM9dW5kZWZpbmVkO1xyXG4gICAgICAgIGlmKG9mZnNldCE9PXVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgb2Zmc2V0RnJhbWVzPU1hdGguZmxvb3Iob2Zmc2V0ICogdGhpcy5fbmV0QXVkaW9CdWZmZXIuc2FtcGxlUmF0ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmKGR1cmF0aW9uIT09dW5kZWZpbmVkKXtcclxuICAgICAgICAgIGR1cmF0aW9uRnJhbWVzPU1hdGguZmxvb3IoZHVyYXRpb24gKiB0aGlzLl9uZXRBdWRpb0J1ZmZlci5zYW1wbGVSYXRlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy9jb25zb2xlLmVycm9yKFwiUGxheWJhY2sgc2VsZWN0aW9uIG5vdCBzdXBwb3J0ZWQgeWV0IVwiKTtcclxuICAgICAgICB0aGlzLl9hdWRpb0lucHV0U3RyZWFtPW5ldyBBc3luY0VkaXRGbG9hdDMyQXJyYXlJbnB1dFN0cmVhbShhcnJBaXMsb2Zmc2V0RnJhbWVzLGR1cmF0aW9uRnJhbWVzKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgbGV0IGNocz10aGlzLl9uZXRBdWRpb0J1ZmZlci5jaGFubmVsQ291bnQ7XHJcbiAgICAgIHRoaXMuX2Fpc0J1ZnM9bmV3IEFycmF5PEZsb2F0MzJBcnJheT4oY2hzKTtcclxuICAgICAgZm9yKGxldCBjaD0wO2NoPGNocztjaCsrKXtcclxuICAgICAgICB0aGlzLl9haXNCdWZzW2NoXT1uZXcgRmxvYXQzMkFycmF5KHRoaXMuX3N0cmVhbVJlYWRGcmFtZUxlbik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuZmlsbEJ1ZmZlck9icygpLnN1YnNjcmliZSh7XHJcbiAgICAgICAgY29tcGxldGU6ICgpPT57XHJcbiAgICAgICAgICAvL2NvbnNvbGUuZGVidWcoXCJJbmRleGVkRGJBdWRpb0J1ZmZlclNvdXJjZU5vZGU6OnN0YXJ0OiBBc3luYyBwbGF5IGJ1ZmZlciBmaWxsIGNvbXBsZXRlZC4gU2VuZGluZyBzdGFydCBjb21tYW5kIHRvIGF1ZGlvIHdvcmtsZXQuXCIpO1xyXG4gICAgICAgICAgaWYodGhpcy5fYWN0aXZlKSB7XHJcbiAgICAgICAgICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZSh7Y21kOiAnc3RhcnQnfSk7XHJcbiAgICAgICAgICAgIGlmKG9mZnNldCkge1xyXG4gICAgICAgICAgICAgIHRoaXMuX3BsYXlTdGFydFRpbWUgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgLSBvZmZzZXQ7XHJcbiAgICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICAgIHRoaXMuX3BsYXlTdGFydFRpbWUgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pXHJcbiAgICAgIHRoaXMuX2FjdGl2ZT10cnVlO1xyXG5cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHN0b3AoKSB7XHJcbiAgICB0aGlzLl9hY3RpdmU9ZmFsc2U7XHJcbiAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2Uoe2NtZDogJ3N0b3AnfSk7XHJcbiAgICB0aGlzLm9uZW5kZWQ/LmNhbGwodGhpcyk7XHJcbiAgfVxyXG5cclxuICBnZXQgcGxheVBvc2l0aW9uVGltZSgpOm51bWJlcnxudWxsIHtcclxuICAgIGxldCBwcHQ6bnVtYmVyfG51bGw9bnVsbDtcclxuICAgIGlmKHRoaXMuX3BsYXlTdGFydFRpbWUhPT1udWxsKSB7XHJcbiAgICAgIGlmKHRoaXMuX2FjdGl2ZSkge1xyXG4gICAgICAgIGlmICh0aGlzLnN0YWxsZWRTdGFydFRpbWUgPT0gbnVsbCkge1xyXG4gICAgICAgICAgcHB0ID0gdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lIC0gdGhpcy5fcGxheVN0YXJ0VGltZSAtIHRoaXMuc3RhbGxlZFRpbWU7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHBwdCA9IHRoaXMuc3RhbGxlZFN0YXJ0VGltZSAtIHRoaXMuX3BsYXlTdGFydFRpbWUgLSB0aGlzLnN0YWxsZWRUaW1lO1xyXG4gICAgICAgIH1cclxuICAgICAgfWVsc2V7XHJcbiAgICAgICAgaWYodGhpcy5zdG9wRW5kVGltZSE9bnVsbCl7XHJcbiAgICAgICAgICAvLyBpZih0aGlzLl9uZXRBdWRpb0J1ZmZlcj8uZnJhbWVMZW4gIT1udWxsICYmIHRoaXMuX25ldEF1ZGlvQnVmZmVyLnNhbXBsZVJhdGUpIHtcclxuICAgICAgICAgIC8vICAgcHB0ID0gdGhpcy5fbmV0QXVkaW9CdWZmZXI/LmZyYW1lTGVuIC8gdGhpcy5fbmV0QXVkaW9CdWZmZXI/LnNhbXBsZVJhdGU7XHJcbiAgICAgICAgICAvLyB9ZWxzZXtcclxuICAgICAgICAgICAgcHB0ID0gdGhpcy5zdG9wRW5kVGltZSAtIHRoaXMuX3BsYXlTdGFydFRpbWUgLSB0aGlzLnN0YWxsZWRUaW1lO1xyXG4gICAgICAgICAgLy99XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gcHB0O1xyXG4gIH1cclxuXHJcbn1cclxuXHJcbiJdfQ==