speechrecorderng 2.24.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/lib/audio/capture/capture.mjs +38 -10
- package/esm2020/lib/audio/io/stream.mjs +41 -1
- package/esm2020/lib/io/stream.mjs +10 -1
- package/esm2020/lib/recorder_component.mjs +5 -1
- package/esm2020/lib/speechrecorder/project/project.mjs +1 -1
- package/esm2020/lib/speechrecorder/session/audiorecorder.mjs +162 -171
- package/esm2020/lib/speechrecorder/session/basicrecorder.mjs +165 -4
- package/esm2020/lib/speechrecorder/session/sessionmanager.mjs +24 -12
- package/esm2020/lib/speechrecorderng.component.mjs +76 -134
- package/esm2020/lib/spr.module.version.mjs +2 -2
- package/fesm2015/speechrecorderng.mjs +585 -401
- package/fesm2015/speechrecorderng.mjs.map +1 -1
- package/fesm2020/speechrecorderng.mjs +581 -401
- package/fesm2020/speechrecorderng.mjs.map +1 -1
- package/lib/audio/io/stream.d.ts +13 -0
- package/lib/io/stream.d.ts +3 -0
- package/lib/recorder_component.d.ts +4 -0
- package/lib/speechrecorder/project/project.d.ts +1 -0
- package/lib/speechrecorder/session/audiorecorder.d.ts +7 -9
- package/lib/speechrecorder/session/basicrecorder.d.ts +40 -2
- package/lib/speechrecorder/session/sessionmanager.d.ts +4 -3
- package/lib/speechrecorderng.component.d.ts +1 -2
- package/lib/spr.module.version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ import * as i1$2 from '@angular/material/dialog';
|
|
|
19
19
|
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
|
20
20
|
import * as i3$2 from '@angular/material/button';
|
|
21
21
|
import { MatButtonModule } from '@angular/material/button';
|
|
22
|
+
import { __decorate, __param } from 'tslib';
|
|
22
23
|
import * as i1$3 from '@angular/material/progress-spinner';
|
|
23
24
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
24
25
|
import * as i8 from '@angular/flex-layout/flex';
|
|
@@ -1047,17 +1048,45 @@ class AudioCapture {
|
|
|
1047
1048
|
this._opened = false;
|
|
1048
1049
|
}
|
|
1049
1050
|
audioBuffer() {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
for (
|
|
1051
|
+
let frameLen = 0;
|
|
1052
|
+
let ch0Data = this.data[0];
|
|
1053
|
+
for (let ch0Chk of ch0Data) {
|
|
1053
1054
|
frameLen += ch0Chk.length;
|
|
1054
1055
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1056
|
+
let ab;
|
|
1057
|
+
try {
|
|
1058
|
+
ab = this.context.createBuffer(this.channelCount, frameLen, this.context.sampleRate);
|
|
1059
|
+
}
|
|
1060
|
+
catch (err) {
|
|
1061
|
+
if (err instanceof DOMException) {
|
|
1062
|
+
if (err.name === 'NotSupportedError') {
|
|
1063
|
+
if (frameLen == 0) {
|
|
1064
|
+
// Empty buffers are not supported by Chromium
|
|
1065
|
+
// Create dummy buffer with one sample
|
|
1066
|
+
ab = this.context.createBuffer(this.channelCount, 1, this.context.sampleRate);
|
|
1067
|
+
}
|
|
1068
|
+
else {
|
|
1069
|
+
throw err;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
else {
|
|
1073
|
+
throw err;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
else if (err instanceof RangeError) {
|
|
1077
|
+
// Out of memory
|
|
1078
|
+
// TODO What to do ??
|
|
1079
|
+
throw err;
|
|
1080
|
+
}
|
|
1081
|
+
else {
|
|
1082
|
+
throw err;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
for (let ch = 0; ch < this.channelCount; ch++) {
|
|
1086
|
+
let chD = ab.getChannelData(ch);
|
|
1087
|
+
let pos = 0;
|
|
1088
|
+
for (let chChk of this.data[ch]) {
|
|
1089
|
+
let bufLen = chChk.length;
|
|
1061
1090
|
chD.set(chChk, pos);
|
|
1062
1091
|
pos += bufLen;
|
|
1063
1092
|
}
|
|
@@ -5629,98 +5658,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
|
|
|
5629
5658
|
type: Output
|
|
5630
5659
|
}] } });
|
|
5631
5660
|
|
|
5632
|
-
class Float32ArrayChunkerOutStream {
|
|
5633
|
-
constructor(outStream) {
|
|
5634
|
-
this.outStream = outStream;
|
|
5635
|
-
this.bufs = new Array();
|
|
5636
|
-
this._channels = 0;
|
|
5637
|
-
this._chunkSize = 0;
|
|
5638
|
-
this.filled = 0;
|
|
5639
|
-
this.receivedFrames = 0;
|
|
5640
|
-
this.sentFrames = 0;
|
|
5641
|
-
}
|
|
5642
|
-
createBuffers() {
|
|
5643
|
-
this.bufs = new Array(this._channels);
|
|
5644
|
-
for (let ch = 0; ch < this._channels; ch++) {
|
|
5645
|
-
this.bufs[ch] = new Float32Array(this._chunkSize);
|
|
5646
|
-
}
|
|
5647
|
-
}
|
|
5648
|
-
set chunkSize(chunkSize) {
|
|
5649
|
-
this._chunkSize = chunkSize;
|
|
5650
|
-
this.createBuffers();
|
|
5651
|
-
}
|
|
5652
|
-
set channels(channels) {
|
|
5653
|
-
this._channels = channels;
|
|
5654
|
-
this.createBuffers();
|
|
5655
|
-
}
|
|
5656
|
-
write(buffers) {
|
|
5657
|
-
let copied = 0;
|
|
5658
|
-
if (buffers.length > 0) {
|
|
5659
|
-
let buffersLen = buffers[0].length;
|
|
5660
|
-
this.receivedFrames += buffersLen;
|
|
5661
|
-
let avail = buffersLen;
|
|
5662
|
-
// Fill out buffers until all values copied
|
|
5663
|
-
while (avail > 0) {
|
|
5664
|
-
let toFill = this._chunkSize - this.filled;
|
|
5665
|
-
if (toFill > avail) {
|
|
5666
|
-
toFill = avail;
|
|
5667
|
-
}
|
|
5668
|
-
let sliceEnd = copied + toFill;
|
|
5669
|
-
// Firefox on Android sends only the first channel
|
|
5670
|
-
for (let ch = 0; ch < buffersLen; ch++) {
|
|
5671
|
-
if (buffers[ch]) {
|
|
5672
|
-
let cpPrt = buffers[ch].slice(copied, sliceEnd);
|
|
5673
|
-
let buf = this.bufs[ch];
|
|
5674
|
-
buf.set(cpPrt, this.filled);
|
|
5675
|
-
}
|
|
5676
|
-
}
|
|
5677
|
-
copied += toFill;
|
|
5678
|
-
avail -= toFill;
|
|
5679
|
-
this.filled += toFill;
|
|
5680
|
-
if (this.filled == this._chunkSize) {
|
|
5681
|
-
this.outStream.write(this.bufs);
|
|
5682
|
-
this.sentFrames += this.filled;
|
|
5683
|
-
this.filled = 0;
|
|
5684
|
-
}
|
|
5685
|
-
}
|
|
5686
|
-
}
|
|
5687
|
-
return copied;
|
|
5688
|
-
}
|
|
5689
|
-
flush() {
|
|
5690
|
-
if (this.filled > 0) {
|
|
5691
|
-
let restBufs = new Array(this._channels);
|
|
5692
|
-
for (let ch = 0; ch < this._channels; ch++) {
|
|
5693
|
-
restBufs[ch] = this.bufs[ch].slice(0, this.filled);
|
|
5694
|
-
}
|
|
5695
|
-
this.outStream.write(restBufs);
|
|
5696
|
-
this.outStream.flush();
|
|
5697
|
-
this.sentFrames += this.filled;
|
|
5698
|
-
this.filled = 0;
|
|
5699
|
-
}
|
|
5700
|
-
}
|
|
5701
|
-
close() {
|
|
5702
|
-
this.outStream.close();
|
|
5703
|
-
}
|
|
5704
|
-
}
|
|
5705
|
-
|
|
5706
|
-
class SequenceAudioFloat32ChunkerOutStream extends Float32ArrayChunkerOutStream {
|
|
5707
|
-
constructor(outStream, chunkDurationSeconds) {
|
|
5708
|
-
super(outStream);
|
|
5709
|
-
this.chunkDurationSeconds = chunkDurationSeconds;
|
|
5710
|
-
this.sampleRate = null;
|
|
5711
|
-
this.sequenceAudioFloat32OutStream = outStream;
|
|
5712
|
-
}
|
|
5713
|
-
setFormat(channels, sampleRate) {
|
|
5714
|
-
this.channels = channels;
|
|
5715
|
-
this.sampleRate = sampleRate;
|
|
5716
|
-
this.chunkSize = Math.round(sampleRate * this.chunkDurationSeconds);
|
|
5717
|
-
this.sequenceAudioFloat32OutStream.setFormat(channels, sampleRate);
|
|
5718
|
-
}
|
|
5719
|
-
nextStream() {
|
|
5720
|
-
this.sequenceAudioFloat32OutStream.nextStream();
|
|
5721
|
-
}
|
|
5722
|
-
}
|
|
5723
|
-
|
|
5724
5661
|
class SessionFinishedDialog {
|
|
5725
5662
|
constructor(dialogRef, data) {
|
|
5726
5663
|
this.dialogRef = dialogRef;
|
|
@@ -7247,23 +7184,209 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
|
|
|
7247
7184
|
type: Input
|
|
7248
7185
|
}] } });
|
|
7249
7186
|
|
|
7187
|
+
class Float32ArrayChunkerOutStream {
|
|
7188
|
+
constructor(outStream) {
|
|
7189
|
+
this.outStream = outStream;
|
|
7190
|
+
this.bufs = new Array();
|
|
7191
|
+
this._channels = 0;
|
|
7192
|
+
this._chunkSize = 0;
|
|
7193
|
+
this.filled = 0;
|
|
7194
|
+
this.receivedFrames = 0;
|
|
7195
|
+
this.sentFrames = 0;
|
|
7196
|
+
}
|
|
7197
|
+
createBuffers() {
|
|
7198
|
+
this.bufs = new Array(this._channels);
|
|
7199
|
+
for (let ch = 0; ch < this._channels; ch++) {
|
|
7200
|
+
this.bufs[ch] = new Float32Array(this._chunkSize);
|
|
7201
|
+
}
|
|
7202
|
+
}
|
|
7203
|
+
set chunkSize(chunkSize) {
|
|
7204
|
+
this._chunkSize = chunkSize;
|
|
7205
|
+
this.createBuffers();
|
|
7206
|
+
}
|
|
7207
|
+
get chunkSize() {
|
|
7208
|
+
return this._chunkSize;
|
|
7209
|
+
}
|
|
7210
|
+
set channels(channels) {
|
|
7211
|
+
this._channels = channels;
|
|
7212
|
+
this.createBuffers();
|
|
7213
|
+
}
|
|
7214
|
+
get channels() {
|
|
7215
|
+
return this._channels;
|
|
7216
|
+
}
|
|
7217
|
+
available() {
|
|
7218
|
+
return this._chunkSize - this.filled;
|
|
7219
|
+
}
|
|
7220
|
+
write(buffers) {
|
|
7221
|
+
let copied = 0;
|
|
7222
|
+
if (buffers.length > 0) {
|
|
7223
|
+
let buffersLen = buffers[0].length;
|
|
7224
|
+
this.receivedFrames += buffersLen;
|
|
7225
|
+
let avail = buffersLen;
|
|
7226
|
+
// Fill out buffers until all values copied
|
|
7227
|
+
while (avail > 0) {
|
|
7228
|
+
let toFill = this._chunkSize - this.filled;
|
|
7229
|
+
if (toFill > avail) {
|
|
7230
|
+
toFill = avail;
|
|
7231
|
+
}
|
|
7232
|
+
let sliceEnd = copied + toFill;
|
|
7233
|
+
// Firefox on Android sends only the first channel
|
|
7234
|
+
for (let ch = 0; ch < buffersLen; ch++) {
|
|
7235
|
+
if (buffers[ch]) {
|
|
7236
|
+
let cpPrt = buffers[ch].slice(copied, sliceEnd);
|
|
7237
|
+
let buf = this.bufs[ch];
|
|
7238
|
+
buf.set(cpPrt, this.filled);
|
|
7239
|
+
}
|
|
7240
|
+
}
|
|
7241
|
+
copied += toFill;
|
|
7242
|
+
avail -= toFill;
|
|
7243
|
+
this.filled += toFill;
|
|
7244
|
+
if (this.filled == this._chunkSize) {
|
|
7245
|
+
this.outStream.write(this.bufs);
|
|
7246
|
+
this.sentFrames += this.filled;
|
|
7247
|
+
this.filled = 0;
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
}
|
|
7251
|
+
return copied;
|
|
7252
|
+
}
|
|
7253
|
+
flush() {
|
|
7254
|
+
if (this.filled > 0) {
|
|
7255
|
+
let restBufs = new Array(this._channels);
|
|
7256
|
+
for (let ch = 0; ch < this._channels; ch++) {
|
|
7257
|
+
restBufs[ch] = this.bufs[ch].slice(0, this.filled);
|
|
7258
|
+
}
|
|
7259
|
+
this.outStream.write(restBufs);
|
|
7260
|
+
this.outStream.flush();
|
|
7261
|
+
this.sentFrames += this.filled;
|
|
7262
|
+
this.filled = 0;
|
|
7263
|
+
}
|
|
7264
|
+
}
|
|
7265
|
+
close() {
|
|
7266
|
+
this.outStream.close();
|
|
7267
|
+
}
|
|
7268
|
+
}
|
|
7269
|
+
|
|
7270
|
+
class SequenceAudioFloat32ChunkerOutStream extends Float32ArrayChunkerOutStream {
|
|
7271
|
+
constructor(outStream, chunkDurationSeconds) {
|
|
7272
|
+
super(outStream);
|
|
7273
|
+
this.chunkDurationSeconds = chunkDurationSeconds;
|
|
7274
|
+
this.sampleRate = null;
|
|
7275
|
+
this.sequenceAudioFloat32OutStream = outStream;
|
|
7276
|
+
}
|
|
7277
|
+
setFormat(channels, sampleRate) {
|
|
7278
|
+
console.debug("SequenceAudioFloat32ChunkerOutStream:setFormat(channels: " + channels + ",sampleRate: " + sampleRate + ")");
|
|
7279
|
+
this.channels = channels;
|
|
7280
|
+
this.sampleRate = sampleRate;
|
|
7281
|
+
this.chunkSize = Math.round(sampleRate * this.chunkDurationSeconds);
|
|
7282
|
+
console.debug("SequenceAudioFloat32ChunkerOutStream: chunkSize: " + this.chunkSize);
|
|
7283
|
+
this.sequenceAudioFloat32OutStream.setFormat(channels, sampleRate);
|
|
7284
|
+
}
|
|
7285
|
+
nextStream() {
|
|
7286
|
+
this.sequenceAudioFloat32OutStream.nextStream();
|
|
7287
|
+
}
|
|
7288
|
+
}
|
|
7289
|
+
/**
|
|
7290
|
+
* Streams a SequenceAudioFloat32OutStream to multiple streams
|
|
7291
|
+
*/
|
|
7292
|
+
class SequenceAudioFloat32OutStreamMultiplier {
|
|
7293
|
+
constructor() {
|
|
7294
|
+
this._sequenceAudioFloat32OutStreams = new Array();
|
|
7295
|
+
}
|
|
7296
|
+
get sequenceAudioFloat32OutStreams() {
|
|
7297
|
+
return this._sequenceAudioFloat32OutStreams;
|
|
7298
|
+
}
|
|
7299
|
+
setFormat(channels, sampleRate) {
|
|
7300
|
+
for (let os of this._sequenceAudioFloat32OutStreams) {
|
|
7301
|
+
os.setFormat(channels, sampleRate);
|
|
7302
|
+
}
|
|
7303
|
+
}
|
|
7304
|
+
nextStream() {
|
|
7305
|
+
for (let os of this._sequenceAudioFloat32OutStreams) {
|
|
7306
|
+
os.nextStream();
|
|
7307
|
+
}
|
|
7308
|
+
}
|
|
7309
|
+
close() {
|
|
7310
|
+
for (let os of this._sequenceAudioFloat32OutStreams) {
|
|
7311
|
+
os.close();
|
|
7312
|
+
}
|
|
7313
|
+
}
|
|
7314
|
+
flush() {
|
|
7315
|
+
for (let os of this._sequenceAudioFloat32OutStreams) {
|
|
7316
|
+
os.flush();
|
|
7317
|
+
}
|
|
7318
|
+
}
|
|
7319
|
+
write(buffers) {
|
|
7320
|
+
let toWrite = buffers.length;
|
|
7321
|
+
for (let os of this._sequenceAudioFloat32OutStreams) {
|
|
7322
|
+
os.write(buffers);
|
|
7323
|
+
}
|
|
7324
|
+
return toWrite;
|
|
7325
|
+
}
|
|
7326
|
+
}
|
|
7327
|
+
|
|
7250
7328
|
const FORCE_REQUEST_AUDIO_PERMISSIONS = false;
|
|
7251
7329
|
const RECFILE_API_CTX = 'recfile';
|
|
7252
7330
|
const MAX_RECORDING_TIME_MS = 1000 * 60 * 60 * 60; // 1 hour
|
|
7253
7331
|
const LEVEL_BAR_INTERVALL_SECONDS = 0.1; // 100ms
|
|
7254
|
-
class
|
|
7255
|
-
constructor(
|
|
7332
|
+
class ChunkManager {
|
|
7333
|
+
constructor(chunkAudioBufferReceiver) {
|
|
7334
|
+
this.chunkAudioBufferReceiver = chunkAudioBufferReceiver;
|
|
7335
|
+
this.channels = 0;
|
|
7336
|
+
this.sampleRate = -1;
|
|
7337
|
+
this.chunkIdx = 0;
|
|
7338
|
+
}
|
|
7339
|
+
set recordingFile(value) {
|
|
7340
|
+
this._rf = value;
|
|
7341
|
+
}
|
|
7342
|
+
close() {
|
|
7343
|
+
// Nothing to do
|
|
7344
|
+
}
|
|
7345
|
+
flush() {
|
|
7346
|
+
this.chunkAudioBufferReceiver.postAudioStreamEnd(this.chunkIdx);
|
|
7347
|
+
}
|
|
7348
|
+
nextStream() {
|
|
7349
|
+
// reset chunk counter
|
|
7350
|
+
this.chunkIdx = 0;
|
|
7351
|
+
this.chunkAudioBufferReceiver.postAudioStreamStart();
|
|
7352
|
+
}
|
|
7353
|
+
setFormat(channels, sampleRate) {
|
|
7354
|
+
this.channels = channels;
|
|
7355
|
+
this.sampleRate = sampleRate;
|
|
7356
|
+
}
|
|
7357
|
+
write(buffers) {
|
|
7358
|
+
let aCtx = AudioContextProvider.audioContextInstance();
|
|
7359
|
+
let bChs = buffers.length;
|
|
7360
|
+
let frameLen = 0;
|
|
7361
|
+
if (aCtx && bChs > 0) {
|
|
7362
|
+
frameLen = buffers[0].length;
|
|
7363
|
+
let ad = aCtx.createBuffer(this.channels, frameLen, this.sampleRate);
|
|
7364
|
+
for (let ch = 0; ch < this.channels; ch++) {
|
|
7365
|
+
ad.copyToChannel(buffers[ch], ch);
|
|
7366
|
+
}
|
|
7367
|
+
this.chunkAudioBufferReceiver.postChunkAudioBuffer(ad, this.chunkIdx);
|
|
7368
|
+
this.chunkIdx++;
|
|
7369
|
+
}
|
|
7370
|
+
return frameLen;
|
|
7371
|
+
}
|
|
7372
|
+
}
|
|
7373
|
+
let BasicRecorder = class BasicRecorder {
|
|
7374
|
+
constructor(dialog, sessionService, uploader, config) {
|
|
7256
7375
|
this.dialog = dialog;
|
|
7257
7376
|
this.sessionService = sessionService;
|
|
7377
|
+
this.uploader = uploader;
|
|
7378
|
+
this.config = config;
|
|
7258
7379
|
this.statusMsg = '';
|
|
7259
7380
|
this.statusWaiting = false;
|
|
7260
7381
|
this.readonly = false;
|
|
7382
|
+
this.rfUuid = null;
|
|
7261
7383
|
this.processingRecording = false;
|
|
7262
7384
|
this.ac = null;
|
|
7263
7385
|
this._wakeLock = false;
|
|
7264
7386
|
this._selectedDeviceId = undefined;
|
|
7265
7387
|
this._channelCount = 2;
|
|
7266
7388
|
this._session = null;
|
|
7389
|
+
this.startedDate = null;
|
|
7267
7390
|
this.uploadProgress = 100;
|
|
7268
7391
|
this.uploadStatus = 'ok';
|
|
7269
7392
|
this.audioSignalCollapsed = true;
|
|
@@ -7273,7 +7396,10 @@ class BasicRecorder {
|
|
|
7273
7396
|
this.audioFetchSubscription = null;
|
|
7274
7397
|
this.destroyed = false;
|
|
7275
7398
|
this.navigationDisabled = true;
|
|
7399
|
+
// Default: Do not try to keep the device awake
|
|
7276
7400
|
this.noSleep = null;
|
|
7401
|
+
// Default: Disabled chunked upload
|
|
7402
|
+
this._uploadChunkSizeSeconds = null;
|
|
7277
7403
|
this.userAgent = UserAgentBuilder.userAgent();
|
|
7278
7404
|
console.debug("Detected platform: " + this.userAgent.detectedPlatform);
|
|
7279
7405
|
console.debug("Detected browser: " + this.userAgent.detectedBrowser);
|
|
@@ -7283,6 +7409,16 @@ class BasicRecorder {
|
|
|
7283
7409
|
this.streamLevelMeasure = new StreamLevelMeasure();
|
|
7284
7410
|
this.selCaptureDeviceId = null;
|
|
7285
7411
|
}
|
|
7412
|
+
get uploadChunkSizeSeconds() {
|
|
7413
|
+
return this._uploadChunkSizeSeconds;
|
|
7414
|
+
}
|
|
7415
|
+
set uploadChunkSizeSeconds(value) {
|
|
7416
|
+
let oldValue = this.uploadChunkSizeSeconds;
|
|
7417
|
+
this._uploadChunkSizeSeconds = value;
|
|
7418
|
+
if (value !== oldValue) {
|
|
7419
|
+
this.configureStreamCaptureStream();
|
|
7420
|
+
}
|
|
7421
|
+
}
|
|
7286
7422
|
get wakeLock() {
|
|
7287
7423
|
return this._wakeLock;
|
|
7288
7424
|
}
|
|
@@ -7296,12 +7432,14 @@ class BasicRecorder {
|
|
|
7296
7432
|
}
|
|
7297
7433
|
if (!this.noSleep.isEnabled) {
|
|
7298
7434
|
this.noSleep.enable();
|
|
7435
|
+
console.debug("Enabled wake lock.");
|
|
7299
7436
|
}
|
|
7300
7437
|
}
|
|
7301
7438
|
}
|
|
7302
7439
|
disableWakeLockCond() {
|
|
7303
7440
|
if (this.noSleep && this.noSleep.isEnabled) {
|
|
7304
7441
|
this.noSleep.disable();
|
|
7442
|
+
console.debug("Disabled wake lock.");
|
|
7305
7443
|
}
|
|
7306
7444
|
}
|
|
7307
7445
|
set audioDevices(audioDevices) {
|
|
@@ -7323,6 +7461,27 @@ class BasicRecorder {
|
|
|
7323
7461
|
this.statusAlertType = 'info';
|
|
7324
7462
|
this.statusMsg = 'Ready.';
|
|
7325
7463
|
}
|
|
7464
|
+
configureStreamCaptureStream() {
|
|
7465
|
+
let outStream;
|
|
7466
|
+
if (this.uploadChunkSizeSeconds) {
|
|
7467
|
+
// Multiply the capture stream to...
|
|
7468
|
+
let sasm = new SequenceAudioFloat32OutStreamMultiplier();
|
|
7469
|
+
// ...upload audio data in chunks...
|
|
7470
|
+
let chMng = new ChunkManager(this); // The chunk manager connects the chunked audio stream to this class to upload the chunks
|
|
7471
|
+
let chOsUpload = new SequenceAudioFloat32ChunkerOutStream(chMng, this.uploadChunkSizeSeconds); // The audio stream chunker itself
|
|
7472
|
+
sasm.sequenceAudioFloat32OutStreams.push(chOsUpload);
|
|
7473
|
+
// ...and to measure the level
|
|
7474
|
+
let chOsLvlMeas = new SequenceAudioFloat32ChunkerOutStream(this.streamLevelMeasure, LEVEL_BAR_INTERVALL_SECONDS);
|
|
7475
|
+
sasm.sequenceAudioFloat32OutStreams.push(chOsLvlMeas);
|
|
7476
|
+
outStream = sasm;
|
|
7477
|
+
}
|
|
7478
|
+
else {
|
|
7479
|
+
outStream = new SequenceAudioFloat32ChunkerOutStream(this.streamLevelMeasure, LEVEL_BAR_INTERVALL_SECONDS);
|
|
7480
|
+
}
|
|
7481
|
+
if (this.ac) {
|
|
7482
|
+
this.ac.audioOutStream = outStream;
|
|
7483
|
+
}
|
|
7484
|
+
}
|
|
7326
7485
|
start() {
|
|
7327
7486
|
this.statusAlertType = 'info';
|
|
7328
7487
|
this.statusMsg = 'Starting session...';
|
|
@@ -7529,6 +7688,73 @@ class BasicRecorder {
|
|
|
7529
7688
|
});
|
|
7530
7689
|
}
|
|
7531
7690
|
}
|
|
7691
|
+
startItem() {
|
|
7692
|
+
this.startedDate = null;
|
|
7693
|
+
this.enableWakeLockCond();
|
|
7694
|
+
this.rfUuid = UUID.generate();
|
|
7695
|
+
this.transportActions.startAction.disabled = true;
|
|
7696
|
+
this.transportActions.pauseAction.disabled = true;
|
|
7697
|
+
if (this.readonly) {
|
|
7698
|
+
return;
|
|
7699
|
+
}
|
|
7700
|
+
}
|
|
7701
|
+
started() {
|
|
7702
|
+
if (!this.startedDate) {
|
|
7703
|
+
this.startedDate = new Date();
|
|
7704
|
+
}
|
|
7705
|
+
this.transportActions.startAction.disabled = true;
|
|
7706
|
+
}
|
|
7707
|
+
postRecording(wavFile, recUrl) {
|
|
7708
|
+
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
7709
|
+
let ul = new Upload(wavBlob, recUrl);
|
|
7710
|
+
this.uploader.queueUpload(ul);
|
|
7711
|
+
}
|
|
7712
|
+
postAudioStreamStart() {
|
|
7713
|
+
if (this.rfUuid) {
|
|
7714
|
+
let apiEndPoint = '';
|
|
7715
|
+
if (this.config && this.config.apiEndPoint) {
|
|
7716
|
+
apiEndPoint = this.config.apiEndPoint;
|
|
7717
|
+
}
|
|
7718
|
+
if (apiEndPoint !== '') {
|
|
7719
|
+
apiEndPoint = apiEndPoint + '/';
|
|
7720
|
+
}
|
|
7721
|
+
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
7722
|
+
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.rfUuid + '/prepareChunksRequest';
|
|
7723
|
+
let fd = new FormData();
|
|
7724
|
+
// Note: At least one parameter must be set
|
|
7725
|
+
fd.set('uuid', this.rfUuid);
|
|
7726
|
+
if (!this.startedDate) {
|
|
7727
|
+
this.startedDate = new Date();
|
|
7728
|
+
}
|
|
7729
|
+
fd.set('startedDate', this.startedDate.toJSON());
|
|
7730
|
+
let ul = new Upload(fd, recUrl);
|
|
7731
|
+
this.uploader.queueUpload(ul);
|
|
7732
|
+
}
|
|
7733
|
+
else {
|
|
7734
|
+
console.error("Recording file UUID not set!");
|
|
7735
|
+
}
|
|
7736
|
+
}
|
|
7737
|
+
postAudioStreamEnd(chunkCount) {
|
|
7738
|
+
if (this.rfUuid) {
|
|
7739
|
+
let apiEndPoint = '';
|
|
7740
|
+
if (this.config && this.config.apiEndPoint) {
|
|
7741
|
+
apiEndPoint = this.config.apiEndPoint;
|
|
7742
|
+
}
|
|
7743
|
+
if (apiEndPoint !== '') {
|
|
7744
|
+
apiEndPoint = apiEndPoint + '/';
|
|
7745
|
+
}
|
|
7746
|
+
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
7747
|
+
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.rfUuid + '/concatChunksRequest';
|
|
7748
|
+
let fd = new FormData();
|
|
7749
|
+
fd.set('uuid', this.rfUuid);
|
|
7750
|
+
fd.set('chunkCount', chunkCount.toString());
|
|
7751
|
+
let ul = new Upload(fd, recUrl);
|
|
7752
|
+
this.uploader.queueUpload(ul);
|
|
7753
|
+
}
|
|
7754
|
+
else {
|
|
7755
|
+
console.error("Recording file UUID not set!");
|
|
7756
|
+
}
|
|
7757
|
+
}
|
|
7532
7758
|
closed() {
|
|
7533
7759
|
this.statusAlertType = 'info';
|
|
7534
7760
|
this.statusMsg = 'Session closed.';
|
|
@@ -7545,7 +7771,11 @@ class BasicRecorder {
|
|
|
7545
7771
|
}
|
|
7546
7772
|
});
|
|
7547
7773
|
}
|
|
7548
|
-
}
|
|
7774
|
+
};
|
|
7775
|
+
BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS = 30;
|
|
7776
|
+
BasicRecorder = __decorate([
|
|
7777
|
+
__param(3, Inject(SPEECHRECORDER_CONFIG))
|
|
7778
|
+
], BasicRecorder);
|
|
7549
7779
|
|
|
7550
7780
|
/**
|
|
7551
7781
|
* Created by klausj on 17.06.2017.
|
|
@@ -7855,7 +8085,7 @@ const DEFAULT_PRE_REC_DELAY = 1000;
|
|
|
7855
8085
|
const DEFAULT_POST_REC_DELAY = 500;
|
|
7856
8086
|
class SessionManager extends BasicRecorder {
|
|
7857
8087
|
constructor(changeDetectorRef, renderer, dialog, sessionService, recFileService, uploader, config) {
|
|
7858
|
-
super(dialog, sessionService);
|
|
8088
|
+
super(dialog, sessionService, uploader, config);
|
|
7859
8089
|
this.changeDetectorRef = changeDetectorRef;
|
|
7860
8090
|
this.renderer = renderer;
|
|
7861
8091
|
this.dialog = dialog;
|
|
@@ -7958,7 +8188,7 @@ class SessionManager extends BasicRecorder {
|
|
|
7958
8188
|
if (this.ac) {
|
|
7959
8189
|
this.transportActions.startAction.onAction = () => this.startItem();
|
|
7960
8190
|
this.ac.listener = this;
|
|
7961
|
-
this.
|
|
8191
|
+
this.configureStreamCaptureStream();
|
|
7962
8192
|
// Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
|
|
7963
8193
|
//this.ac.listDevices();
|
|
7964
8194
|
}
|
|
@@ -8104,12 +8334,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8104
8334
|
}
|
|
8105
8335
|
}
|
|
8106
8336
|
startItem() {
|
|
8107
|
-
|
|
8108
|
-
this.transportActions.startAction.disabled = true;
|
|
8109
|
-
this.transportActions.pauseAction.disabled = true;
|
|
8110
|
-
if (this.readonly) {
|
|
8111
|
-
return;
|
|
8112
|
-
}
|
|
8337
|
+
super.startItem();
|
|
8113
8338
|
this.transportActions.fwdAction.disabled = true;
|
|
8114
8339
|
this.transportActions.fwdNextAction.disabled = true;
|
|
8115
8340
|
this.transportActions.bwdAction.disabled = true;
|
|
@@ -8408,8 +8633,8 @@ class SessionManager extends BasicRecorder {
|
|
|
8408
8633
|
}
|
|
8409
8634
|
}
|
|
8410
8635
|
started() {
|
|
8636
|
+
super.started();
|
|
8411
8637
|
this.status = 2 /* PRE_RECORDING */;
|
|
8412
|
-
this.transportActions.startAction.disabled = true;
|
|
8413
8638
|
this.startStopSignalState = 1 /* PRERECORDING */;
|
|
8414
8639
|
if (this._session) {
|
|
8415
8640
|
if (this._session.status === "LOADED") {
|
|
@@ -8578,7 +8803,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8578
8803
|
rf = new SprRecordingFile(sessId, ic, it.recs.length, ad);
|
|
8579
8804
|
it.recs.push(rf);
|
|
8580
8805
|
}
|
|
8581
|
-
if (this.enableUploadRecordings) {
|
|
8806
|
+
if (this.enableUploadRecordings && !this.uploadChunkSizeSeconds) {
|
|
8582
8807
|
// TODO use SpeechRecorderconfig resp. RecfileService
|
|
8583
8808
|
// convert asynchronously to 16-bit integer PCM
|
|
8584
8809
|
// TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
|
|
@@ -8657,6 +8882,24 @@ class SessionManager extends BasicRecorder {
|
|
|
8657
8882
|
}
|
|
8658
8883
|
this.changeDetectorRef.detectChanges();
|
|
8659
8884
|
}
|
|
8885
|
+
postChunkAudioBuffer(audioBuffer, chunkIdx) {
|
|
8886
|
+
this.processingRecording = true;
|
|
8887
|
+
let ww = new WavWriter();
|
|
8888
|
+
//new REST API URL
|
|
8889
|
+
let apiEndPoint = '';
|
|
8890
|
+
if (this.config && this.config.apiEndPoint) {
|
|
8891
|
+
apiEndPoint = this.config.apiEndPoint;
|
|
8892
|
+
}
|
|
8893
|
+
if (apiEndPoint !== '') {
|
|
8894
|
+
apiEndPoint = apiEndPoint + '/';
|
|
8895
|
+
}
|
|
8896
|
+
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
8897
|
+
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.promptItem.itemcode + '/' + this.rfUuid + '/' + chunkIdx;
|
|
8898
|
+
ww.writeAsync(audioBuffer, (wavFile) => {
|
|
8899
|
+
this.postRecording(wavFile, recUrl);
|
|
8900
|
+
this.processingRecording = false;
|
|
8901
|
+
});
|
|
8902
|
+
}
|
|
8660
8903
|
postRecording(wavFile, recUrl) {
|
|
8661
8904
|
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
8662
8905
|
let ul = new Upload(wavBlob, recUrl);
|
|
@@ -8834,6 +9077,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
|
|
|
8834
9077
|
}] } });
|
|
8835
9078
|
|
|
8836
9079
|
class RecorderComponent {
|
|
9080
|
+
constructor(uploader) {
|
|
9081
|
+
this.uploader = uploader;
|
|
9082
|
+
this.dataSaved = true;
|
|
9083
|
+
}
|
|
8837
9084
|
}
|
|
8838
9085
|
|
|
8839
9086
|
/**
|
|
@@ -8884,7 +9131,7 @@ var Mode;
|
|
|
8884
9131
|
})(Mode || (Mode = {}));
|
|
8885
9132
|
class SpeechrecorderngComponent extends RecorderComponent {
|
|
8886
9133
|
constructor(route, router, changeDetectorRef, sessionsService, projectService, scriptService, recFilesService, uploader) {
|
|
8887
|
-
super();
|
|
9134
|
+
super(uploader);
|
|
8888
9135
|
this.route = route;
|
|
8889
9136
|
this.router = router;
|
|
8890
9137
|
this.changeDetectorRef = changeDetectorRef;
|
|
@@ -8894,7 +9141,6 @@ class SpeechrecorderngComponent extends RecorderComponent {
|
|
|
8894
9141
|
this.recFilesService = recFilesService;
|
|
8895
9142
|
this.uploader = uploader;
|
|
8896
9143
|
this._project = null;
|
|
8897
|
-
this.dataSaved = true;
|
|
8898
9144
|
}
|
|
8899
9145
|
ngOnInit() {
|
|
8900
9146
|
try {
|
|
@@ -8937,39 +9183,39 @@ class SpeechrecorderngComponent extends RecorderComponent {
|
|
|
8937
9183
|
}
|
|
8938
9184
|
}
|
|
8939
9185
|
fetchSession(sessionId) {
|
|
8940
|
-
//Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'statusMsg: Player initialized.'. Current value: 'statusMsg: Fetching session info...'.
|
|
8941
|
-
// params.subscribe seems not to be asynchronous
|
|
8942
|
-
// this.sm.statusAlertType='info';
|
|
8943
|
-
// this.sm.statusMsg = 'Fetching session info...';
|
|
8944
|
-
// this.sm.statusWaiting=true;
|
|
8945
9186
|
let sessObs = this.sessionsService.sessionObserver(sessionId);
|
|
8946
9187
|
if (sessObs) {
|
|
8947
|
-
sessObs.subscribe(
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
|
|
8955
|
-
this.project
|
|
9188
|
+
sessObs.subscribe({
|
|
9189
|
+
next: sess => {
|
|
9190
|
+
this.setSession(sess);
|
|
9191
|
+
this.sm.statusAlertType = 'info';
|
|
9192
|
+
this.sm.statusMsg = 'Received session info.';
|
|
9193
|
+
this.sm.statusWaiting = false;
|
|
9194
|
+
if (sess.project) {
|
|
9195
|
+
//console.debug("Session associated project: "+sess.project)
|
|
9196
|
+
this.projectService.projectObservable(sess.project).subscribe({
|
|
9197
|
+
next: (project) => {
|
|
9198
|
+
this.project = project;
|
|
9199
|
+
this.fetchScript(sess);
|
|
9200
|
+
}, error: (reason) => {
|
|
9201
|
+
this.sm.statusMsg = reason;
|
|
9202
|
+
this.sm.statusAlertType = 'error';
|
|
9203
|
+
this.sm.statusWaiting = false;
|
|
9204
|
+
console.error("Error fetching project config: " + reason);
|
|
9205
|
+
}
|
|
9206
|
+
});
|
|
9207
|
+
}
|
|
9208
|
+
else {
|
|
9209
|
+
console.info("Session has no associated project. Using default configuration.");
|
|
8956
9210
|
this.fetchScript(sess);
|
|
8957
|
-
}
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
|
|
9211
|
+
}
|
|
9212
|
+
},
|
|
9213
|
+
error: (reason) => {
|
|
9214
|
+
this.sm.statusMsg = reason;
|
|
9215
|
+
this.sm.statusAlertType = 'error';
|
|
9216
|
+
this.sm.statusWaiting = false;
|
|
9217
|
+
console.error("Error fetching session " + reason);
|
|
8963
9218
|
}
|
|
8964
|
-
else {
|
|
8965
|
-
console.info("Session has no associated project. Using default configuration.");
|
|
8966
|
-
this.fetchScript(sess);
|
|
8967
|
-
}
|
|
8968
|
-
}, (reason) => {
|
|
8969
|
-
this.sm.statusMsg = reason;
|
|
8970
|
-
this.sm.statusAlertType = 'error';
|
|
8971
|
-
this.sm.statusWaiting = false;
|
|
8972
|
-
console.error("Error fetching session " + reason);
|
|
8973
9219
|
});
|
|
8974
9220
|
}
|
|
8975
9221
|
}
|
|
@@ -8978,19 +9224,21 @@ class SpeechrecorderngComponent extends RecorderComponent {
|
|
|
8978
9224
|
this.sm.statusAlertType = 'info';
|
|
8979
9225
|
this.sm.statusMsg = 'Fetching recording script...';
|
|
8980
9226
|
this.sm.statusWaiting = true;
|
|
8981
|
-
this.scriptService.scriptObservable(sess.script).subscribe(
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
9227
|
+
this.scriptService.scriptObservable(sess.script).subscribe({
|
|
9228
|
+
next: (script) => {
|
|
9229
|
+
this.sm.statusAlertType = 'info';
|
|
9230
|
+
this.sm.statusMsg = 'Received recording script.';
|
|
9231
|
+
this.sm.statusWaiting = false;
|
|
9232
|
+
this.setScript(script);
|
|
9233
|
+
this.sm.session = sess;
|
|
9234
|
+
this.fetchRecordings(sess, this.script);
|
|
9235
|
+
}, error: (reason) => {
|
|
9236
|
+
let errMsg = "Error fetching recording script: " + reason;
|
|
9237
|
+
console.error(errMsg);
|
|
9238
|
+
this.sm.statusMsg = errMsg;
|
|
9239
|
+
this.sm.statusAlertType = 'error';
|
|
9240
|
+
this.sm.statusWaiting = false;
|
|
9241
|
+
}
|
|
8994
9242
|
});
|
|
8995
9243
|
}
|
|
8996
9244
|
else {
|
|
@@ -9007,29 +9255,31 @@ class SpeechrecorderngComponent extends RecorderComponent {
|
|
|
9007
9255
|
let prNm = null;
|
|
9008
9256
|
if (this.project) {
|
|
9009
9257
|
let rfsObs = this.recFilesService.recordingFileDescrList(this.project.name, sess.sessionId);
|
|
9010
|
-
rfsObs.subscribe(
|
|
9011
|
-
|
|
9012
|
-
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
if (rfs
|
|
9016
|
-
rfs
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9258
|
+
rfsObs.subscribe({
|
|
9259
|
+
next: (rfs) => {
|
|
9260
|
+
this.sm.statusAlertType = 'info';
|
|
9261
|
+
this.sm.statusMsg = 'Received infos of recordings.';
|
|
9262
|
+
this.sm.statusWaiting = false;
|
|
9263
|
+
if (rfs) {
|
|
9264
|
+
if (rfs instanceof Array) {
|
|
9265
|
+
rfs.forEach((rf) => {
|
|
9266
|
+
//console.debug("Already recorded: " + rf+ " "+rf.recording.itemcode);
|
|
9267
|
+
this.sm.addRecordingFileByDescriptor(rf);
|
|
9268
|
+
});
|
|
9269
|
+
}
|
|
9270
|
+
else {
|
|
9271
|
+
console.error('Expected type array for list of already recorded files ');
|
|
9272
|
+
}
|
|
9020
9273
|
}
|
|
9021
9274
|
else {
|
|
9022
|
-
console.
|
|
9275
|
+
//console.debug("Recording file list: " + rfs);
|
|
9023
9276
|
}
|
|
9277
|
+
}, error: (err) => {
|
|
9278
|
+
// we start the session anyway
|
|
9279
|
+
this.startSession();
|
|
9280
|
+
}, complete: () => {
|
|
9281
|
+
this.startSession();
|
|
9024
9282
|
}
|
|
9025
|
-
else {
|
|
9026
|
-
//console.debug("Recording file list: " + rfs);
|
|
9027
|
-
}
|
|
9028
|
-
}, () => {
|
|
9029
|
-
// we start the session anyway
|
|
9030
|
-
this.startSession();
|
|
9031
|
-
}, () => {
|
|
9032
|
-
this.startSession();
|
|
9033
9283
|
});
|
|
9034
9284
|
}
|
|
9035
9285
|
else {
|
|
@@ -9052,36 +9302,10 @@ class SpeechrecorderngComponent extends RecorderComponent {
|
|
|
9052
9302
|
return this.dataSaved && !this.sm.isActive();
|
|
9053
9303
|
}
|
|
9054
9304
|
init() {
|
|
9055
|
-
|
|
9056
|
-
//var getUserMediaFnct= n.getUserMedia || n.webkitGetUserMedia ||
|
|
9057
|
-
// n.mozGetUserMedia || n.msGetUserMedia;
|
|
9058
|
-
var w = window;
|
|
9059
|
-
// TODO test onyl !!
|
|
9060
|
-
// let debugFail=true;
|
|
9061
|
-
// AudioContext = w.AudioContext || w.webkitAudioContext;
|
|
9062
|
-
// if (typeof AudioContext !== 'function' || debugFail) {
|
|
9063
|
-
// this.sm.statusAlertType='error';
|
|
9064
|
-
// this.sm.statusMsg = 'ERROR: Browser does not support Web Audio API!';
|
|
9065
|
-
// return false;
|
|
9066
|
-
// } else {
|
|
9067
|
-
// var context = new AudioContext();
|
|
9068
|
-
//
|
|
9069
|
-
// if (typeof navigator.mediaDevices.getUserMedia !== 'function') {
|
|
9070
|
-
// this.sm.statusAlertType='error';
|
|
9071
|
-
// this.sm.statusMsg= 'ERROR: Browser does not support Media streams!';
|
|
9072
|
-
// return false;
|
|
9073
|
-
// } else {
|
|
9074
|
-
//
|
|
9075
|
-
//this.sm = new SessionManager(new SimpleTrafficLight(), this.uploader);
|
|
9076
|
-
//this.sm.init();
|
|
9077
|
-
//this.ap = new AudioPlayer(context,this);
|
|
9078
|
-
//this.sm.listener=this;
|
|
9079
|
-
// }
|
|
9080
|
-
// }
|
|
9305
|
+
//TODO Duplicate code in AudioRecorderComponent
|
|
9081
9306
|
this.uploader.listener = (ue) => {
|
|
9082
9307
|
this.uploadUpdate(ue);
|
|
9083
9308
|
};
|
|
9084
|
-
//TODO Duplicate code in AudioRecorderComponent
|
|
9085
9309
|
window.addEventListener('beforeunload', (e) => {
|
|
9086
9310
|
console.debug("Before page unload event");
|
|
9087
9311
|
if (this.ready()) {
|
|
@@ -9170,6 +9394,13 @@ class SpeechrecorderngComponent extends RecorderComponent {
|
|
|
9170
9394
|
chCnt = ProjectUtil.audioChannelCount(project);
|
|
9171
9395
|
console.info("Project requested recording channel count: " + chCnt);
|
|
9172
9396
|
this.sm.autoGainControlConfigs = project.autoGainControlConfigs;
|
|
9397
|
+
if (project.chunkedRecording === true) {
|
|
9398
|
+
console.debug("Enable chunked upload: chunkSize: " + BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS);
|
|
9399
|
+
this.sm.uploadChunkSizeSeconds = BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS;
|
|
9400
|
+
}
|
|
9401
|
+
else {
|
|
9402
|
+
this.sm.uploadChunkSizeSeconds = null;
|
|
9403
|
+
}
|
|
9173
9404
|
}
|
|
9174
9405
|
else {
|
|
9175
9406
|
console.error("Empty project configuration!");
|
|
@@ -9206,50 +9437,7 @@ class SpeechrecorderngComponent extends RecorderComponent {
|
|
|
9206
9437
|
pLoader.send();
|
|
9207
9438
|
}
|
|
9208
9439
|
}
|
|
9209
|
-
// loadScript(callback: ()=>any){
|
|
9210
|
-
// var scrLoader = new XMLHttpRequest();
|
|
9211
|
-
// let hn:string =window.location.hostname;
|
|
9212
|
-
// let pn:string =window.location.pathname;
|
|
9213
|
-
// let pr:string =window.location.protocol;
|
|
9214
|
-
// let po:string =window.location.port;
|
|
9215
|
-
//
|
|
9216
|
-
// let sessionId:string=this.session.sessionId;
|
|
9217
|
-
//
|
|
9218
|
-
// let scrUrl:string | null = null;
|
|
9219
|
-
//
|
|
9220
|
-
// if (hn === 'localhost' || this.mode===Mode.DEMO) {
|
|
9221
|
-
// // local debug mode
|
|
9222
|
-
// // FF caches
|
|
9223
|
-
// scrUrl = 'test/' + this.session.script.toString() + '.json?' + new Date().getTime();
|
|
9224
|
-
//
|
|
9225
|
-
// } else {
|
|
9226
|
-
// let scrPath:string = '/wikispeech/session/scripts/servlet';
|
|
9227
|
-
// let scrQu:string = 'sessionId=' + sessionId;
|
|
9228
|
-
// scrUrl = pr + '//' + hn + ':' + po + scrPath;
|
|
9229
|
-
// if (scrQu) {
|
|
9230
|
-
// scrUrl = scrUrl + '?' + scrQu;
|
|
9231
|
-
// }
|
|
9232
|
-
// }
|
|
9233
|
-
//
|
|
9234
|
-
// scrLoader.open("GET",scrUrl , true);
|
|
9235
|
-
// scrLoader.setRequestHeader('Accept','application/json');
|
|
9236
|
-
// scrLoader.responseType = "json";
|
|
9237
|
-
// scrLoader.onload = (e) => {
|
|
9238
|
-
//
|
|
9239
|
-
// this.script = scrLoader.response;
|
|
9240
|
-
//
|
|
9241
|
-
//
|
|
9242
|
-
// this.sm.script = this.script;
|
|
9243
|
-
//
|
|
9244
|
-
// callback();
|
|
9245
|
-
// }
|
|
9246
|
-
// scrLoader.onerror = (e) => {
|
|
9247
|
-
// console.log("Error downloading recording script data ...");
|
|
9248
|
-
// }
|
|
9249
|
-
// scrLoader.send();
|
|
9250
|
-
// }
|
|
9251
9440
|
start() {
|
|
9252
|
-
//this.configure();
|
|
9253
9441
|
}
|
|
9254
9442
|
audioPlayerUpdate(e) {
|
|
9255
9443
|
if (EventType.STARTED === e.type) {
|
|
@@ -10929,13 +11117,12 @@ class Item {
|
|
|
10929
11117
|
}
|
|
10930
11118
|
}
|
|
10931
11119
|
class AudioRecorder extends BasicRecorder {
|
|
10932
|
-
constructor(changeDetectorRef, renderer, route, dialog,
|
|
10933
|
-
super(dialog, sessionService);
|
|
11120
|
+
constructor(changeDetectorRef, renderer, route, dialog, sessionService, recFileService, uploader, config) {
|
|
11121
|
+
super(dialog, sessionService, uploader, config);
|
|
10934
11122
|
this.changeDetectorRef = changeDetectorRef;
|
|
10935
11123
|
this.renderer = renderer;
|
|
10936
11124
|
this.route = route;
|
|
10937
11125
|
this.dialog = dialog;
|
|
10938
|
-
this.projectService = projectService;
|
|
10939
11126
|
this.sessionService = sessionService;
|
|
10940
11127
|
this.recFileService = recFileService;
|
|
10941
11128
|
this.uploader = uploader;
|
|
@@ -10946,7 +11133,6 @@ class AudioRecorder extends BasicRecorder {
|
|
|
10946
11133
|
this.enableDownloadRecordings = false;
|
|
10947
11134
|
this.status = 0 /* BLOCKED */;
|
|
10948
11135
|
this.dataSaved = true;
|
|
10949
|
-
this.startedDate = null;
|
|
10950
11136
|
this.maxRecTimerId = null;
|
|
10951
11137
|
this.maxRecTimerRunning = false;
|
|
10952
11138
|
this._promptIndex = null;
|
|
@@ -11037,7 +11223,7 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11037
11223
|
if (this.ac) {
|
|
11038
11224
|
this.transportActions.startAction.onAction = () => this.startItem();
|
|
11039
11225
|
this.ac.listener = this;
|
|
11040
|
-
this.
|
|
11226
|
+
this.configureStreamCaptureStream();
|
|
11041
11227
|
// Don't list the devices here. If we do not have audio permissions we only get anonymized devices without labels.
|
|
11042
11228
|
//this.ac.listDevices();
|
|
11043
11229
|
}
|
|
@@ -11064,23 +11250,6 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11064
11250
|
this.uploader.listener = (ue) => {
|
|
11065
11251
|
this.uploadUpdate(ue);
|
|
11066
11252
|
};
|
|
11067
|
-
let wakeLockSupp = ('wakeLock' in navigator);
|
|
11068
|
-
// if(wakeLockSupp) {
|
|
11069
|
-
// let wakeLock = null;
|
|
11070
|
-
// try {
|
|
11071
|
-
// //@ts-ignore
|
|
11072
|
-
// wakeLock = navigator.wakeLock.request('screen');
|
|
11073
|
-
//
|
|
11074
|
-
// //statusElem.textContent = 'Wake Lock is active!';
|
|
11075
|
-
// } catch (err) {
|
|
11076
|
-
// // The Wake Lock request has failed - usually system related, such as battery.
|
|
11077
|
-
// console.error('Wakelock failed'+err)
|
|
11078
|
-
// }
|
|
11079
|
-
// }else{
|
|
11080
|
-
// let noSleep=new NoSleep();
|
|
11081
|
-
// noSleep.enable();
|
|
11082
|
-
//
|
|
11083
|
-
// }
|
|
11084
11253
|
}
|
|
11085
11254
|
onKeyPress(ke) {
|
|
11086
11255
|
if (ke.key == ' ') {
|
|
@@ -11133,36 +11302,36 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11133
11302
|
let prNm = null;
|
|
11134
11303
|
if (this.project) {
|
|
11135
11304
|
let rfsObs = this.recFileService.recordingFileList(this.project.name, sess.sessionId);
|
|
11136
|
-
rfsObs.subscribe((rfs) => {
|
|
11137
|
-
|
|
11138
|
-
|
|
11139
|
-
|
|
11140
|
-
|
|
11141
|
-
|
|
11142
|
-
|
|
11143
|
-
|
|
11144
|
-
|
|
11145
|
-
|
|
11146
|
-
|
|
11147
|
-
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
|
|
11305
|
+
rfsObs.subscribe({ next: (rfs) => {
|
|
11306
|
+
this.statusAlertType = 'info';
|
|
11307
|
+
this.statusMsg = 'Received infos of recordings.';
|
|
11308
|
+
this.statusWaiting = false;
|
|
11309
|
+
if (rfs) {
|
|
11310
|
+
if (rfs instanceof Array) {
|
|
11311
|
+
rfs.forEach((rf) => {
|
|
11312
|
+
if (rf.startedDate) {
|
|
11313
|
+
rf._startedAsDateObj = new Date(rf.startedDate);
|
|
11314
|
+
}
|
|
11315
|
+
if (rf.date) {
|
|
11316
|
+
rf._dateAsDateObj = new Date(rf.date);
|
|
11317
|
+
}
|
|
11318
|
+
this.recorderCombiPane.push(rf);
|
|
11319
|
+
});
|
|
11320
|
+
}
|
|
11321
|
+
else {
|
|
11322
|
+
console.error('Expected type array for list of already recorded files ');
|
|
11323
|
+
}
|
|
11151
11324
|
}
|
|
11152
11325
|
else {
|
|
11153
|
-
console.
|
|
11326
|
+
//console.debug("Recording file list: " + rfs);
|
|
11154
11327
|
}
|
|
11155
|
-
}
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
}
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
|
|
11162
|
-
}, () => {
|
|
11163
|
-
// Normal start
|
|
11164
|
-
this.start();
|
|
11165
|
-
});
|
|
11328
|
+
}, error: (err) => {
|
|
11329
|
+
// Failed fetching existing, but we start the session anyway
|
|
11330
|
+
this.start();
|
|
11331
|
+
}, complete: () => {
|
|
11332
|
+
// Normal start
|
|
11333
|
+
this.start();
|
|
11334
|
+
} });
|
|
11166
11335
|
}
|
|
11167
11336
|
else {
|
|
11168
11337
|
// No project def -> error
|
|
@@ -11184,6 +11353,12 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11184
11353
|
chCnt = ProjectUtil.audioChannelCount(project);
|
|
11185
11354
|
console.info("Project requested recording channel count: " + chCnt);
|
|
11186
11355
|
this.autoGainControlConfigs = project.autoGainControlConfigs;
|
|
11356
|
+
if (project.chunkedRecording === true) {
|
|
11357
|
+
this.uploadChunkSizeSeconds = BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS;
|
|
11358
|
+
}
|
|
11359
|
+
else {
|
|
11360
|
+
this.uploadChunkSizeSeconds = null;
|
|
11361
|
+
}
|
|
11187
11362
|
}
|
|
11188
11363
|
else {
|
|
11189
11364
|
console.error("Empty project configuration!");
|
|
@@ -11283,12 +11458,7 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11283
11458
|
}
|
|
11284
11459
|
}
|
|
11285
11460
|
startItem() {
|
|
11286
|
-
|
|
11287
|
-
this.transportActions.startAction.disabled = true;
|
|
11288
|
-
this.transportActions.pauseAction.disabled = true;
|
|
11289
|
-
if (this.readonly) {
|
|
11290
|
-
return;
|
|
11291
|
-
}
|
|
11461
|
+
super.startItem();
|
|
11292
11462
|
this.transportActions.fwdAction.disabled = true;
|
|
11293
11463
|
this.transportActions.fwdNextAction.disabled = true;
|
|
11294
11464
|
this.transportActions.bwdAction.disabled = true;
|
|
@@ -11440,8 +11610,7 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11440
11610
|
}
|
|
11441
11611
|
}
|
|
11442
11612
|
started() {
|
|
11443
|
-
|
|
11444
|
-
this.transportActions.startAction.disabled = true;
|
|
11613
|
+
super.started();
|
|
11445
11614
|
this.statusAlertType = 'info';
|
|
11446
11615
|
this.statusMsg = 'Recording...';
|
|
11447
11616
|
let maxRecordingTimeMs = MAX_RECORDING_TIME_MS;
|
|
@@ -11474,24 +11643,6 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11474
11643
|
this.ac.stop();
|
|
11475
11644
|
}
|
|
11476
11645
|
}
|
|
11477
|
-
// addRecordingFileByDescriptor(rfd:RecordingFileDescriptorImpl){
|
|
11478
|
-
// let prIdx=0;
|
|
11479
|
-
// if(this.items) {
|
|
11480
|
-
// let it = this.items[prIdx];
|
|
11481
|
-
// if (it) {
|
|
11482
|
-
// if (!it.recs) {
|
|
11483
|
-
// it.recs = new Array<SprRecordingFile>();
|
|
11484
|
-
// }
|
|
11485
|
-
//
|
|
11486
|
-
// } else {
|
|
11487
|
-
// //console.debug("WARN: No recording item with code: \"" +rfd.recording.itemcode+ "\" found.");
|
|
11488
|
-
// }
|
|
11489
|
-
// }
|
|
11490
|
-
// }
|
|
11491
|
-
//
|
|
11492
|
-
// addRecordingFileByPromptIndex(promptIndex:number, rf:SprRecordingFile){
|
|
11493
|
-
//
|
|
11494
|
-
// }
|
|
11495
11646
|
stopped() {
|
|
11496
11647
|
this.updateStartActionDisableState();
|
|
11497
11648
|
this.transportActions.stopAction.disabled = true;
|
|
@@ -11506,41 +11657,39 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11506
11657
|
if (this._session) {
|
|
11507
11658
|
sessId = this._session.sessionId;
|
|
11508
11659
|
}
|
|
11509
|
-
|
|
11660
|
+
if (!this.rfUuid) {
|
|
11661
|
+
this.rfUuid = UUID.generate();
|
|
11662
|
+
}
|
|
11663
|
+
let rf = new RecordingFile(this.rfUuid, sessId, ad);
|
|
11510
11664
|
rf._startedAsDateObj = this.startedDate;
|
|
11511
11665
|
if (rf._startedAsDateObj) {
|
|
11512
11666
|
rf.startedDate = rf._startedAsDateObj.toString();
|
|
11513
11667
|
}
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
if (
|
|
11519
|
-
apiEndPoint =
|
|
11668
|
+
rf.frames = ad.length;
|
|
11669
|
+
this.displayRecFile = rf;
|
|
11670
|
+
this.recorderCombiPane.push(rf);
|
|
11671
|
+
// Upload if upload enabled and not in chunked upload mode
|
|
11672
|
+
if (this.enableUploadRecordings && !this.uploadChunkSizeSeconds) {
|
|
11673
|
+
let apiEndPoint = '';
|
|
11674
|
+
if (this.config && this.config.apiEndPoint) {
|
|
11675
|
+
apiEndPoint = this.config.apiEndPoint;
|
|
11676
|
+
}
|
|
11677
|
+
if (apiEndPoint !== '') {
|
|
11678
|
+
apiEndPoint = apiEndPoint + '/';
|
|
11679
|
+
}
|
|
11680
|
+
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
11681
|
+
let recUrl = sessionsUrl + '/' + rf.session + '/' + RECFILE_API_CTX + '/' + rf.uuid;
|
|
11682
|
+
// convert asynchronously to 16-bit integer PCM
|
|
11683
|
+
// TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
|
|
11684
|
+
// TODO duplicate conversion for manual download
|
|
11685
|
+
this.processingRecording = true;
|
|
11686
|
+
let ww = new WavWriter();
|
|
11687
|
+
ww.writeAsync(ad, (wavFile) => {
|
|
11688
|
+
this.postRecordingMultipart(wavFile, rf.uuid, rf.session, rf._startedAsDateObj, recUrl);
|
|
11689
|
+
this.processingRecording = false;
|
|
11690
|
+
this.changeDetectorRef.detectChanges();
|
|
11691
|
+
});
|
|
11520
11692
|
}
|
|
11521
|
-
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
11522
|
-
let recUrl = sessionsUrl + '/' + rf.session + '/' + RECFILE_API_CTX + '/' + rf.uuid;
|
|
11523
|
-
//
|
|
11524
|
-
//
|
|
11525
|
-
//
|
|
11526
|
-
// // convert asynchronously to 16-bit integer PCM
|
|
11527
|
-
// // TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
|
|
11528
|
-
// // TODO duplicate conversion for manual download
|
|
11529
|
-
// //console.log("Build wav writer...");
|
|
11530
|
-
this.processingRecording = true;
|
|
11531
|
-
let ww = new WavWriter();
|
|
11532
|
-
ww.writeAsync(ad, (wavFile) => {
|
|
11533
|
-
//this.postRecording(wavFile, recUrl);
|
|
11534
|
-
//rf._dateAsDateObj=new Date();
|
|
11535
|
-
rf.frames = ad.length;
|
|
11536
|
-
this.displayRecFile = rf;
|
|
11537
|
-
//this.recordingListComp.recordingList.push(rf);
|
|
11538
|
-
this.recorderCombiPane.push(rf);
|
|
11539
|
-
this.postRecordingMultipart(wavFile, rf.uuid, rf.session, rf._startedAsDateObj, recUrl);
|
|
11540
|
-
this.processingRecording = false;
|
|
11541
|
-
this.changeDetectorRef.detectChanges();
|
|
11542
|
-
});
|
|
11543
|
-
// }
|
|
11544
11693
|
}
|
|
11545
11694
|
// check complete session
|
|
11546
11695
|
let complete = true;
|
|
@@ -11551,11 +11700,6 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11551
11700
|
this.updateNavigationActions();
|
|
11552
11701
|
this.changeDetectorRef.detectChanges();
|
|
11553
11702
|
}
|
|
11554
|
-
postRecording(wavFile, recUrl) {
|
|
11555
|
-
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
11556
|
-
let ul = new Upload(wavBlob, recUrl);
|
|
11557
|
-
this.uploader.queueUpload(ul);
|
|
11558
|
-
}
|
|
11559
11703
|
postRecordingMultipart(wavFile, uuid, sessionId, startedDate, recUrl) {
|
|
11560
11704
|
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
11561
11705
|
let fd = new FormData();
|
|
@@ -11572,6 +11716,24 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11572
11716
|
let ul = new Upload(fd, recUrl);
|
|
11573
11717
|
this.uploader.queueUpload(ul);
|
|
11574
11718
|
}
|
|
11719
|
+
postChunkAudioBuffer(audioBuffer, chunkIdx) {
|
|
11720
|
+
this.processingRecording = true;
|
|
11721
|
+
let ww = new WavWriter();
|
|
11722
|
+
//new REST API URL
|
|
11723
|
+
let apiEndPoint = '';
|
|
11724
|
+
if (this.config && this.config.apiEndPoint) {
|
|
11725
|
+
apiEndPoint = this.config.apiEndPoint;
|
|
11726
|
+
}
|
|
11727
|
+
if (apiEndPoint !== '') {
|
|
11728
|
+
apiEndPoint = apiEndPoint + '/';
|
|
11729
|
+
}
|
|
11730
|
+
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
11731
|
+
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.rfUuid + '/' + chunkIdx;
|
|
11732
|
+
ww.writeAsync(audioBuffer, (wavFile) => {
|
|
11733
|
+
this.postRecording(wavFile, recUrl);
|
|
11734
|
+
this.processingRecording = false;
|
|
11735
|
+
});
|
|
11736
|
+
}
|
|
11575
11737
|
stop() {
|
|
11576
11738
|
if (this.ac) {
|
|
11577
11739
|
this.ac.close();
|
|
@@ -11599,8 +11761,8 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11599
11761
|
}
|
|
11600
11762
|
}
|
|
11601
11763
|
}
|
|
11602
|
-
AudioRecorder.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: AudioRecorder, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i1$1.ActivatedRoute }, { token: i1$2.MatDialog }, { token:
|
|
11603
|
-
AudioRecorder.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.2", type: AudioRecorder, selector: "app-audiorecorder", inputs: {
|
|
11764
|
+
AudioRecorder.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: AudioRecorder, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i1$1.ActivatedRoute }, { token: i1$2.MatDialog }, { token: SessionService }, { token: RecordingService }, { token: SpeechRecorderUploader }, { token: SPEECHRECORDER_CONFIG }], target: i0.ɵɵFactoryTarget.Component });
|
|
11765
|
+
AudioRecorder.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.2", 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: `
|
|
11604
11766
|
<app-warningbar [show]="isTestSession()" warningText="Test recording only!"></app-warningbar>
|
|
11605
11767
|
<app-warningbar [show]="isDefaultAudioTestSession()"
|
|
11606
11768
|
warningText="This test uses default audio device! Regular sessions may require a particular audio device (microphone)!"></app-warningbar>
|
|
@@ -11755,12 +11917,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
|
|
|
11755
11917
|
}`
|
|
11756
11918
|
]
|
|
11757
11919
|
}]
|
|
11758
|
-
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i1$1.ActivatedRoute }, { type: i1$2.MatDialog }, { type:
|
|
11920
|
+
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i1$1.ActivatedRoute }, { type: i1$2.MatDialog }, { type: SessionService }, { type: RecordingService }, { type: SpeechRecorderUploader }, { type: SpeechRecorderConfig, decorators: [{
|
|
11759
11921
|
type: Inject,
|
|
11760
11922
|
args: [SPEECHRECORDER_CONFIG]
|
|
11761
|
-
}] }]; }, propDecorators: {
|
|
11762
|
-
type: Input
|
|
11763
|
-
}], projectName: [{
|
|
11923
|
+
}] }]; }, propDecorators: { projectName: [{
|
|
11764
11924
|
type: Input
|
|
11765
11925
|
}], recorderCombiPane: [{
|
|
11766
11926
|
type: ViewChild,
|
|
@@ -11778,16 +11938,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
|
|
|
11778
11938
|
args: ['window:keydown', ['$event']]
|
|
11779
11939
|
}] } });
|
|
11780
11940
|
class AudioRecorderComponent extends RecorderComponent {
|
|
11781
|
-
constructor(injector, route, router, changeDetectorRef, sessionService, projectService,
|
|
11782
|
-
super();
|
|
11941
|
+
constructor(injector, route, router, changeDetectorRef, sessionService, projectService, uploader) {
|
|
11942
|
+
super(uploader);
|
|
11783
11943
|
this.injector = injector;
|
|
11784
11944
|
this.route = route;
|
|
11785
11945
|
this.router = router;
|
|
11786
11946
|
this.changeDetectorRef = changeDetectorRef;
|
|
11787
11947
|
this.sessionService = sessionService;
|
|
11788
11948
|
this.projectService = projectService;
|
|
11789
|
-
this.
|
|
11790
|
-
this.dataSaved = true;
|
|
11949
|
+
this.uploader = uploader;
|
|
11791
11950
|
}
|
|
11792
11951
|
ngOnInit() {
|
|
11793
11952
|
//super.ngOnInit();
|
|
@@ -11822,6 +11981,9 @@ class AudioRecorderComponent extends RecorderComponent {
|
|
|
11822
11981
|
});
|
|
11823
11982
|
}
|
|
11824
11983
|
ngAfterViewInit() {
|
|
11984
|
+
this.uploader.listener = (ue) => {
|
|
11985
|
+
this.uploadUpdate(ue);
|
|
11986
|
+
};
|
|
11825
11987
|
this.route.queryParams.subscribe((params) => {
|
|
11826
11988
|
if (params['sessionId']) {
|
|
11827
11989
|
this.fetchSession(params['sessionId']);
|
|
@@ -11838,50 +12000,68 @@ class AudioRecorderComponent extends RecorderComponent {
|
|
|
11838
12000
|
//super.ngOnDestroy();
|
|
11839
12001
|
}
|
|
11840
12002
|
fetchSession(sessionId) {
|
|
11841
|
-
//Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'statusMsg: Player initialized.'. Current value: 'statusMsg: Fetching session info...'.
|
|
11842
|
-
// params.subscribe seems not to be asynchronous
|
|
11843
|
-
// this.sm.statusAlertType='info';
|
|
11844
|
-
// this.sm.statusMsg = 'Fetching session info...';
|
|
11845
|
-
// this.sm.statusWaiting=true;
|
|
11846
12003
|
let sessObs = this.sessionService.sessionObserver(sessionId);
|
|
11847
12004
|
if (sessObs) {
|
|
11848
|
-
sessObs.subscribe(
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
this.
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
12005
|
+
sessObs.subscribe({
|
|
12006
|
+
next: (sess) => {
|
|
12007
|
+
this.ar.statusAlertType = 'info';
|
|
12008
|
+
this.ar.statusMsg = 'Received session info.';
|
|
12009
|
+
this.ar.statusWaiting = false;
|
|
12010
|
+
this.session = sess;
|
|
12011
|
+
this.ar.session = sess;
|
|
12012
|
+
if (sess.project) {
|
|
12013
|
+
//console.debug("Session associated project: "+sess.project)
|
|
12014
|
+
this.projectService.projectObservable(sess.project).subscribe({
|
|
12015
|
+
next: (project) => {
|
|
12016
|
+
this.ar.project = project;
|
|
12017
|
+
this.ar.fetchRecordings(sess);
|
|
12018
|
+
}, error: (reason) => {
|
|
12019
|
+
this.ar.statusMsg = reason;
|
|
12020
|
+
this.ar.statusAlertType = 'error';
|
|
12021
|
+
this.ar.statusWaiting = false;
|
|
12022
|
+
console.error("Error fetching project config: " + reason);
|
|
12023
|
+
}
|
|
12024
|
+
});
|
|
12025
|
+
}
|
|
12026
|
+
else {
|
|
12027
|
+
console.info("Session has no associated project. Using default configuration.");
|
|
12028
|
+
}
|
|
12029
|
+
},
|
|
12030
|
+
error: (reason) => {
|
|
12031
|
+
this.ar.statusMsg = reason;
|
|
12032
|
+
this.ar.statusAlertType = 'error';
|
|
12033
|
+
this.ar.statusWaiting = false;
|
|
12034
|
+
console.error("Error fetching session " + reason);
|
|
11868
12035
|
}
|
|
11869
|
-
}, (reason) => {
|
|
11870
|
-
this.ar.statusMsg = reason;
|
|
11871
|
-
this.ar.statusAlertType = 'error';
|
|
11872
|
-
this.ar.statusWaiting = false;
|
|
11873
|
-
console.error("Error fetching session " + reason);
|
|
11874
12036
|
});
|
|
11875
12037
|
}
|
|
11876
12038
|
}
|
|
12039
|
+
uploadUpdate(ue) {
|
|
12040
|
+
let upStatus = ue.status;
|
|
12041
|
+
this.dataSaved = (UploaderStatus.DONE === upStatus);
|
|
12042
|
+
let percentUpl = ue.percentDone();
|
|
12043
|
+
if (UploaderStatus.ERR === upStatus) {
|
|
12044
|
+
this.ar.uploadStatus = 'warn';
|
|
12045
|
+
}
|
|
12046
|
+
else {
|
|
12047
|
+
if (percentUpl < 50) {
|
|
12048
|
+
this.ar.uploadStatus = 'accent';
|
|
12049
|
+
}
|
|
12050
|
+
else {
|
|
12051
|
+
this.ar.uploadStatus = 'success';
|
|
12052
|
+
}
|
|
12053
|
+
this.ar.uploadProgress = percentUpl;
|
|
12054
|
+
}
|
|
12055
|
+
this.changeDetectorRef.detectChanges();
|
|
12056
|
+
}
|
|
11877
12057
|
ready() {
|
|
11878
12058
|
return this.dataSaved && !this.ar.isActive();
|
|
11879
12059
|
}
|
|
11880
12060
|
}
|
|
11881
|
-
AudioRecorderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: AudioRecorderComponent, deps: [{ token: i0.Injector }, { token: i1$1.ActivatedRoute }, { token: i1$1.Router }, { token: i0.ChangeDetectorRef }, { token: SessionService }, { token: ProjectService }, { token:
|
|
12061
|
+
AudioRecorderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: AudioRecorderComponent, deps: [{ token: i0.Injector }, { token: i1$1.ActivatedRoute }, { token: i1$1.Router }, { token: i0.ChangeDetectorRef }, { token: SessionService }, { token: ProjectService }, { token: SpeechRecorderUploader }], target: i0.ɵɵFactoryTarget.Component });
|
|
11882
12062
|
AudioRecorderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.2", type: AudioRecorderComponent, selector: "app-audiorecorder-comp", providers: [SessionService], viewQueries: [{ propertyName: "ar", first: true, predicate: AudioRecorder, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
|
|
11883
12063
|
<app-audiorecorder [projectName]="_project?.name" [dataSaved]="dataSaved"></app-audiorecorder>
|
|
11884
|
-
`, isInline: true, styles: [":host{flex:2;display:flex;height:100%;flex-direction:column;min-height:0}\n"], components: [{ type: AudioRecorder, selector: "app-audiorecorder", inputs: ["
|
|
12064
|
+
`, isInline: true, styles: [":host{flex:2;display:flex;height:100%;flex-direction:column;min-height:0}\n"], components: [{ type: AudioRecorder, selector: "app-audiorecorder", inputs: ["projectName", "dataSaved"] }] });
|
|
11885
12065
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: AudioRecorderComponent, decorators: [{
|
|
11886
12066
|
type: Component,
|
|
11887
12067
|
args: [{
|
|
@@ -11899,7 +12079,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
|
|
|
11899
12079
|
|
|
11900
12080
|
}`]
|
|
11901
12081
|
}]
|
|
11902
|
-
}], ctorParameters: function () { return [{ type: i0.Injector }, { type: i1$1.ActivatedRoute }, { type: i1$1.Router }, { type: i0.ChangeDetectorRef }, { type: SessionService }, { type: ProjectService }, { type:
|
|
12082
|
+
}], ctorParameters: function () { return [{ type: i0.Injector }, { type: i1$1.ActivatedRoute }, { type: i1$1.Router }, { type: i0.ChangeDetectorRef }, { type: SessionService }, { type: ProjectService }, { type: SpeechRecorderUploader }]; }, propDecorators: { ar: [{
|
|
11903
12083
|
type: ViewChild,
|
|
11904
12084
|
args: [AudioRecorder, { static: true }]
|
|
11905
12085
|
}] } });
|
|
@@ -11948,7 +12128,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
|
|
|
11948
12128
|
}]
|
|
11949
12129
|
}] });
|
|
11950
12130
|
|
|
11951
|
-
const VERSION = '2.
|
|
12131
|
+
const VERSION = '2.25.0';
|
|
11952
12132
|
|
|
11953
12133
|
/*
|
|
11954
12134
|
* Public API Surface of speechrecorderng
|