speechrecorderng 2.18.13 → 2.19.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.
@@ -720,15 +720,309 @@
720
720
  }());
721
721
  AudioPlayer.DEFAULT_BUFSIZE = 8192;
722
722
 
723
- var AudioStreamConstr = /** @class */ (function () {
724
- function AudioStreamConstr() {
725
- this.audio = true;
726
- this.video = false;
723
+ var UserAgentComponent = /** @class */ (function () {
724
+ function UserAgentComponent(name, version, comment) {
725
+ this.name = name;
726
+ this.version = version;
727
+ this.comment = comment;
727
728
  }
728
- return AudioStreamConstr;
729
+ UserAgentComponent.prototype.toString = function () {
730
+ var s = '[' + this.name + ']';
731
+ if (this.version) {
732
+ s = s + ' [' + this.version + ']';
733
+ }
734
+ if (this.comment) {
735
+ s = s + ' [' + this.comment + ']';
736
+ }
737
+ return s;
738
+ };
739
+ return UserAgentComponent;
740
+ }());
741
+ var NAME_FIREFOX = 'Firefox';
742
+ var NAME_CHROME = 'Chrome';
743
+ var NAME_SAFARI = 'Safari';
744
+ var NAME_EDGE = 'Edge';
745
+ var Browser$1;
746
+ (function (Browser) {
747
+ Browser["Firefox"] = "Firefox";
748
+ Browser["Chrome"] = "Chrome";
749
+ Browser["Safari"] = "Safari";
750
+ Browser["Edge"] = "Edge";
751
+ })(Browser$1 || (Browser$1 = {}));
752
+ var OS_WINDOWS = 'Windows';
753
+ var OS_ANDROID = 'Android';
754
+ var Platform$1;
755
+ (function (Platform) {
756
+ Platform["Windows"] = "Windows";
757
+ Platform["Android"] = "Android";
758
+ Platform["macOS"] = "MAC OS X";
759
+ })(Platform$1 || (Platform$1 = {}));
760
+ var UserAgent = /** @class */ (function () {
761
+ function UserAgent(_detectedPlatform, _detectedBrowser) {
762
+ this._detectedPlatform = _detectedPlatform;
763
+ this._detectedBrowser = _detectedBrowser;
764
+ }
765
+ Object.defineProperty(UserAgent.prototype, "detectedBrowser", {
766
+ get: function () {
767
+ return this._detectedBrowser;
768
+ },
769
+ enumerable: false,
770
+ configurable: true
771
+ });
772
+ Object.defineProperty(UserAgent.prototype, "detectedPlatform", {
773
+ get: function () {
774
+ return this._detectedPlatform;
775
+ },
776
+ enumerable: false,
777
+ configurable: true
778
+ });
779
+ return UserAgent;
780
+ }());
781
+ var UserAgentBuilder = /** @class */ (function () {
782
+ function UserAgentBuilder() {
783
+ this.comps = new Array();
784
+ }
785
+ UserAgentBuilder.prototype.build = function () {
786
+ // // @ts-ignore
787
+ // if(navigator.userAgentData){
788
+ // // maybe we can use this in the future
789
+ // console.info("Browser provides userAgentData:");
790
+ //
791
+ // console.info("Brands:");
792
+ // // @ts-ignore
793
+ // navigator.userAgentData.brands.forEach((br=>{
794
+ // console.info(br.brand +" "+br.version);
795
+ // }))
796
+ // // @ts-ignore
797
+ // console.info("Platform: "+navigator.userAgentData.platform);
798
+ // // @ts-ignore
799
+ // console.info("Mobile:"+navigator.userAgentData.mobile);
800
+ // // @ts-ignore
801
+ // //console.info(navigator.userAgentData.toJSON());
802
+ // }else {
803
+ // console.info("Browser does not provide userAgentData.");
804
+ // }
805
+ var ua = navigator.userAgent;
806
+ this.comps = new Array();
807
+ var pp = 0;
808
+ while (pp < ua.length) {
809
+ //parse name/version
810
+ var name = null;
811
+ var version = null;
812
+ var comment = void 0;
813
+ var blPos = ua.indexOf(' ', pp);
814
+ var prt = void 0;
815
+ if (blPos == -1) {
816
+ prt = ua.substr(pp);
817
+ pp += prt.length;
818
+ }
819
+ else {
820
+ prt = ua.substr(pp, blPos - pp);
821
+ pp = blPos + 1;
822
+ }
823
+ var sepPos = prt.indexOf('/');
824
+ if (sepPos > 0) {
825
+ name = prt.substr(0, sepPos);
826
+ version = prt.substr(sepPos + 1);
827
+ }
828
+ else {
829
+ name = prt;
830
+ }
831
+ while (ua[pp] === ' ' && pp < ua.length) {
832
+ pp++;
833
+ }
834
+ if (ua[pp] === '(') {
835
+ pp++;
836
+ var commEnd = ua.indexOf(')', pp);
837
+ comment = ua.substr(pp, commEnd - pp);
838
+ pp = commEnd + 1;
839
+ }
840
+ while (ua[pp] === ' ' && pp < ua.length) {
841
+ pp++;
842
+ }
843
+ this.comps.push(new UserAgentComponent(name, version, comment));
844
+ }
845
+ var detPlatf = null;
846
+ if (this.runsOnOS(Platform$1.Android)) {
847
+ detPlatf = Platform$1.Android;
848
+ }
849
+ else if (this.runsOnOS(Platform$1.Windows)) {
850
+ detPlatf = Platform$1.Windows;
851
+ }
852
+ else if (this.runsOnOS(Platform$1.macOS)) {
853
+ detPlatf = Platform$1.macOS;
854
+ }
855
+ var detBr = null;
856
+ if (this.matchesBrowser(Browser$1.Firefox)) {
857
+ detBr = Browser$1.Firefox;
858
+ }
859
+ else if (this.matchesBrowser(Browser$1.Chrome)) {
860
+ detBr = Browser$1.Chrome;
861
+ }
862
+ else if (this.matchesBrowser(Browser$1.Safari)) {
863
+ detBr = Browser$1.Safari;
864
+ }
865
+ this.userAgent = new UserAgent(detPlatf, detBr);
866
+ };
867
+ UserAgentBuilder.prototype.matchesBrowser = function (browserName) {
868
+ for (var ci = 0; ci < this.comps.length; ci++) {
869
+ var bn = this.comps[ci].name;
870
+ var bnRe = new RegExp(browserName, 'i');
871
+ if (bn.match(bnRe)) {
872
+ return true;
873
+ }
874
+ }
875
+ return false;
876
+ };
877
+ UserAgentBuilder.prototype.runsOnOS = function (os) {
878
+ for (var ci = 0; ci < this.comps.length; ci++) {
879
+ var cc = this.comps[ci].comment;
880
+ if (cc) {
881
+ var osRe = new RegExp(os, 'i');
882
+ if (cc.match(osRe)) {
883
+ return true;
884
+ }
885
+ }
886
+ }
887
+ return false;
888
+ };
889
+ UserAgentBuilder.userAgent = function () {
890
+ if (!this.instance) {
891
+ this.instance = new UserAgentBuilder();
892
+ }
893
+ this.instance.build();
894
+ return this.instance.userAgent;
895
+ };
896
+ return UserAgentBuilder;
729
897
  }());
898
+ UserAgentBuilder.instance = undefined;
899
+
900
+ var ConstraintType;
901
+ (function (ConstraintType) {
902
+ ConstraintType["Exact"] = "EXACT";
903
+ ConstraintType["Ideal"] = "IDEAL";
904
+ })(ConstraintType || (ConstraintType = {}));
905
+ ;
906
+ var Platform;
907
+ (function (Platform) {
908
+ Platform["Linux"] = "LINUX";
909
+ Platform["macOS"] = "MACOS";
910
+ Platform["Windows"] = "WINDOWS";
911
+ Platform["Android"] = "ANDROID";
912
+ })(Platform || (Platform = {}));
913
+ var BrowserBase;
914
+ (function (BrowserBase) {
915
+ BrowserBase["Chromium"] = "CHROMIUM";
916
+ })(BrowserBase || (BrowserBase = {}));
917
+ ;
918
+ var Browser;
919
+ (function (Browser) {
920
+ Browser["Firefox"] = "FIREFOX";
921
+ Browser["Chromium"] = "CHROMIUM";
922
+ Browser["Chrome"] = "CHROME";
923
+ Browser["Edge"] = "EDGE";
924
+ Browser["Opera"] = "OPERA";
925
+ })(Browser || (Browser = {}));
926
+ var ProjectUtil = /** @class */ (function () {
927
+ function ProjectUtil() {
928
+ }
929
+ ProjectUtil.audioChannelCount = function (project) {
930
+ var chs = ProjectUtil.DEFAULT_AUDIO_CHANNEL_COUNT;
931
+ if (project.mediaCaptureFormat) {
932
+ chs = project.mediaCaptureFormat.audioChannelCount;
933
+ }
934
+ else if (project.audioFormat) {
935
+ chs = project.audioFormat.channels;
936
+ }
937
+ return chs;
938
+ };
939
+ return ProjectUtil;
940
+ }());
941
+ ProjectUtil.DEFAULT_AUDIO_CHANNEL_COUNT = 2;
942
+
943
+ var CHROME_ACTIVATE_ECHO_CANCELLATION_WITH_AGC = false;
944
+ var DEBUG_TRACE_LEVEL = 0;
945
+ var ENABLE_AUDIO_WORKLET = true;
946
+ // Super dirty way to load this module
947
+ // Copy content of interceptor_worklet.js to this string
948
+ var awpStr = "class AudioCaptureInterceptorProcessor extends AudioWorkletProcessor{\n" +
949
+ "\n" +
950
+ " BUFFER_QUANTUMS=64;\n" +
951
+ " QUANTUM_FRAME_LEN=128;\n" +
952
+ " BUFFER_FRAME_LEN=this.QUANTUM_FRAME_LEN*this.BUFFER_QUANTUMS;\n" +
953
+ " buffer=null;\n" +
954
+ " bufferPos=0;\n" +
955
+ " bufferPosBytes=0;\n" +
956
+ " constructor() {\n" +
957
+ " super();\n" +
958
+ "\n" +
959
+ " }\n" +
960
+ "\n" +
961
+ " process(\n" +
962
+ " inputs,\n" +
963
+ " outputs,\n" +
964
+ " parameters\n" +
965
+ " ){\n" +
966
+ "\n" +
967
+ " let inputsCnt=inputs.length;\n" +
968
+ " let channelCount=0;\n" +
969
+ " let inputLen=0;\n" +
970
+ " let inputLenBytes=0;\n" +
971
+ " if(inputsCnt>0) {\n" +
972
+ " let input0 = inputs[0];\n" +
973
+ " channelCount = input0.length;\n" +
974
+ " if (channelCount > 0) {\n" +
975
+ " let input0ch0=input0[0];\n" +
976
+ " inputLen=input0ch0.length;\n" +
977
+ " inputLenBytes=input0ch0.buffer.length;\n" +
978
+ " }\n" +
979
+ " }\n" +
980
+ " if (!this.buffer || this.buffer.length < channelCount) {\n" +
981
+ " this.buffer = new Array(channelCount);\n" +
982
+ " this.bufferPos = 0\n" +
983
+ " for (let bch = 0; bch < channelCount; bch++) {\n" +
984
+ " this.buffer[bch] = new Float32Array(this.BUFFER_FRAME_LEN);\n" +
985
+ " this.bufferPos = 0;\n" +
986
+ " this.bufferPosBytes=0;\n" +
987
+ " }\n" +
988
+ " }\n" +
989
+ " let bufAvail = this.BUFFER_FRAME_LEN - this.bufferPos;\n" +
990
+ " // check if buffer has to be transferred\n" +
991
+ " if (inputLen > bufAvail) {\n" +
992
+ " let ada=new Array(channelCount);\n" +
993
+ " for (let ch = 0; ch < channelCount; ch++) {\n" +
994
+ " ada[ch]=this.buffer[ch].buffer.slice(0);\n" +
995
+ " }\n" +
996
+ " this.port.postMessage({\n" +
997
+ " data: ada,\n" +
998
+ " chs: channelCount,\n" +
999
+ " len: this.bufferPos\n" +
1000
+ " }, ada);\n" +
1001
+ " // buffer transferred, reset\n" +
1002
+ " this.bufferPos = 0;\n" +
1003
+ " this.bufferPosBytes=0;\n" +
1004
+ " }\n" +
1005
+ "\n" +
1006
+ " for(let ii=0;ii<inputsCnt;ii++) {\n" +
1007
+ " for (let ch = 0; ch < channelCount; ch++) {\n" +
1008
+ " // Mute outputs\n" +
1009
+ " //outputs[ii][ch].fill(0);\n" +
1010
+ " let chSamples = inputs[ii][ch];\n" +
1011
+ " this.buffer[ch].set(chSamples,this.bufferPos);\n" +
1012
+ " }\n" +
1013
+ " this.bufferPos+=inputLen;\n" +
1014
+ " this.bufferPosBytes+=inputLenBytes;\n" +
1015
+ " }\n" +
1016
+ " \n" +
1017
+ " return true;\n" +
1018
+ " }\n" +
1019
+ "}\n" +
1020
+ "\n" +
1021
+ "registerProcessor('capture-interceptor',AudioCaptureInterceptorProcessor);\n";
730
1022
  var AudioCapture = /** @class */ (function () {
731
1023
  function AudioCapture(context) {
1024
+ this.agcStatus = null;
1025
+ this.bufferingNode = null;
732
1026
  this.audioOutStream = null;
733
1027
  this.disconnectStreams = true;
734
1028
  this._opened = false;
@@ -783,7 +1077,7 @@
783
1077
  if (!labelsAvailable) {
784
1078
  //console.debug("Media device enumeration: No labels.")
785
1079
  if (retry) {
786
- //console.debug("Starting dummy session to request audio permissions...")
1080
+ console.info("Starting dummy session to request audio permissions...");
787
1081
  _this.dummySession().then(function (s) {
788
1082
  // and stop it immediately
789
1083
  if (s) {
@@ -848,13 +1142,14 @@
848
1142
  console.log("Audio device: Id: " + di.deviceId + " groupId: " + di.groupId + " label: " + di.label + " kind: " + di.kind);
849
1143
  }
850
1144
  };
851
- AudioCapture.prototype.open = function (channelCount, selDeviceId) {
1145
+ AudioCapture.prototype.open = function (channelCount, selDeviceId, autoGainControlConfigs) {
852
1146
  var _this = this;
853
1147
  this.context.resume().then(function () {
854
- _this._open(channelCount, selDeviceId);
1148
+ _this._open(channelCount, selDeviceId, autoGainControlConfigs);
855
1149
  });
856
1150
  };
857
- AudioCapture.prototype._open = function (channelCount, selDeviceId) {
1151
+ AudioCapture.prototype._open = function (channelCount, selDeviceId, autoGainControlConfigs) {
1152
+ var e_1, _a;
858
1153
  var _this = this;
859
1154
  this.channelCount = channelCount;
860
1155
  this.framesRecorded = 0;
@@ -871,7 +1166,58 @@
871
1166
  // TODO test if input is unprocessed
872
1167
  var msc;
873
1168
  console.info('User agent: ' + navigator.userAgent);
874
- if (navigator.userAgent.match(".*Edge.*")) {
1169
+ var ua = UserAgentBuilder.userAgent();
1170
+ // ua.components.forEach((c)=>{
1171
+ // console.info("UA_Comp: "+c.toString());
1172
+ // })
1173
+ var agcCfg = null;
1174
+ var autoGainControl = false;
1175
+ var chromeEchoCancellation = false;
1176
+ if (autoGainControlConfigs) {
1177
+ try {
1178
+ for (var autoGainControlConfigs_1 = __values(autoGainControlConfigs), autoGainControlConfigs_1_1 = autoGainControlConfigs_1.next(); !autoGainControlConfigs_1_1.done; autoGainControlConfigs_1_1 = autoGainControlConfigs_1.next()) {
1179
+ var agcc = autoGainControlConfigs_1_1.value;
1180
+ if (agcc.platform === Platform.Android && ua.detectedPlatform === Platform$1.Android) {
1181
+ agcCfg = agcc;
1182
+ break;
1183
+ }
1184
+ if (agcc.platform === Platform.Windows && ua.detectedPlatform === Platform$1.Windows) {
1185
+ agcCfg = agcc;
1186
+ break;
1187
+ }
1188
+ }
1189
+ }
1190
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1191
+ finally {
1192
+ try {
1193
+ if (autoGainControlConfigs_1_1 && !autoGainControlConfigs_1_1.done && (_a = autoGainControlConfigs_1.return)) _a.call(autoGainControlConfigs_1);
1194
+ }
1195
+ finally { if (e_1) throw e_1.error; }
1196
+ }
1197
+ if (agcCfg) {
1198
+ // TODO use EXACT/IDEAL constraint
1199
+ autoGainControl = agcCfg.value;
1200
+ if (CHROME_ACTIVATE_ECHO_CANCELLATION_WITH_AGC) {
1201
+ chromeEchoCancellation = agcCfg.value;
1202
+ }
1203
+ // TODO query real AGC status
1204
+ this.agcStatus = agcCfg.value;
1205
+ }
1206
+ else {
1207
+ this.agcStatus = false;
1208
+ }
1209
+ }
1210
+ // default
1211
+ msc = {
1212
+ audio: {
1213
+ deviceId: selDeviceId,
1214
+ echoCancellation: false,
1215
+ channelCount: channelCount,
1216
+ autoGainControl: autoGainControl
1217
+ },
1218
+ video: false
1219
+ };
1220
+ if (ua.detectedBrowser === Browser$1.Edge) {
875
1221
  // Microsoft Edge sends unmodified audio
876
1222
  // The constraint can follow the specification
877
1223
  console.info("Setting media track constraints for Microsoft Edge.");
@@ -879,12 +1225,13 @@
879
1225
  audio: {
880
1226
  deviceId: selDeviceId,
881
1227
  echoCancellation: false,
882
- channelCount: channelCount
1228
+ channelCount: channelCount,
1229
+ autoGainControl: autoGainControl
883
1230
  },
884
1231
  video: false
885
1232
  };
886
1233
  }
887
- else if (navigator.userAgent.match(".*Chrome.*")) {
1234
+ else if (ua.detectedBrowser === Browser$1.Chrome) {
888
1235
  // Google Chrome: we need to switch of each of the preprocessing units including the
889
1236
  console.info("Setting media track constraints for Google Chrome.");
890
1237
  // Chrome 60 -> 61 changed
@@ -892,47 +1239,38 @@
892
1239
  // Requires at least Chrome 61
893
1240
  msc = {
894
1241
  audio: {
895
- "deviceId": selDeviceId,
896
- "channelCount": channelCount,
897
- "echoCancellation": false,
898
- "autoGainControl": false,
899
- "googEchoCancellation": false,
900
- "googExperimentalEchoCancellation": false,
901
- "googAutoGainControl": false,
902
- "googTypingNoiseDetection": false,
903
- "googNoiseSuppression": false,
904
- "googHighpassFilter": false,
905
- "googBeamforming": false
1242
+ deviceId: selDeviceId,
1243
+ channelCount: channelCount,
1244
+ echoCancellation: { exact: chromeEchoCancellation },
1245
+ autoGainControl: { exact: autoGainControl },
1246
+ sampleSize: { min: 16 },
906
1247
  },
907
1248
  video: false,
908
1249
  };
909
1250
  }
910
- else if (navigator.userAgent.match(".*Firefox.*")) {
1251
+ else if (ua.detectedBrowser === Browser$1.Firefox) {
911
1252
  console.info("Setting media track constraints for Mozilla Firefox.");
912
1253
  // Firefox
913
1254
  msc = {
914
1255
  audio: {
915
- "deviceId": selDeviceId,
916
- "channelCount": channelCount,
917
- "echoCancellation": false,
918
- "mozEchoCancellation": false,
919
- "autoGainControl": false,
920
- "mozAutoGainControl": false,
921
- "noiseSuppression": false,
922
- "mozNoiseSuppression": false
1256
+ deviceId: selDeviceId,
1257
+ channelCount: channelCount,
1258
+ echoCancellation: false,
1259
+ autoGainControl: autoGainControl,
1260
+ noiseSuppression: false
923
1261
  },
924
1262
  video: false,
925
1263
  };
926
1264
  }
927
- else if (navigator.userAgent.match(".*Safari.*")) {
1265
+ else if (ua.detectedBrowser === Browser$1.Safari) {
928
1266
  console.info("Setting media track constraints for Safari browser.");
929
1267
  console.info("Apply workaround for Safari: Avoid disconnect of streams.");
930
1268
  this.disconnectStreams = false;
931
1269
  msc = {
932
1270
  audio: {
933
- "deviceId": selDeviceId,
934
- "channelCount": channelCount,
935
- "echoCancellation": false
1271
+ deviceId: selDeviceId,
1272
+ channelCount: channelCount,
1273
+ echoCancellation: false
936
1274
  },
937
1275
  video: false,
938
1276
  };
@@ -940,6 +1278,7 @@
940
1278
  else {
941
1279
  // TODO default constraints or error Browser not supported
942
1280
  }
1281
+ console.debug("Audio capture, AGC: " + this.agcStatus);
943
1282
  var ump = navigator.mediaDevices.getUserMedia(msc);
944
1283
  ump.then(function (s) {
945
1284
  _this.stream = s;
@@ -947,6 +1286,11 @@
947
1286
  for (var i = 0; i < aTracks.length; i++) {
948
1287
  var aTrack = aTracks[i];
949
1288
  console.info("Track audio info: id: " + aTrack.id + " kind: " + aTrack.kind + " label: \"" + aTrack.label + "\"");
1289
+ var mtrSts = aTrack.getSettings();
1290
+ console.info("Track audio settings: Ch cnt: " + mtrSts.channelCount + ", AGC: " + mtrSts.autoGainControl + ", Echo cancell.: " + mtrSts.echoCancellation);
1291
+ if (mtrSts.autoGainControl) {
1292
+ _this.agcStatus = mtrSts.autoGainControl;
1293
+ }
950
1294
  }
951
1295
  var vTracks = s.getVideoTracks();
952
1296
  for (var i = 0; i < vTracks.length; i++) {
@@ -956,6 +1300,7 @@
956
1300
  _this.mediaStream = _this.context.createMediaStreamSource(s);
957
1301
  // stream channel count ( is always 2 !)
958
1302
  var streamChannelCount = _this.mediaStream.channelCount;
1303
+ console.info("Stream channel count: " + streamChannelCount);
959
1304
  // is not set!!
960
1305
  //this.currentSampleRate = this.mediaStream.sampleRate;
961
1306
  _this.currentSampleRate = _this.context.sampleRate;
@@ -965,43 +1310,117 @@
965
1310
  }
966
1311
  // W3C -> new name is createScriptProcessor
967
1312
  //
968
- // TODO Again deprecated, but AudioWorker not yet implemented in stable releases (June 2016)
1313
+ // Again deprecated, but AudioWorker not yet implemented in stable releases (June 2016)
969
1314
  // AudioWorker is now AudioWorkletProcessor ... (May 2017)
970
1315
  // Update 12-2020:
971
1316
  // The ScriptProcessorNode Interface - DEPRECATED
972
- if (!_this.context.createScriptProcessor) {
973
- //console.debug("Audio script processor NOT implemented.")
1317
+ // Update 06-2021
1318
+ // AudioWorkletProcessor is here to stay. Web Audio API has now Recommendation status !
1319
+ if (ENABLE_AUDIO_WORKLET && _this.context.audioWorklet) {
1320
+ //const workletFileName = ('file-loader!./interceptor_worklet.js');
1321
+ //const workletFileName = 'http://localhost:4200/assets/interceptor_worklet.js';
1322
+ //console.log(awpStr);
1323
+ var audioWorkletModuleBlob = new Blob([awpStr], { type: 'text/javascript' });
1324
+ var audioWorkletModuleBlobUrl = window.URL.createObjectURL(audioWorkletModuleBlob);
1325
+ _this.context.audioWorklet.addModule(audioWorkletModuleBlobUrl).then(function () {
1326
+ var awn = new AudioWorkletNode(_this.context, 'capture-interceptor');
1327
+ awn.onprocessorerror = function (ev) {
1328
+ var msg = 'Unknwon error';
1329
+ if (ev instanceof ErrorEvent) {
1330
+ msg = ev.message;
1331
+ }
1332
+ console.error("Capture audio worklet error: " + msg);
1333
+ if (_this.listener) {
1334
+ _this.listener.error(msg);
1335
+ }
1336
+ };
1337
+ var awnPt = awn.port;
1338
+ if (awnPt) {
1339
+ awnPt.onmessage = function (ev) {
1340
+ if (_this.capturing) {
1341
+ var dt = ev.data;
1342
+ var chs = dt.chs;
1343
+ var adaLen = dt.data.length;
1344
+ if (DEBUG_TRACE_LEVEL > 8) {
1345
+ console.debug('Received data from worklet: ' + chs + ' ' + dt.len + ' Data chs: ' + adaLen);
1346
+ }
1347
+ //let chunkLen = adaLen / chs;
1348
+ var chunkLen = adaLen;
1349
+ var chunk = new Array(chs);
1350
+ for (var ch = 0; ch < chs; ch++) {
1351
+ if (_this.data && _this.data[ch]) {
1352
+ var adaPos = ch * chunkLen;
1353
+ if (dt.data[ch]) {
1354
+ var fa = new Float32Array(dt.data[ch]);
1355
+ _this.data[ch].push(fa);
1356
+ chunk[ch] = fa;
1357
+ // Use samples of channel 0 to count frames (samples)
1358
+ if (ch == 0) {
1359
+ _this.framesRecorded += fa.length;
1360
+ }
1361
+ }
1362
+ else {
1363
+ if (DEBUG_TRACE_LEVEL > 8) {
1364
+ console.debug('Channel ' + ch + ' data not set!!');
1365
+ }
1366
+ }
1367
+ }
1368
+ }
1369
+ if (_this.audioOutStream) {
1370
+ _this.audioOutStream.write(chunk);
1371
+ }
1372
+ }
1373
+ };
1374
+ }
1375
+ _this.bufferingNode = awn;
1376
+ _this._opened = true;
1377
+ if (_this.listener) {
1378
+ _this.listener.opened();
1379
+ }
1380
+ }).catch(function (error) {
1381
+ console.log('Could not add module ' + error);
1382
+ });
974
1383
  }
975
- else {
976
- // The ScriptProcessorNode Interface - DEPRECATED
977
- //console.debug("Audio script processor implemented!!");
1384
+ else if (_this.context.createScriptProcessor) {
1385
+ // The ScriptProcessorNode Interface - DEPRECATED Only as fallback
978
1386
  // TODO should we use streamChannelCount or channelCount here ?
979
- _this.bufferingNode = _this.context.createScriptProcessor(AudioCapture.BUFFER_SIZE, streamChannelCount, streamChannelCount);
1387
+ var scriptProcessorNode = _this.context.createScriptProcessor(AudioCapture.BUFFER_SIZE, streamChannelCount, streamChannelCount);
1388
+ _this.bufferingNode = scriptProcessorNode;
980
1389
  var c_1 = 0;
981
- _this.bufferingNode.onaudioprocess = function (e) {
982
- if (_this.capturing) {
983
- // TODO use chCnt
984
- var inBuffer = e.inputBuffer;
985
- var duration = inBuffer.duration;
986
- // only process requested count of channels
987
- var currentBuffers = new Array(channelCount);
988
- for (var ch = 0; ch < channelCount; ch++) {
989
- var chSamples = inBuffer.getChannelData(ch);
990
- var chSamplesCopy = chSamples.slice(0);
991
- currentBuffers[ch] = chSamplesCopy.slice(0);
992
- _this.data[ch].push(chSamplesCopy);
993
- _this.framesRecorded += chSamplesCopy.length;
994
- }
995
- c_1++;
996
- if (_this.audioOutStream) {
997
- _this.audioOutStream.write(currentBuffers);
1390
+ if (scriptProcessorNode.onaudioprocess) {
1391
+ scriptProcessorNode.onaudioprocess = function (e) {
1392
+ if (_this.capturing) {
1393
+ var inBuffer = e.inputBuffer;
1394
+ var duration = inBuffer.duration;
1395
+ // only process requested count of channels
1396
+ var currentBuffers = new Array(channelCount);
1397
+ for (var ch = 0; ch < channelCount; ch++) {
1398
+ var chSamples = inBuffer.getChannelData(ch);
1399
+ var chSamplesCopy = chSamples.slice(0);
1400
+ currentBuffers[ch] = chSamplesCopy.slice(0);
1401
+ _this.data[ch].push(chSamplesCopy);
1402
+ if (DEBUG_TRACE_LEVEL > 8) {
1403
+ console.debug("Process " + chSamplesCopy.length + " samples.");
1404
+ }
1405
+ _this.framesRecorded += chSamplesCopy.length;
1406
+ }
1407
+ c_1++;
1408
+ if (_this.audioOutStream) {
1409
+ _this.audioOutStream.write(currentBuffers);
1410
+ }
998
1411
  }
1412
+ };
1413
+ _this._opened = true;
1414
+ if (_this.listener) {
1415
+ _this.listener.opened();
999
1416
  }
1000
- };
1417
+ }
1418
+ else {
1419
+ _this.listener.error('Browser does not support audio processing (ScriptProcessor.onaudioprocess method not found)!');
1420
+ }
1001
1421
  }
1002
- _this._opened = true;
1003
- if (_this.listener) {
1004
- _this.listener.opened();
1422
+ else {
1423
+ _this.listener.error('Browser does not support audio processing (neither AudioWorkletProcessor nor ScriptProcessor)!');
1005
1424
  }
1006
1425
  }, function (e) {
1007
1426
  console.error(e + " Error name: " + e.name);
@@ -1028,14 +1447,16 @@
1028
1447
  this.audioOutStream.nextStream();
1029
1448
  }
1030
1449
  this.capturing = true;
1031
- this.mediaStream.connect(this.bufferingNode);
1032
- this.bufferingNode.connect(this.context.destination);
1450
+ if (this.bufferingNode) {
1451
+ this.mediaStream.connect(this.bufferingNode);
1452
+ this.bufferingNode.connect(this.context.destination);
1453
+ }
1033
1454
  if (this.listener) {
1034
1455
  this.listener.started();
1035
1456
  }
1036
1457
  };
1037
1458
  AudioCapture.prototype.stop = function () {
1038
- if (this.disconnectStreams) {
1459
+ if (this.disconnectStreams && this.bufferingNode) {
1039
1460
  this.mediaStream.disconnect(this.bufferingNode);
1040
1461
  this.bufferingNode.disconnect(this.context.destination);
1041
1462
  }
@@ -1061,7 +1482,7 @@
1061
1482
  this._opened = false;
1062
1483
  };
1063
1484
  AudioCapture.prototype.audioBuffer = function () {
1064
- var e_1, _a, e_2, _b;
1485
+ var e_2, _a, e_3, _b;
1065
1486
  var frameLen = 0;
1066
1487
  var ch0Data = this.data[0];
1067
1488
  try {
@@ -1070,31 +1491,31 @@
1070
1491
  frameLen += ch0Chk.length;
1071
1492
  }
1072
1493
  }
1073
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1494
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
1074
1495
  finally {
1075
1496
  try {
1076
1497
  if (ch0Data_1_1 && !ch0Data_1_1.done && (_a = ch0Data_1.return)) _a.call(ch0Data_1);
1077
1498
  }
1078
- finally { if (e_1) throw e_1.error; }
1499
+ finally { if (e_2) throw e_2.error; }
1079
1500
  }
1080
1501
  var ab = this.context.createBuffer(this.channelCount, frameLen, this.context.sampleRate);
1081
1502
  for (var ch = 0; ch < this.channelCount; ch++) {
1082
1503
  var chD = ab.getChannelData(ch);
1083
1504
  var pos = 0;
1084
1505
  try {
1085
- for (var _c = (e_2 = void 0, __values(this.data[ch])), _d = _c.next(); !_d.done; _d = _c.next()) {
1506
+ for (var _c = (e_3 = void 0, __values(this.data[ch])), _d = _c.next(); !_d.done; _d = _c.next()) {
1086
1507
  var chChk = _d.value;
1087
1508
  var bufLen = chChk.length;
1088
1509
  chD.set(chChk, pos);
1089
1510
  pos += bufLen;
1090
1511
  }
1091
1512
  }
1092
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
1513
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
1093
1514
  finally {
1094
1515
  try {
1095
1516
  if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
1096
1517
  }
1097
- finally { if (e_2) throw e_2.error; }
1518
+ finally { if (e_3) throw e_3.error; }
1098
1519
  }
1099
1520
  }
1100
1521
  return ab;
@@ -2283,6 +2704,8 @@
2283
2704
  this.peakDbLevelStr = "-___ dB";
2284
2705
  this.peakDbLvl = MIN_DB_LEVEL;
2285
2706
  this._displayLevelInfos = null;
2707
+ this._agc = undefined;
2708
+ this.agcString = 'n/a';
2286
2709
  this.onShowRecordingDetails = new i0.EventEmitter();
2287
2710
  this.onDownloadRecording = new i0.EventEmitter();
2288
2711
  this.playStartEnabled = false;
@@ -2291,6 +2714,24 @@
2291
2714
  this.destroyed = false;
2292
2715
  this.warnDbLevel = DEFAULT_WARN_DB_LEVEL;
2293
2716
  }
2717
+ Object.defineProperty(LevelBarDisplay.prototype, "agc", {
2718
+ set: function (agc) {
2719
+ this._agc = agc;
2720
+ if (this._agc === undefined || this._agc === null) {
2721
+ this.agcString = 'n/a';
2722
+ }
2723
+ else {
2724
+ if (this._agc === true) {
2725
+ this.agcString = 'On';
2726
+ }
2727
+ else {
2728
+ this.agcString = 'Off';
2729
+ }
2730
+ }
2731
+ },
2732
+ enumerable: false,
2733
+ configurable: true
2734
+ });
2294
2735
  LevelBarDisplay.prototype.ngOnDestroy = function () {
2295
2736
  this.destroyed = true;
2296
2737
  };
@@ -2357,12 +2798,12 @@
2357
2798
  return LevelBarDisplay;
2358
2799
  }());
2359
2800
  LevelBarDisplay.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.10", ngImport: i0__namespace, type: LevelBarDisplay, deps: [{ token: i0__namespace.ElementRef }, { token: i0__namespace.ChangeDetectorRef }], target: i0__namespace.ɵɵFactoryTarget.Component });
2360
- LevelBarDisplay.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.10", type: LevelBarDisplay, selector: "spr-recordingitemdisplay", inputs: { streamingMode: "streamingMode", audioSignalCollapsed: "audioSignalCollapsed", enableDownload: "enableDownload", playStartAction: "playStartAction", playStopAction: "playStopAction", displayAudioBuffer: "displayAudioBuffer", displayLevelInfos: "displayLevelInfos" }, outputs: { onShowRecordingDetails: "onShowRecordingDetails", onDownloadRecording: "onDownloadRecording" }, viewQueries: [{ propertyName: "liveLevel", first: true, predicate: LevelBar, descendants: true, static: true }], ngImport: i0__namespace, template: "\n <audio-levelbar [streamingMode]=\"streamingMode\" [displayLevelInfos]=\"_displayLevelInfos\"></audio-levelbar>\n <button matTooltip=\"Start playback\" (click)=\"playStartAction?.perform()\"\n [disabled]=\"playStartAction?.disabled\"\n [style.color]=\"playStartAction?.disabled ? 'grey' : 'green'\">\n <mat-icon>play_arrow</mat-icon>\n </button>\n <button matTooltip=\"Stop playback\" (click)=\"playStopAction?.perform()\"\n [disabled]=\"playStopAction?.disabled\"\n [style.color]=\"playStopAction?.disabled ? 'grey' : 'yellow'\">\n <mat-icon>stop</mat-icon>\n </button>\n <button matTooltip=\"Toggle detailed audio display\" [disabled]=\"displayAudioBuffer==null\"\n (click)=\"showRecordingDetails()\">\n <mat-icon>{{(audioSignalCollapsed) ? \"expand_less\" : \"expand_more\"}}</mat-icon>\n </button>\n <button matTooltip=\"Download current recording\" *ngIf=\"enableDownload\" [disabled]=\"displayAudioBuffer==null\"\n (click)=\"downloadRecording()\">\n <mat-icon>file_download</mat-icon>\n </button>\n <div style=\"min-width: 14ch;padding:2px\"><table border=\"0\"><tr><td>Peak:</td><td><span matTooltip=\"Peak level\"\n [style.color]=\"(peakDbLvl > warnDbLevel)?'red':'black'\">{{peakDbLvl | number:'1.1-1'}} dB </span></td></tr></table></div>\n ", isInline: true, styles: [":host {\n flex: 0; /* only required vertical space */\n width: 100%;\n background: darkgray;\n padding: 4px;\n box-sizing: border-box;\n height: 100px;\n min-height: 100px;\n display: flex; /* flex container: left level bar, right decimal peak level value */\n flex-direction: row;\n flex-wrap: nowrap; /* wrap could completely destroy the layout */\n }", "audio-levelbar {\n flex: 1;\n box-sizing: border-box;\n }", "span {\n flex: 0;\n font-weight: bold;\n display: inline-block;\n white-space: nowrap;\n box-sizing: border-box;\n }"], components: [{ type: LevelBar, selector: "audio-levelbar", inputs: ["streamingMode", "displayLevelInfos"] }, { type: i2__namespace.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i3__namespace.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i4__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "number": i4__namespace.DecimalPipe } });
2801
+ LevelBarDisplay.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.10", type: LevelBarDisplay, selector: "spr-recordingitemdisplay", inputs: { streamingMode: "streamingMode", audioSignalCollapsed: "audioSignalCollapsed", enableDownload: "enableDownload", agc: "agc", playStartAction: "playStartAction", playStopAction: "playStopAction", displayAudioBuffer: "displayAudioBuffer", displayLevelInfos: "displayLevelInfos" }, outputs: { onShowRecordingDetails: "onShowRecordingDetails", onDownloadRecording: "onDownloadRecording" }, viewQueries: [{ propertyName: "liveLevel", first: true, predicate: LevelBar, descendants: true, static: true }], ngImport: i0__namespace, template: "\n <audio-levelbar [streamingMode]=\"streamingMode\" [displayLevelInfos]=\"_displayLevelInfos\"></audio-levelbar>\n <button matTooltip=\"Start playback\" (click)=\"playStartAction?.perform()\"\n [disabled]=\"playStartAction?.disabled\"\n [style.color]=\"playStartAction?.disabled ? 'grey' : 'green'\">\n <mat-icon>play_arrow</mat-icon>\n </button>\n <button matTooltip=\"Stop playback\" (click)=\"playStopAction?.perform()\"\n [disabled]=\"playStopAction?.disabled\"\n [style.color]=\"playStopAction?.disabled ? 'grey' : 'yellow'\">\n <mat-icon>stop</mat-icon>\n </button>\n <button matTooltip=\"Toggle detailed audio display\" [disabled]=\"displayAudioBuffer==null\"\n (click)=\"showRecordingDetails()\">\n <mat-icon>{{(audioSignalCollapsed) ? \"expand_less\" : \"expand_more\"}}</mat-icon>\n </button>\n <button matTooltip=\"Download current recording\" *ngIf=\"enableDownload\" [disabled]=\"displayAudioBuffer==null\"\n (click)=\"downloadRecording()\">\n <mat-icon>file_download</mat-icon>\n </button>\n <div style=\"min-width: 14ch;padding:2px\"><table border=\"0\"><tr><td>Peak:</td><td><span matTooltip=\"Peak level\"\n [style.color]=\"(peakDbLvl > warnDbLevel)?'red':'black'\">{{peakDbLvl | number:'1.1-1'}} dB </span></td></tr>\n <tr *ngIf=\"_agc\"><td>AGC:</td><td><span matTooltip=\"Auto gain control\">{{agcString}}</span></td></tr></table></div>\n ", isInline: true, styles: [":host {\n flex: 0; /* only required vertical space */\n width: 100%;\n background: darkgray;\n padding: 4px;\n box-sizing: border-box;\n height: 100px;\n min-height: 100px;\n display: flex; /* flex container: left level bar, right decimal peak level value */\n flex-direction: row;\n flex-wrap: nowrap; /* wrap could completely destroy the layout */\n }", "audio-levelbar {\n flex: 1;\n box-sizing: border-box;\n }", "span {\n flex: 0;\n font-weight: bold;\n display: inline-block;\n white-space: nowrap;\n box-sizing: border-box;\n }"], components: [{ type: LevelBar, selector: "audio-levelbar", inputs: ["streamingMode", "displayLevelInfos"] }, { type: i2__namespace.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i3__namespace.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i4__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "number": i4__namespace.DecimalPipe } });
2361
2802
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.10", ngImport: i0__namespace, type: LevelBarDisplay, decorators: [{
2362
2803
  type: i0.Component,
2363
2804
  args: [{
2364
2805
  selector: 'spr-recordingitemdisplay',
2365
- template: "\n <audio-levelbar [streamingMode]=\"streamingMode\" [displayLevelInfos]=\"_displayLevelInfos\"></audio-levelbar>\n <button matTooltip=\"Start playback\" (click)=\"playStartAction?.perform()\"\n [disabled]=\"playStartAction?.disabled\"\n [style.color]=\"playStartAction?.disabled ? 'grey' : 'green'\">\n <mat-icon>play_arrow</mat-icon>\n </button>\n <button matTooltip=\"Stop playback\" (click)=\"playStopAction?.perform()\"\n [disabled]=\"playStopAction?.disabled\"\n [style.color]=\"playStopAction?.disabled ? 'grey' : 'yellow'\">\n <mat-icon>stop</mat-icon>\n </button>\n <button matTooltip=\"Toggle detailed audio display\" [disabled]=\"displayAudioBuffer==null\"\n (click)=\"showRecordingDetails()\">\n <mat-icon>{{(audioSignalCollapsed) ? \"expand_less\" : \"expand_more\"}}</mat-icon>\n </button>\n <button matTooltip=\"Download current recording\" *ngIf=\"enableDownload\" [disabled]=\"displayAudioBuffer==null\"\n (click)=\"downloadRecording()\">\n <mat-icon>file_download</mat-icon>\n </button>\n <div style=\"min-width: 14ch;padding:2px\"><table border=\"0\"><tr><td>Peak:</td><td><span matTooltip=\"Peak level\"\n [style.color]=\"(peakDbLvl > warnDbLevel)?'red':'black'\">{{peakDbLvl | number:'1.1-1'}} dB </span></td></tr></table></div>\n ",
2806
+ template: "\n <audio-levelbar [streamingMode]=\"streamingMode\" [displayLevelInfos]=\"_displayLevelInfos\"></audio-levelbar>\n <button matTooltip=\"Start playback\" (click)=\"playStartAction?.perform()\"\n [disabled]=\"playStartAction?.disabled\"\n [style.color]=\"playStartAction?.disabled ? 'grey' : 'green'\">\n <mat-icon>play_arrow</mat-icon>\n </button>\n <button matTooltip=\"Stop playback\" (click)=\"playStopAction?.perform()\"\n [disabled]=\"playStopAction?.disabled\"\n [style.color]=\"playStopAction?.disabled ? 'grey' : 'yellow'\">\n <mat-icon>stop</mat-icon>\n </button>\n <button matTooltip=\"Toggle detailed audio display\" [disabled]=\"displayAudioBuffer==null\"\n (click)=\"showRecordingDetails()\">\n <mat-icon>{{(audioSignalCollapsed) ? \"expand_less\" : \"expand_more\"}}</mat-icon>\n </button>\n <button matTooltip=\"Download current recording\" *ngIf=\"enableDownload\" [disabled]=\"displayAudioBuffer==null\"\n (click)=\"downloadRecording()\">\n <mat-icon>file_download</mat-icon>\n </button>\n <div style=\"min-width: 14ch;padding:2px\"><table border=\"0\"><tr><td>Peak:</td><td><span matTooltip=\"Peak level\"\n [style.color]=\"(peakDbLvl > warnDbLevel)?'red':'black'\">{{peakDbLvl | number:'1.1-1'}} dB </span></td></tr>\n <tr *ngIf=\"_agc\"><td>AGC:</td><td><span matTooltip=\"Auto gain control\">{{agcString}}</span></td></tr></table></div>\n ",
2366
2807
  styles: [":host {\n flex: 0; /* only required vertical space */\n width: 100%;\n background: darkgray;\n padding: 4px;\n box-sizing: border-box;\n height: 100px;\n min-height: 100px;\n display: flex; /* flex container: left level bar, right decimal peak level value */\n flex-direction: row;\n flex-wrap: nowrap; /* wrap could completely destroy the layout */\n }", "audio-levelbar {\n flex: 1;\n box-sizing: border-box;\n }", "span {\n flex: 0;\n font-weight: bold;\n display: inline-block;\n white-space: nowrap;\n box-sizing: border-box;\n }"]
2367
2808
  }]
2368
2809
  }], ctorParameters: function () { return [{ type: i0__namespace.ElementRef }, { type: i0__namespace.ChangeDetectorRef }]; }, propDecorators: { liveLevel: [{
@@ -2374,6 +2815,8 @@
2374
2815
  type: i0.Input
2375
2816
  }], enableDownload: [{
2376
2817
  type: i0.Input
2818
+ }], agc: [{
2819
+ type: i0.Input
2377
2820
  }], onShowRecordingDetails: [{
2378
2821
  type: i0.Output
2379
2822
  }], onDownloadRecording: [{
@@ -6118,12 +6561,13 @@
6118
6561
  toFill = avail;
6119
6562
  }
6120
6563
  var sliceEnd = copied + toFill;
6121
- for (var ch = 0; ch < this._channels; ch++) {
6122
- var cpPrt = buffers[ch].slice(copied, sliceEnd);
6123
- var prtLen = cpPrt.length;
6124
- var buf = this.bufs[ch];
6125
- var bufLen = buf.length;
6126
- buf.set(cpPrt, this.filled);
6564
+ // Firefox on Android sends only the first channel
6565
+ for (var ch = 0; ch < buffersLen; ch++) {
6566
+ if (buffers[ch]) {
6567
+ var cpPrt = buffers[ch].slice(copied, sliceEnd);
6568
+ var buf = this.bufs[ch];
6569
+ buf.set(cpPrt, this.filled);
6570
+ }
6127
6571
  }
6128
6572
  copied += toFill;
6129
6573
  avail -= toFill;
@@ -6759,6 +7203,7 @@
6759
7203
  type: i0.Input
6760
7204
  }] } });
6761
7205
 
7206
+ var FORCE_REQUEST_AUDIO_PERMISSIONS = false;
6762
7207
  var RECFILE_API_CTX = 'recfile';
6763
7208
  var MAX_RECORDING_TIME_MS = 1000 * 60 * 60 * 60; // 1 hour
6764
7209
  var DEFAULT_PRE_REC_DELAY = 1000;
@@ -6810,6 +7255,9 @@
6810
7255
  this.selCaptureDeviceId = null;
6811
7256
  this.levelMeasure = new LevelMeasure();
6812
7257
  this.streamLevelMeasure = new StreamLevelMeasure();
7258
+ this.userAgent = UserAgentBuilder.userAgent();
7259
+ console.debug("Detected platform: " + this.userAgent.detectedPlatform);
7260
+ console.debug("Detected browser: " + this.userAgent.detectedBrowser);
6813
7261
  if (this.config && this.config.enableUploadRecordings !== undefined) {
6814
7262
  this.enableUploadRecordings = this.config.enableUploadRecordings;
6815
7263
  }
@@ -6994,6 +7442,13 @@
6994
7442
  enumerable: false,
6995
7443
  configurable: true
6996
7444
  });
7445
+ Object.defineProperty(SessionManager.prototype, "autoGainControlConfigs", {
7446
+ set: function (autoGainControlConfigs) {
7447
+ this._autoGainControlConfigs = autoGainControlConfigs;
7448
+ },
7449
+ enumerable: false,
7450
+ configurable: true
7451
+ });
6997
7452
  SessionManager.prototype.update = function (e) {
6998
7453
  if (e.type == exports.EventType.STARTED) {
6999
7454
  this.playStartAction.disabled = true;
@@ -7076,7 +7531,7 @@
7076
7531
  else {
7077
7532
  console.log("Open session with default audio device for " + this._channelCount + " channels");
7078
7533
  }
7079
- this.ac.open(this._channelCount, this._selectedDeviceId);
7534
+ this.ac.open(this._channelCount, this._selectedDeviceId, this._autoGainControlConfigs);
7080
7535
  }
7081
7536
  else {
7082
7537
  this.ac.start();
@@ -7328,9 +7783,22 @@
7328
7783
  this.sessionService.patchSessionObserver(this._session, body).subscribe();
7329
7784
  }
7330
7785
  }
7786
+ // Check browser compatibility
7787
+ if (this.userAgent.detectedBrowser === Browser$1.Safari && this._channelCount > 1) {
7788
+ var eMsg = "Error: Safari browser does not support stereo recordings.";
7789
+ console.error(eMsg);
7790
+ this.dialog.open(MessageDialog, {
7791
+ data: {
7792
+ type: 'error',
7793
+ title: 'Browser not supported',
7794
+ msg: eMsg,
7795
+ advice: "Please use a supported browser, e.g. Mozilla Firefox."
7796
+ }
7797
+ });
7798
+ }
7331
7799
  //console.log("Session ID: "+this._session.session+ " status: "+this._session.status)
7332
7800
  this._selectedDeviceId = undefined;
7333
- if (!this.readonly && this.ac) {
7801
+ if (!this.readonly && this.ac && (FORCE_REQUEST_AUDIO_PERMISSIONS || (this._audioDevices && this._audioDevices.length > 0))) {
7334
7802
  this.statusMsg = 'Requesting audio permissions...';
7335
7803
  this.statusAlertType = 'info';
7336
7804
  this.ac.deviceInfos(function (mdis) {
@@ -7447,6 +7915,7 @@
7447
7915
  }
7448
7916
  });
7449
7917
  }
7918
+ // Safari does not list playback devices
7450
7919
  if (!audioPlayDeviceAvail) {
7451
7920
  // Firefox does not enumerate audiooutput devices
7452
7921
  // Do not show this warning, because it would always appear on Firefox
@@ -7454,7 +7923,8 @@
7454
7923
  // It is already implemneted but kept behind a preference setting https://bugzilla.mozilla.org/show_bug.cgi?id=1152401
7455
7924
  // Output devices are listed if about:config media.setsinkid.enabled=true
7456
7925
  // but default setting is false
7457
- if (!navigator.userAgent.match(".*Firefox.*")) {
7926
+ // Same problem with Safari
7927
+ if (!(_this.userAgent.detectedBrowser === Browser$1.Safari || _this.userAgent.detectedBrowser === Browser$1.Firefox)) {
7458
7928
  // no device found
7459
7929
  _this.statusMsg = 'WARNING: No audio playback device available!';
7460
7930
  _this.statusAlertType = 'warn';
@@ -7865,13 +8335,13 @@
7865
8335
  return SessionManager;
7866
8336
  }());
7867
8337
  SessionManager.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.10", ngImport: i0__namespace, type: SessionManager, deps: [{ token: i0__namespace.ChangeDetectorRef }, { token: i0__namespace.Renderer2 }, { token: i1__namespace$3.MatDialog }, { token: SessionService }, { token: RecordingService }, { token: SpeechRecorderUploader }, { token: SPEECHRECORDER_CONFIG }], target: i0__namespace.ɵɵFactoryTarget.Component });
7868
- SessionManager.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.10", type: SessionManager, selector: "app-sprrecordingsession", inputs: { projectName: "projectName", dataSaved: "dataSaved" }, host: { listeners: { "window:keypress": "onKeyPress($event)", "window:keydown": "onKeyDown($event)" } }, providers: [SessionService], viewQueries: [{ propertyName: "prompting", first: true, predicate: Prompting, descendants: true, static: true }, { propertyName: "liveLevelDisplay", first: true, predicate: LevelBarDisplay, descendants: true, static: true }], ngImport: i0__namespace, template: "\n <app-warningbar [show]=\"isTestSession()\" warningText=\"Test recording only!\"></app-warningbar>\n <app-warningbar [show]=\"isDefaultAudioTestSession()\" warningText=\"This test uses default audio device! Regular sessions may require a particular audio device (microphone)!\"></app-warningbar>\n <app-sprprompting [projectName]=\"projectName\"\n [startStopSignalState]=\"startStopSignalState\" [promptItem]=\"promptItem\" [showPrompt]=\"showPrompt\"\n [items]=\"items\"\n [transportActions]=\"transportActions\"\n [selectedItemIdx]=\"promptIndex\" (onItemSelect)=\"itemSelect($event)\" (onNextItem)=\"nextItem()\" (onPrevItem)=\"prevItem()\"\n [audioSignalCollapsed]=\"audioSignalCollapsed\" [displayAudioClip]=\"displayAudioClip\"\n [playStartAction]=\"controlAudioPlayer?.startAction\"\n [playSelectionAction]=\"controlAudioPlayer?.startSelectionAction\"\n [autoPlayOnSelectToggleAction]=\"controlAudioPlayer?.autoPlayOnSelectToggleAction\"\n [playStopAction]=\"controlAudioPlayer?.stopAction\">\n\n </app-sprprompting>\n <mat-progress-bar [value]=\"progressPercentValue()\" fxShow=\"false\" fxShow.xs=\"true\" ></mat-progress-bar>\n\n <spr-recordingitemdisplay #levelbardisplay\n [playStartAction]=\"controlAudioPlayer?.startAction\"\n [playStopAction]=\"controlAudioPlayer?.stopAction\"\n [streamingMode]=\"isRecording()\"\n [displayLevelInfos]=\"displayLevelInfos\"\n [displayAudioBuffer]=\"displayAudioClip?.buffer\" [audioSignalCollapsed]=\"audioSignalCollapsed\"\n (onShowRecordingDetails)=\"audioSignalCollapsed=!audioSignalCollapsed\"\n (onDownloadRecording)=\"downloadRecording()\"\n [enableDownload]=\"enableDownloadRecordings\"></spr-recordingitemdisplay>\n <app-sprcontrolpanel [enableUploadRecordings]=\"enableUploadRecordings\" [readonly]=\"readonly\" [currentRecording]=\"displayAudioClip?.buffer\"\n [transportActions]=\"transportActions\" [statusMsg]=\"statusMsg\" [statusWaiting]=\"statusWaiting\"\n [statusAlertType]=\"statusAlertType\" [uploadProgress]=\"uploadProgress\"\n [uploadStatus]=\"uploadStatus\" [ready]=\"dataSaved && !isActive()\" [processing]=\"processingRecording\" [navigationEnabled]=\"items==null || items.length>1\"></app-sprcontrolpanel>\n\n ", isInline: true, styles: [":host {\n flex: 2;\n background: lightgrey;\n display: flex; /* Vertical flex container: Bottom transport panel, above prompting panel */\n flex-direction: column;\n margin: 0;\n padding: 0;\n min-height: 0px;\n\n /* Prevents horizontal scroll bar on swipe right */\n overflow: hidden;\n }"], components: [{ type: WarningBar, selector: "app-warningbar", inputs: ["warningText", "show"] }, { type: Prompting, selector: "app-sprprompting", inputs: ["projectName", "startStopSignalState", "promptItem", "showPrompt", "items", "selectedItemIdx", "transportActions", "enableDownload", "audioSignalCollapsed", "displayAudioClip", "playStartAction", "playSelectionAction", "autoPlayOnSelectToggleAction", "playStopAction"], outputs: ["onItemSelect", "onNextItem", "onPrevItem"] }, { type: i7__namespace.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "mode", "value", "bufferValue"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { type: LevelBarDisplay, selector: "spr-recordingitemdisplay", inputs: ["streamingMode", "audioSignalCollapsed", "enableDownload", "playStartAction", "playStopAction", "displayAudioBuffer", "displayLevelInfos"], outputs: ["onShowRecordingDetails", "onDownloadRecording"] }, { type: ControlPanel, selector: "app-sprcontrolpanel", inputs: ["readonly", "transportActions", "processing", "statusMsg", "statusAlertType", "statusWaiting", "uploadStatus", "uploadProgress", "currentRecording", "enableUploadRecordings", "navigationEnabled", "ready"] }], directives: [{ type: i6__namespace.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }] });
8338
+ SessionManager.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.10", type: SessionManager, selector: "app-sprrecordingsession", inputs: { projectName: "projectName", dataSaved: "dataSaved" }, host: { listeners: { "window:keypress": "onKeyPress($event)", "window:keydown": "onKeyDown($event)" } }, providers: [SessionService], viewQueries: [{ propertyName: "prompting", first: true, predicate: Prompting, descendants: true, static: true }, { propertyName: "liveLevelDisplay", first: true, predicate: LevelBarDisplay, descendants: true, static: true }], ngImport: i0__namespace, template: "\n <app-warningbar [show]=\"isTestSession()\" warningText=\"Test recording only!\"></app-warningbar>\n <app-warningbar [show]=\"isDefaultAudioTestSession()\" warningText=\"This test uses default audio device! Regular sessions may require a particular audio device (microphone)!\"></app-warningbar>\n <app-sprprompting [projectName]=\"projectName\"\n [startStopSignalState]=\"startStopSignalState\" [promptItem]=\"promptItem\" [showPrompt]=\"showPrompt\"\n [items]=\"items\"\n [transportActions]=\"transportActions\"\n [selectedItemIdx]=\"promptIndex\" (onItemSelect)=\"itemSelect($event)\" (onNextItem)=\"nextItem()\" (onPrevItem)=\"prevItem()\"\n [audioSignalCollapsed]=\"audioSignalCollapsed\" [displayAudioClip]=\"displayAudioClip\"\n [playStartAction]=\"controlAudioPlayer?.startAction\"\n [playSelectionAction]=\"controlAudioPlayer?.startSelectionAction\"\n [autoPlayOnSelectToggleAction]=\"controlAudioPlayer?.autoPlayOnSelectToggleAction\"\n [playStopAction]=\"controlAudioPlayer?.stopAction\">\n\n </app-sprprompting>\n <mat-progress-bar [value]=\"progressPercentValue()\" fxShow=\"false\" fxShow.xs=\"true\" ></mat-progress-bar>\n\n <spr-recordingitemdisplay #levelbardisplay\n [playStartAction]=\"controlAudioPlayer?.startAction\"\n [playStopAction]=\"controlAudioPlayer?.stopAction\"\n [streamingMode]=\"isRecording()\"\n [displayLevelInfos]=\"displayLevelInfos\"\n [displayAudioBuffer]=\"displayAudioClip?.buffer\"\n [agc]=\"this.ac?.agcStatus\"\n [audioSignalCollapsed]=\"audioSignalCollapsed\"\n (onShowRecordingDetails)=\"audioSignalCollapsed=!audioSignalCollapsed\"\n (onDownloadRecording)=\"downloadRecording()\"\n [enableDownload]=\"enableDownloadRecordings\"></spr-recordingitemdisplay>\n <app-sprcontrolpanel [enableUploadRecordings]=\"enableUploadRecordings\" [readonly]=\"readonly\" [currentRecording]=\"displayAudioClip?.buffer\"\n [transportActions]=\"transportActions\" [statusMsg]=\"statusMsg\" [statusWaiting]=\"statusWaiting\"\n [statusAlertType]=\"statusAlertType\" [uploadProgress]=\"uploadProgress\"\n [uploadStatus]=\"uploadStatus\" [ready]=\"dataSaved && !isActive()\" [processing]=\"processingRecording\" [navigationEnabled]=\"items==null || items.length>1\"></app-sprcontrolpanel>\n\n ", isInline: true, styles: [":host {\n flex: 2;\n background: lightgrey;\n display: flex; /* Vertical flex container: Bottom transport panel, above prompting panel */\n flex-direction: column;\n margin: 0;\n padding: 0;\n min-height: 0px;\n\n /* Prevents horizontal scroll bar on swipe right */\n overflow: hidden;\n }"], components: [{ type: WarningBar, selector: "app-warningbar", inputs: ["warningText", "show"] }, { type: Prompting, selector: "app-sprprompting", inputs: ["projectName", "startStopSignalState", "promptItem", "showPrompt", "items", "selectedItemIdx", "transportActions", "enableDownload", "audioSignalCollapsed", "displayAudioClip", "playStartAction", "playSelectionAction", "autoPlayOnSelectToggleAction", "playStopAction"], outputs: ["onItemSelect", "onNextItem", "onPrevItem"] }, { type: i7__namespace.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "mode", "value", "bufferValue"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { type: LevelBarDisplay, selector: "spr-recordingitemdisplay", inputs: ["streamingMode", "audioSignalCollapsed", "enableDownload", "agc", "playStartAction", "playStopAction", "displayAudioBuffer", "displayLevelInfos"], outputs: ["onShowRecordingDetails", "onDownloadRecording"] }, { type: ControlPanel, selector: "app-sprcontrolpanel", inputs: ["readonly", "transportActions", "processing", "statusMsg", "statusAlertType", "statusWaiting", "uploadStatus", "uploadProgress", "currentRecording", "enableUploadRecordings", "navigationEnabled", "ready"] }], directives: [{ type: i6__namespace.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }] });
7869
8339
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.10", ngImport: i0__namespace, type: SessionManager, decorators: [{
7870
8340
  type: i0.Component,
7871
8341
  args: [{
7872
8342
  selector: 'app-sprrecordingsession',
7873
8343
  providers: [SessionService],
7874
- template: "\n <app-warningbar [show]=\"isTestSession()\" warningText=\"Test recording only!\"></app-warningbar>\n <app-warningbar [show]=\"isDefaultAudioTestSession()\" warningText=\"This test uses default audio device! Regular sessions may require a particular audio device (microphone)!\"></app-warningbar>\n <app-sprprompting [projectName]=\"projectName\"\n [startStopSignalState]=\"startStopSignalState\" [promptItem]=\"promptItem\" [showPrompt]=\"showPrompt\"\n [items]=\"items\"\n [transportActions]=\"transportActions\"\n [selectedItemIdx]=\"promptIndex\" (onItemSelect)=\"itemSelect($event)\" (onNextItem)=\"nextItem()\" (onPrevItem)=\"prevItem()\"\n [audioSignalCollapsed]=\"audioSignalCollapsed\" [displayAudioClip]=\"displayAudioClip\"\n [playStartAction]=\"controlAudioPlayer?.startAction\"\n [playSelectionAction]=\"controlAudioPlayer?.startSelectionAction\"\n [autoPlayOnSelectToggleAction]=\"controlAudioPlayer?.autoPlayOnSelectToggleAction\"\n [playStopAction]=\"controlAudioPlayer?.stopAction\">\n\n </app-sprprompting>\n <mat-progress-bar [value]=\"progressPercentValue()\" fxShow=\"false\" fxShow.xs=\"true\" ></mat-progress-bar>\n\n <spr-recordingitemdisplay #levelbardisplay\n [playStartAction]=\"controlAudioPlayer?.startAction\"\n [playStopAction]=\"controlAudioPlayer?.stopAction\"\n [streamingMode]=\"isRecording()\"\n [displayLevelInfos]=\"displayLevelInfos\"\n [displayAudioBuffer]=\"displayAudioClip?.buffer\" [audioSignalCollapsed]=\"audioSignalCollapsed\"\n (onShowRecordingDetails)=\"audioSignalCollapsed=!audioSignalCollapsed\"\n (onDownloadRecording)=\"downloadRecording()\"\n [enableDownload]=\"enableDownloadRecordings\"></spr-recordingitemdisplay>\n <app-sprcontrolpanel [enableUploadRecordings]=\"enableUploadRecordings\" [readonly]=\"readonly\" [currentRecording]=\"displayAudioClip?.buffer\"\n [transportActions]=\"transportActions\" [statusMsg]=\"statusMsg\" [statusWaiting]=\"statusWaiting\"\n [statusAlertType]=\"statusAlertType\" [uploadProgress]=\"uploadProgress\"\n [uploadStatus]=\"uploadStatus\" [ready]=\"dataSaved && !isActive()\" [processing]=\"processingRecording\" [navigationEnabled]=\"items==null || items.length>1\"></app-sprcontrolpanel>\n\n ",
8344
+ template: "\n <app-warningbar [show]=\"isTestSession()\" warningText=\"Test recording only!\"></app-warningbar>\n <app-warningbar [show]=\"isDefaultAudioTestSession()\" warningText=\"This test uses default audio device! Regular sessions may require a particular audio device (microphone)!\"></app-warningbar>\n <app-sprprompting [projectName]=\"projectName\"\n [startStopSignalState]=\"startStopSignalState\" [promptItem]=\"promptItem\" [showPrompt]=\"showPrompt\"\n [items]=\"items\"\n [transportActions]=\"transportActions\"\n [selectedItemIdx]=\"promptIndex\" (onItemSelect)=\"itemSelect($event)\" (onNextItem)=\"nextItem()\" (onPrevItem)=\"prevItem()\"\n [audioSignalCollapsed]=\"audioSignalCollapsed\" [displayAudioClip]=\"displayAudioClip\"\n [playStartAction]=\"controlAudioPlayer?.startAction\"\n [playSelectionAction]=\"controlAudioPlayer?.startSelectionAction\"\n [autoPlayOnSelectToggleAction]=\"controlAudioPlayer?.autoPlayOnSelectToggleAction\"\n [playStopAction]=\"controlAudioPlayer?.stopAction\">\n\n </app-sprprompting>\n <mat-progress-bar [value]=\"progressPercentValue()\" fxShow=\"false\" fxShow.xs=\"true\" ></mat-progress-bar>\n\n <spr-recordingitemdisplay #levelbardisplay\n [playStartAction]=\"controlAudioPlayer?.startAction\"\n [playStopAction]=\"controlAudioPlayer?.stopAction\"\n [streamingMode]=\"isRecording()\"\n [displayLevelInfos]=\"displayLevelInfos\"\n [displayAudioBuffer]=\"displayAudioClip?.buffer\"\n [agc]=\"this.ac?.agcStatus\"\n [audioSignalCollapsed]=\"audioSignalCollapsed\"\n (onShowRecordingDetails)=\"audioSignalCollapsed=!audioSignalCollapsed\"\n (onDownloadRecording)=\"downloadRecording()\"\n [enableDownload]=\"enableDownloadRecordings\"></spr-recordingitemdisplay>\n <app-sprcontrolpanel [enableUploadRecordings]=\"enableUploadRecordings\" [readonly]=\"readonly\" [currentRecording]=\"displayAudioClip?.buffer\"\n [transportActions]=\"transportActions\" [statusMsg]=\"statusMsg\" [statusWaiting]=\"statusWaiting\"\n [statusAlertType]=\"statusAlertType\" [uploadProgress]=\"uploadProgress\"\n [uploadStatus]=\"uploadStatus\" [ready]=\"dataSaved && !isActive()\" [processing]=\"processingRecording\" [navigationEnabled]=\"items==null || items.length>1\"></app-sprcontrolpanel>\n\n ",
7875
8345
  styles: [":host {\n flex: 2;\n background: lightgrey;\n display: flex; /* Vertical flex container: Bottom transport panel, above prompting panel */\n flex-direction: column;\n margin: 0;\n padding: 0;\n min-height: 0px;\n\n /* Prevents horizontal scroll bar on swipe right */\n overflow: hidden;\n }"]
7876
8346
  }]
7877
8347
  }], ctorParameters: function () {
@@ -7897,23 +8367,6 @@
7897
8367
  args: ['window:keydown', ['$event']]
7898
8368
  }] } });
7899
8369
 
7900
- var ProjectUtil = /** @class */ (function () {
7901
- function ProjectUtil() {
7902
- }
7903
- ProjectUtil.audioChannelCount = function (project) {
7904
- var chs = ProjectUtil.DEFAULT_AUDIO_CHANNEL_COUNT;
7905
- if (project.mediaCaptureFormat) {
7906
- chs = project.mediaCaptureFormat.audioChannelCount;
7907
- }
7908
- else if (project.audioFormat) {
7909
- chs = project.audioFormat.channels;
7910
- }
7911
- return chs;
7912
- };
7913
- return ProjectUtil;
7914
- }());
7915
- ProjectUtil.DEFAULT_AUDIO_CHANNEL_COUNT = 2;
7916
-
7917
8370
  /**
7918
8371
  * Created by klausj on 17.06.2017.
7919
8372
  */
@@ -8249,6 +8702,7 @@
8249
8702
  this.sm.audioDevices = project.audioDevices;
8250
8703
  chCnt = ProjectUtil.audioChannelCount(project);
8251
8704
  console.info("Project requested recording channel count: " + chCnt);
8705
+ this.sm.autoGainControlConfigs = project.autoGainControlConfigs;
8252
8706
  }
8253
8707
  else {
8254
8708
  console.error("Empty project configuration!");
@@ -9451,7 +9905,7 @@
9451
9905
  }]
9452
9906
  }] });
9453
9907
 
9454
- var VERSION = '2.18.13';
9908
+ var VERSION = '2.19.0';
9455
9909
 
9456
9910
  /*
9457
9911
  * Public API Surface of speechrecorderng