testaugnitorecorder4 1.1.10 → 1.1.12

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.
@@ -913,6 +913,7 @@ var Streamer = /*#__PURE__*/function () {
913
913
  this.deviceChangeHandler = null;
914
914
  this.onMicReady = onMicReady;
915
915
  this._originalDeviceId = null;
916
+ this._originalDeviceLabel = null;
916
917
  if (this.shouldPreIntialiseRecorder) {
917
918
  this.InitialiseMediaStream(reconnectAudioDuration, socketUrl);
918
919
  }
@@ -975,40 +976,39 @@ var Streamer = /*#__PURE__*/function () {
975
976
  case 6:
976
977
  return _context.abrupt("return");
977
978
  case 7:
978
- currentDeviceId = (_track$getSettings$de = (_track$getSettings = track.getSettings) === null || _track$getSettings === void 0 || (_track$getSettings = _track$getSettings.call(track)) === null || _track$getSettings === void 0 ? void 0 : _track$getSettings.deviceId) !== null && _track$getSettings$de !== void 0 ? _track$getSettings$de : track.label; // this.log(
979
- // `Device change detected. Probing current device: "${track.label}"`,
980
- // );
981
- _context.next = 10;
979
+ currentDeviceId = (_track$getSettings$de = (_track$getSettings = track.getSettings) === null || _track$getSettings === void 0 || (_track$getSettings = _track$getSettings.call(track)) === null || _track$getSettings === void 0 ? void 0 : _track$getSettings.deviceId) !== null && _track$getSettings$de !== void 0 ? _track$getSettings$de : track.label;
980
+ _this.log("Device change detected. Probing current device: \"".concat(track.label, "\""));
981
+ _context.next = 11;
982
982
  return isDeviceProducingAudio(currentDeviceId);
983
- case 10:
983
+ case 11:
984
984
  currentDeviceActive = _context.sent;
985
985
  if (currentDeviceActive) {
986
- _context.next = 21;
986
+ _context.next = 23;
987
987
  break;
988
988
  }
989
- // this.log(
990
- // `Current device "${track.label}" appears silent/virtual. Searching for a real input device...`,
991
- // );
989
+ _this.log("Current device \"".concat(track.label, "\" appears silent/virtual. Searching for a real input device..."));
992
990
  _this.micNeedsRecovery = true;
993
- _context.next = 15;
991
+ _context.next = 17;
994
992
  return findFirstActiveAudioDevice(currentDeviceId, _this.enableLogs);
995
- case 15:
993
+ case 17:
996
994
  realDeviceId = _context.sent;
997
995
  if (realDeviceId) {
998
996
  _this._preferredDeviceId = realDeviceId;
999
997
  } else {
1000
- // this.log("No active audio input device found after device change");
998
+ _this.log("No active audio input device found after device change");
1001
999
  _this._preferredDeviceId = null;
1002
1000
  }
1003
1001
 
1004
1002
  // Recover regardless of streaming state so onMicReady fires even
1005
1003
  // when the recorder is paused/stopped after an unplug error.
1006
- _context.next = 19;
1007
- return _this.recoverAudioGraph();
1008
- case 19:
1009
1004
  _context.next = 21;
1010
- break;
1005
+ return _this.recoverAudioGraph();
1011
1006
  case 21:
1007
+ _context.next = 24;
1008
+ break;
1009
+ case 23:
1010
+ _this.log("Current device \"".concat(track.label, "\" is producing audio \u2014 no switch needed"));
1011
+ case 24:
1012
1012
  case "end":
1013
1013
  return _context.stop();
1014
1014
  }
@@ -1132,13 +1132,13 @@ var Streamer = /*#__PURE__*/function () {
1132
1132
  }, {
1133
1133
  key: "createMediaStreamSourceNode",
1134
1134
  value: function () {
1135
- var _createMediaStreamSourceNode = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() {
1135
+ var _createMediaStreamSourceNode = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5() {
1136
1136
  var _this2 = this;
1137
- var _track$getSettings$de2, _track$getSettings2, audioConstraints, track, acquiredDeviceId, errMessage;
1138
- return _regeneratorRuntime().wrap(function _callee6$(_context6) {
1139
- while (1) switch (_context6.prev = _context6.next) {
1137
+ var _track$getSettings$de2, _track$getSettings2, _track$label, audioConstraints, track, acquiredDeviceId, acquiredLabel, errMessage;
1138
+ return _regeneratorRuntime().wrap(function _callee5$(_context5) {
1139
+ while (1) switch (_context5.prev = _context5.next) {
1140
1140
  case 0:
1141
- _context6.prev = 0;
1141
+ _context5.prev = 0;
1142
1142
  audioConstraints = {
1143
1143
  channelCount: CHANNEL_COUNT,
1144
1144
  noiseSuppression: this.noiseSuppression !== undefined ? this.noiseSuppression : NOISE_SUPPRESS_ENABLED
@@ -1163,21 +1163,29 @@ var Streamer = /*#__PURE__*/function () {
1163
1163
  exact: this._preferredDeviceId
1164
1164
  };
1165
1165
  }
1166
- _context6.next = 8;
1166
+ _context5.next = 8;
1167
1167
  return navigator.mediaDevices.getUserMedia({
1168
1168
  audio: audioConstraints
1169
1169
  });
1170
1170
  case 8:
1171
- this.audioStream = _context6.sent;
1171
+ this.audioStream = _context5.sent;
1172
1172
  if (!this.audioContext || this.audioContext.state === "closed") {
1173
1173
  this.audioContext = new AudioContext();
1174
1174
  }
1175
1175
  this.source = this.audioContext.createMediaStreamSource(this.audioStream);
1176
1176
  track = this.audioStream.getAudioTracks()[0]; // Record the device that was first used for recording so we can
1177
1177
  // identify when that exact mic is reconnected after being unplugged.
1178
- acquiredDeviceId = (_track$getSettings$de2 = (_track$getSettings2 = track.getSettings) === null || _track$getSettings2 === void 0 || (_track$getSettings2 = _track$getSettings2.call(track)) === null || _track$getSettings2 === void 0 ? void 0 : _track$getSettings2.deviceId) !== null && _track$getSettings$de2 !== void 0 ? _track$getSettings$de2 : track.label;
1178
+ // We store BOTH the deviceId and the label because on Windows the
1179
+ // deviceId is often a generic alias ("default" / "communications")
1180
+ // that does not change when a USB mic is unplugged and a fallback
1181
+ // device takes over. The label is the physical device name and IS
1182
+ // unique per device, so the combination of both fields lets us
1183
+ // reliably distinguish a true reconnect from a same-alias fallback.
1184
+ acquiredDeviceId = (_track$getSettings$de2 = (_track$getSettings2 = track.getSettings) === null || _track$getSettings2 === void 0 || (_track$getSettings2 = _track$getSettings2.call(track)) === null || _track$getSettings2 === void 0 ? void 0 : _track$getSettings2.deviceId) !== null && _track$getSettings$de2 !== void 0 ? _track$getSettings$de2 : "";
1185
+ acquiredLabel = (_track$label = track.label) !== null && _track$label !== void 0 ? _track$label : "";
1179
1186
  if (!this._originalDeviceId) {
1180
1187
  this._originalDeviceId = acquiredDeviceId;
1188
+ this._originalDeviceLabel = acquiredLabel;
1181
1189
  }
1182
1190
 
1183
1191
  // Clear any previously registered handler before attaching a new one
@@ -1185,52 +1193,43 @@ var Streamer = /*#__PURE__*/function () {
1185
1193
  if (this.trackEndedHandler) {
1186
1194
  this.trackEndedHandler = null;
1187
1195
  }
1188
- this.trackEndedHandler = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5() {
1189
- return _regeneratorRuntime().wrap(function _callee5$(_context5) {
1190
- while (1) switch (_context5.prev = _context5.next) {
1191
- case 0:
1192
- // this.log("Microphone disconnected");
1196
+ this.trackEndedHandler = function () {
1197
+ // this.log("Microphone disconnected");
1193
1198
 
1194
- _this2.micNeedsRecovery = true;
1195
- _this2.onError(JSON.stringify({
1196
- Type: "ERROR",
1197
- Data: "Audio track ended. Possibly the mic was unplugged."
1198
- }));
1199
- if (!(_this2.isStreaming && !_this2.isPaused)) {
1200
- _context5.next = 5;
1201
- break;
1202
- }
1203
- _context5.next = 5;
1204
- return _this2.recoverAudioGraph();
1205
- case 5:
1206
- case "end":
1207
- return _context5.stop();
1208
- }
1209
- }, _callee5);
1210
- }));
1199
+ _this2.micNeedsRecovery = true;
1200
+ _this2.onError(JSON.stringify({
1201
+ Type: "ERROR",
1202
+ Data: "Audio track ended. Possibly the mic was unplugged."
1203
+ }));
1204
+
1205
+ // Do NOT call recoverAudioGraph() here. The devicechange event fires
1206
+ // immediately after track-ended on all major browsers/OS and will
1207
+ // handle recovery in deviceChangeHandler. Calling it here as well
1208
+ // causes a double-recovery race (two sequential error/ready callbacks).
1209
+ };
1211
1210
  track.addEventListener("ended", this.trackEndedHandler);
1212
- _context6.next = 24;
1211
+ _context5.next = 25;
1213
1212
  break;
1214
- case 19:
1215
- _context6.prev = 19;
1216
- _context6.t0 = _context6["catch"](0);
1213
+ case 20:
1214
+ _context5.prev = 20;
1215
+ _context5.t0 = _context5["catch"](0);
1217
1216
  errMessage = "";
1218
- if (_context6.t0.name == "NotAllowedError") {
1217
+ if (_context5.t0.name == "NotAllowedError") {
1219
1218
  errMessage = "Mic permission denied";
1220
- } else if (_context6.t0.name === "NotFoundError") {
1219
+ } else if (_context5.t0.name === "NotFoundError") {
1221
1220
  errMessage = "No suitable media device found";
1222
- } else if (_context6.t0.name === "NotReadableError") {
1221
+ } else if (_context5.t0.name === "NotReadableError") {
1223
1222
  errMessage = "Microphone is being used by another application";
1224
1223
  }
1225
1224
  this.onError(JSON.stringify({
1226
1225
  Type: "ERROR",
1227
1226
  Data: errMessage
1228
1227
  }));
1229
- case 24:
1228
+ case 25:
1230
1229
  case "end":
1231
- return _context6.stop();
1230
+ return _context5.stop();
1232
1231
  }
1233
- }, _callee6, this, [[0, 19]]);
1232
+ }, _callee5, this, [[0, 20]]);
1234
1233
  }));
1235
1234
  function createMediaStreamSourceNode() {
1236
1235
  return _createMediaStreamSourceNode.apply(this, arguments);
@@ -1240,35 +1239,35 @@ var Streamer = /*#__PURE__*/function () {
1240
1239
  }, {
1241
1240
  key: "loadAudio",
1242
1241
  value: function () {
1243
- var _loadAudio = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7() {
1242
+ var _loadAudio = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() {
1244
1243
  var response, arrayBuffer, audioBuffer;
1245
- return _regeneratorRuntime().wrap(function _callee7$(_context7) {
1246
- while (1) switch (_context7.prev = _context7.next) {
1244
+ return _regeneratorRuntime().wrap(function _callee6$(_context6) {
1245
+ while (1) switch (_context6.prev = _context6.next) {
1247
1246
  case 0:
1248
- _context7.prev = 0;
1249
- _context7.next = 3;
1247
+ _context6.prev = 0;
1248
+ _context6.next = 3;
1250
1249
  return fetch("./radiology_speed_test.wav");
1251
1250
  case 3:
1252
- response = _context7.sent;
1253
- _context7.next = 6;
1251
+ response = _context6.sent;
1252
+ _context6.next = 6;
1254
1253
  return response.arrayBuffer();
1255
1254
  case 6:
1256
- arrayBuffer = _context7.sent;
1257
- _context7.next = 9;
1255
+ arrayBuffer = _context6.sent;
1256
+ _context6.next = 9;
1258
1257
  return this.audioContext.decodeAudioData(arrayBuffer);
1259
1258
  case 9:
1260
- audioBuffer = _context7.sent;
1261
- return _context7.abrupt("return", audioBuffer);
1259
+ audioBuffer = _context6.sent;
1260
+ return _context6.abrupt("return", audioBuffer);
1262
1261
  case 13:
1263
- _context7.prev = 13;
1264
- _context7.t0 = _context7["catch"](0);
1265
- console.error("Unable to fetch the audio file. Error: ".concat(_context7.t0.message));
1266
- return _context7.abrupt("return", null);
1262
+ _context6.prev = 13;
1263
+ _context6.t0 = _context6["catch"](0);
1264
+ console.error("Unable to fetch the audio file. Error: ".concat(_context6.t0.message));
1265
+ return _context6.abrupt("return", null);
1267
1266
  case 17:
1268
1267
  case "end":
1269
- return _context7.stop();
1268
+ return _context6.stop();
1270
1269
  }
1271
- }, _callee7, this, [[0, 13]]);
1270
+ }, _callee6, this, [[0, 13]]);
1272
1271
  }));
1273
1272
  function loadAudio() {
1274
1273
  return _loadAudio.apply(this, arguments);
@@ -1278,14 +1277,14 @@ var Streamer = /*#__PURE__*/function () {
1278
1277
  }, {
1279
1278
  key: "createProcessorNode",
1280
1279
  value: function () {
1281
- var _createProcessorNode = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee8() {
1280
+ var _createProcessorNode = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7() {
1282
1281
  var _this3 = this;
1283
1282
  var _this$shouldReadInten, sampleRateParam, bufferSizeIntervalParam, pausedBufferIntervalParam, shouldReadIntensityParam;
1284
- return _regeneratorRuntime().wrap(function _callee8$(_context8) {
1285
- while (1) switch (_context8.prev = _context8.next) {
1283
+ return _regeneratorRuntime().wrap(function _callee7$(_context7) {
1284
+ while (1) switch (_context7.prev = _context7.next) {
1286
1285
  case 0:
1287
- _context8.prev = 0;
1288
- _context8.next = 3;
1286
+ _context7.prev = 0;
1287
+ _context7.next = 3;
1289
1288
  return this.audioContext.audioWorklet.addModule("data:application/javascript,".concat(encodeURIComponent(worklet)));
1290
1289
  case 3:
1291
1290
  this.processorNode = new AudioWorkletNode(this.audioContext, WORKLET_PROCESSOR);
@@ -1333,17 +1332,17 @@ var Streamer = /*#__PURE__*/function () {
1333
1332
  }
1334
1333
  }
1335
1334
  };
1336
- _context8.next = 18;
1335
+ _context7.next = 18;
1337
1336
  break;
1338
1337
  case 15:
1339
- _context8.prev = 15;
1340
- _context8.t0 = _context8["catch"](0);
1341
- console.error("Error: Unable to create worklet node: ", _context8.t0);
1338
+ _context7.prev = 15;
1339
+ _context7.t0 = _context7["catch"](0);
1340
+ console.error("Error: Unable to create worklet node: ", _context7.t0);
1342
1341
  case 18:
1343
1342
  case "end":
1344
- return _context8.stop();
1343
+ return _context7.stop();
1345
1344
  }
1346
- }, _callee8, this, [[0, 15]]);
1345
+ }, _callee7, this, [[0, 15]]);
1347
1346
  }));
1348
1347
  function createProcessorNode() {
1349
1348
  return _createProcessorNode.apply(this, arguments);
@@ -1353,25 +1352,25 @@ var Streamer = /*#__PURE__*/function () {
1353
1352
  }, {
1354
1353
  key: "PauseStream",
1355
1354
  value: function () {
1356
- var _PauseStream = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9() {
1357
- return _regeneratorRuntime().wrap(function _callee9$(_context9) {
1358
- while (1) switch (_context9.prev = _context9.next) {
1355
+ var _PauseStream = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee8() {
1356
+ return _regeneratorRuntime().wrap(function _callee8$(_context8) {
1357
+ while (1) switch (_context8.prev = _context8.next) {
1359
1358
  case 0:
1360
1359
  if (!(this.audioContext.state == "running")) {
1361
- _context9.next = 9;
1360
+ _context8.next = 9;
1362
1361
  break;
1363
1362
  }
1364
1363
  if (this.shouldPreIntialiseRecorder) {
1365
- _context9.next = 8;
1364
+ _context8.next = 8;
1366
1365
  break;
1367
1366
  }
1368
- _context9.next = 4;
1367
+ _context8.next = 4;
1369
1368
  return this.audioContext.suspend();
1370
1369
  case 4:
1371
1370
  this.log("Stream paused...");
1372
1371
  // message sent to worklet-thread
1373
1372
  this.processorNode.port.postMessage(PAUSE_MSG);
1374
- _context9.next = 9;
1373
+ _context8.next = 9;
1375
1374
  break;
1376
1375
  case 8:
1377
1376
  this.processorNode.port.postMessage(PAUSE_SOCKET_MSG);
@@ -1381,9 +1380,9 @@ var Streamer = /*#__PURE__*/function () {
1381
1380
  this.isStreaming = false;
1382
1381
  case 12:
1383
1382
  case "end":
1384
- return _context9.stop();
1383
+ return _context8.stop();
1385
1384
  }
1386
- }, _callee9, this);
1385
+ }, _callee8, this);
1387
1386
  }));
1388
1387
  function PauseStream() {
1389
1388
  return _PauseStream.apply(this, arguments);
@@ -1393,52 +1392,52 @@ var Streamer = /*#__PURE__*/function () {
1393
1392
  }, {
1394
1393
  key: "ResumeStream",
1395
1394
  value: function () {
1396
- var _ResumeStream = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee10() {
1395
+ var _ResumeStream = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9() {
1397
1396
  var _this$audioStream3, _this$audioStream3$ge;
1398
1397
  var track, trackEnded;
1399
- return _regeneratorRuntime().wrap(function _callee10$(_context10) {
1400
- while (1) switch (_context10.prev = _context10.next) {
1398
+ return _regeneratorRuntime().wrap(function _callee9$(_context9) {
1399
+ while (1) switch (_context9.prev = _context9.next) {
1401
1400
  case 0:
1402
1401
  track = (_this$audioStream3 = this.audioStream) === null || _this$audioStream3 === void 0 || (_this$audioStream3$ge = _this$audioStream3.getAudioTracks) === null || _this$audioStream3$ge === void 0 ? void 0 : _this$audioStream3$ge.call(_this$audioStream3)[0];
1403
1402
  trackEnded = !track || track.readyState === "ended";
1404
1403
  if (!(trackEnded || this.micNeedsRecovery)) {
1405
- _context10.next = 5;
1404
+ _context9.next = 5;
1406
1405
  break;
1407
1406
  }
1408
- _context10.next = 5;
1407
+ _context9.next = 5;
1409
1408
  return this.recoverAudioGraph();
1410
1409
  case 5:
1411
1410
  if (!this.IsMicrophoneMuted) {
1412
- _context10.next = 11;
1411
+ _context9.next = 11;
1413
1412
  break;
1414
1413
  }
1415
1414
  if (!(this.audioContext && this.audioContext.state === "running")) {
1416
- _context10.next = 9;
1415
+ _context9.next = 9;
1417
1416
  break;
1418
1417
  }
1419
- _context10.next = 9;
1418
+ _context9.next = 9;
1420
1419
  return this.audioContext.suspend();
1421
1420
  case 9:
1422
1421
  this.onError(JSON.stringify({
1423
1422
  Type: "ERROR",
1424
1423
  Data: "Microphone is muted."
1425
1424
  }));
1426
- return _context10.abrupt("return");
1425
+ return _context9.abrupt("return");
1427
1426
  case 11:
1428
1427
  if (!this.shouldPreIntialiseRecorder) {
1429
- _context10.next = 16;
1428
+ _context9.next = 16;
1430
1429
  break;
1431
1430
  }
1432
1431
  this.processorNode.port.postMessage(RESUME_SOCKET_MSG);
1433
1432
  this.executor.Send(RESUME_SOCKET_MSG);
1434
- _context10.next = 20;
1433
+ _context9.next = 20;
1435
1434
  break;
1436
1435
  case 16:
1437
1436
  if (!(this.audioContext.state === "suspended")) {
1438
- _context10.next = 19;
1437
+ _context9.next = 19;
1439
1438
  break;
1440
1439
  }
1441
- _context10.next = 19;
1440
+ _context9.next = 19;
1442
1441
  return this.audioContext.resume();
1443
1442
  case 19:
1444
1443
  this.log("Stream resumed...");
@@ -1448,9 +1447,9 @@ var Streamer = /*#__PURE__*/function () {
1448
1447
  this.isStreaming = true;
1449
1448
  case 23:
1450
1449
  case "end":
1451
- return _context10.stop();
1450
+ return _context9.stop();
1452
1451
  }
1453
- }, _callee10, this);
1452
+ }, _callee9, this);
1454
1453
  }));
1455
1454
  function ResumeStream() {
1456
1455
  return _ResumeStream.apply(this, arguments);
@@ -1480,17 +1479,17 @@ var Streamer = /*#__PURE__*/function () {
1480
1479
  }, {
1481
1480
  key: "StopStream",
1482
1481
  value: function () {
1483
- var _StopStream = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee11(shouldSendEOS) {
1482
+ var _StopStream = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee10(shouldSendEOS) {
1484
1483
  var _this$audioContext, _this$audioStream5, _this$audioStream5$ge, _this$audioStream6, _this$audioStream6$ge, _this$processorNode;
1485
1484
  var _this$audioContext2, track;
1486
- return _regeneratorRuntime().wrap(function _callee11$(_context11) {
1487
- while (1) switch (_context11.prev = _context11.next) {
1485
+ return _regeneratorRuntime().wrap(function _callee10$(_context10) {
1486
+ while (1) switch (_context10.prev = _context10.next) {
1488
1487
  case 0:
1489
1488
  if (!(((_this$audioContext = this.audioContext) === null || _this$audioContext === void 0 ? void 0 : _this$audioContext.state) !== "suspended")) {
1490
- _context11.next = 4;
1489
+ _context10.next = 4;
1491
1490
  break;
1492
1491
  }
1493
- _context11.next = 3;
1492
+ _context10.next = 3;
1494
1493
  return (_this$audioContext2 = this.audioContext) === null || _this$audioContext2 === void 0 ? void 0 : _this$audioContext2.suspend();
1495
1494
  case 3:
1496
1495
  this.onStateChanged(false);
@@ -1520,9 +1519,9 @@ var Streamer = /*#__PURE__*/function () {
1520
1519
  (_this$processorNode = this.processorNode) === null || _this$processorNode === void 0 || (_this$processorNode = _this$processorNode.port) === null || _this$processorNode === void 0 || _this$processorNode.postMessage(STOP_MSG);
1521
1520
  case 14:
1522
1521
  case "end":
1523
- return _context11.stop();
1522
+ return _context10.stop();
1524
1523
  }
1525
- }, _callee11, this);
1524
+ }, _callee10, this);
1526
1525
  }));
1527
1526
  function StopStream(_x5) {
1528
1527
  return _StopStream.apply(this, arguments);
@@ -1532,20 +1531,20 @@ var Streamer = /*#__PURE__*/function () {
1532
1531
  }, {
1533
1532
  key: "recoverAudioGraph",
1534
1533
  value: function () {
1535
- var _recoverAudioGraph = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee12() {
1534
+ var _recoverAudioGraph = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee11() {
1536
1535
  var _this4 = this;
1537
- var _this$audioStream7, _this$audioStream8, _this$audioStream8$ge, _recoveredTrack$getSe, _recoveredTrack$getSe2, _this$source, _this$processorNode2, recoveredTrack, recoveredDeviceId, isOriginalDeviceReconnected;
1538
- return _regeneratorRuntime().wrap(function _callee12$(_context12) {
1539
- while (1) switch (_context12.prev = _context12.next) {
1536
+ var _this$audioStream7, _this$audioStream8, _this$audioStream8$ge, _recoveredTrack$getSe, _recoveredTrack$getSe2, _recoveredTrack$label, _this$source, _this$processorNode2, recoveredTrack, recoveredDeviceId, recoveredLabel, isOriginalDeviceReconnected;
1537
+ return _regeneratorRuntime().wrap(function _callee11$(_context11) {
1538
+ while (1) switch (_context11.prev = _context11.next) {
1540
1539
  case 0:
1541
1540
  if (!this.isRecovering) {
1542
- _context12.next = 2;
1541
+ _context11.next = 2;
1543
1542
  break;
1544
1543
  }
1545
- return _context12.abrupt("return");
1544
+ return _context11.abrupt("return");
1546
1545
  case 2:
1547
1546
  this.isRecovering = true;
1548
- _context12.prev = 3;
1547
+ _context11.prev = 3;
1549
1548
  // this.log("Recovering audio graph...");
1550
1549
 
1551
1550
  // stop old track
@@ -1566,11 +1565,11 @@ var Streamer = /*#__PURE__*/function () {
1566
1565
  } catch (_unused5) {}
1567
1566
 
1568
1567
  // recreate media stream ONLY
1569
- _context12.next = 9;
1568
+ _context11.next = 9;
1570
1569
  return this.createMediaStreamSourceNode();
1571
1570
  case 9:
1572
1571
  if (this.source) {
1573
- _context12.next = 11;
1572
+ _context11.next = 11;
1574
1573
  break;
1575
1574
  }
1576
1575
  throw new Error("Failed to recreate source");
@@ -1580,13 +1579,13 @@ var Streamer = /*#__PURE__*/function () {
1580
1579
  this.audioContext = new AudioContext();
1581
1580
  }
1582
1581
  if (!(this.audioContext.state === "suspended")) {
1583
- _context12.next = 15;
1582
+ _context11.next = 15;
1584
1583
  break;
1585
1584
  }
1586
- _context12.next = 15;
1585
+ _context11.next = 15;
1587
1586
  return this.audioContext.resume();
1588
1587
  case 15:
1589
- _context12.next = 17;
1588
+ _context11.next = 17;
1590
1589
  return this.createProcessorNode();
1591
1590
  case 17:
1592
1591
  // reconnect graph
@@ -1596,29 +1595,38 @@ var Streamer = /*#__PURE__*/function () {
1596
1595
  // AudioContext immediately after rebuilding the graph so the mic does
1597
1596
  // not start capturing audio without an explicit start/resume call.
1598
1597
  if (!(!this.isStreaming || this.isPaused)) {
1599
- _context12.next = 22;
1598
+ _context11.next = 22;
1600
1599
  break;
1601
1600
  }
1602
1601
  if (!(this.audioContext.state === "running")) {
1603
- _context12.next = 22;
1602
+ _context11.next = 22;
1604
1603
  break;
1605
1604
  }
1606
- _context12.next = 22;
1605
+ _context11.next = 22;
1607
1606
  return this.audioContext.suspend();
1608
1607
  case 22:
1609
1608
  this.micNeedsRecovery = false;
1610
1609
 
1611
1610
  // Determine whether the recovered stream is the original recording device.
1611
+ // On Windows, deviceId alone is unreliable (it can be a generic alias like
1612
+ // "default" that stays the same even after a USB mic is unplugged and a
1613
+ // fallback device takes over). We therefore require BOTH deviceId AND label
1614
+ // to match before declaring the original device reconnected.
1612
1615
  recoveredTrack = (_this$audioStream8 = this.audioStream) === null || _this$audioStream8 === void 0 || (_this$audioStream8$ge = _this$audioStream8.getAudioTracks) === null || _this$audioStream8$ge === void 0 ? void 0 : _this$audioStream8$ge.call(_this$audioStream8)[0];
1613
- recoveredDeviceId = (_recoveredTrack$getSe = recoveredTrack === null || recoveredTrack === void 0 || (_recoveredTrack$getSe2 = recoveredTrack.getSettings) === null || _recoveredTrack$getSe2 === void 0 || (_recoveredTrack$getSe2 = _recoveredTrack$getSe2.call(recoveredTrack)) === null || _recoveredTrack$getSe2 === void 0 ? void 0 : _recoveredTrack$getSe2.deviceId) !== null && _recoveredTrack$getSe !== void 0 ? _recoveredTrack$getSe : recoveredTrack === null || recoveredTrack === void 0 ? void 0 : recoveredTrack.label;
1614
- isOriginalDeviceReconnected = !!this._originalDeviceId && recoveredDeviceId === this._originalDeviceId; // Notify the client that a replacement mic is ready but only when the
1615
- // recorder is in the paused state. In stopped state the client manages
1616
- // the flow themselves; in actively-streaming state recovery is seamless
1617
- // and no notification is needed.
1618
- // Fire if the mic is unmuted, OR if the original recording device was
1619
- // reconnected (even while muted — the client should know it is back).
1620
- // Do NOT fire if a different fallback device is muted, preserving the
1621
- // original intent of the !IsMicrophoneMuted guard.
1616
+ recoveredDeviceId = (_recoveredTrack$getSe = recoveredTrack === null || recoveredTrack === void 0 || (_recoveredTrack$getSe2 = recoveredTrack.getSettings) === null || _recoveredTrack$getSe2 === void 0 || (_recoveredTrack$getSe2 = _recoveredTrack$getSe2.call(recoveredTrack)) === null || _recoveredTrack$getSe2 === void 0 ? void 0 : _recoveredTrack$getSe2.deviceId) !== null && _recoveredTrack$getSe !== void 0 ? _recoveredTrack$getSe : "";
1617
+ recoveredLabel = (_recoveredTrack$label = recoveredTrack === null || recoveredTrack === void 0 ? void 0 : recoveredTrack.label) !== null && _recoveredTrack$label !== void 0 ? _recoveredTrack$label : "";
1618
+ isOriginalDeviceReconnected = !!this._originalDeviceId && recoveredDeviceId === this._originalDeviceId && !!this._originalDeviceLabel && recoveredLabel === this._originalDeviceLabel; // Fire onMicReady when:
1619
+ // the recorder is paused, AND
1620
+ // the mic is genuinely usable (!IsMicrophoneMuted), OR the exact
1621
+ // original device (same id + same label) was reconnected even if
1622
+ // it is currently in a muted/ended state.
1623
+ // This means:
1624
+ // - Unplug with no real replacement → IsMicrophoneMuted=true,
1625
+ // isOriginalDeviceReconnected=false → no callback (correct).
1626
+ // - Unplug, fallback to another muted mic → IsMicrophoneMuted=true,
1627
+ // label differs → isOriginalDeviceReconnected=false → no callback.
1628
+ // - Original USB mic plugged back in while muted → same id+label
1629
+ // → isOriginalDeviceReconnected=true → callback fires (correct).
1622
1630
  if (this.isPaused && (!this.IsMicrophoneMuted || isOriginalDeviceReconnected)) {
1623
1631
  if (this.onMicReady && !this._micReadyFired) {
1624
1632
  this._micReadyFired = true;
@@ -1628,13 +1636,13 @@ var Streamer = /*#__PURE__*/function () {
1628
1636
  this.onMicReady();
1629
1637
  }
1630
1638
  }
1631
- // this.log("Audio graph recovery completed");
1632
- _context12.next = 32;
1639
+ this.log("Audio graph recovery completed");
1640
+ _context11.next = 34;
1633
1641
  break;
1634
- case 29:
1635
- _context12.prev = 29;
1636
- _context12.t0 = _context12["catch"](3);
1637
- console.error("Recovery failed", _context12.t0);
1642
+ case 31:
1643
+ _context11.prev = 31;
1644
+ _context11.t0 = _context11["catch"](3);
1645
+ console.error("Recovery failed", _context11.t0);
1638
1646
 
1639
1647
  // this.onError(
1640
1648
  // JSON.stringify({
@@ -1642,15 +1650,15 @@ var Streamer = /*#__PURE__*/function () {
1642
1650
  // Data: "Failed to recover microphone",
1643
1651
  // }),
1644
1652
  // );
1645
- case 32:
1646
- _context12.prev = 32;
1653
+ case 34:
1654
+ _context11.prev = 34;
1647
1655
  this.isRecovering = false;
1648
- return _context12.finish(32);
1649
- case 35:
1656
+ return _context11.finish(34);
1657
+ case 37:
1650
1658
  case "end":
1651
- return _context12.stop();
1659
+ return _context11.stop();
1652
1660
  }
1653
- }, _callee12, this, [[3, 29, 32, 35]]);
1661
+ }, _callee11, this, [[3, 31, 34, 37]]);
1654
1662
  }));
1655
1663
  function recoverAudioGraph() {
1656
1664
  return _recoverAudioGraph.apply(this, arguments);
@@ -1781,7 +1789,7 @@ function isDeviceProducingAudio(_x6) {
1781
1789
  * @returns {Promise<string|null>}
1782
1790
  */
1783
1791
  function _isDeviceProducingAudio() {
1784
- _isDeviceProducingAudio = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee13(deviceId) {
1792
+ _isDeviceProducingAudio = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee12(deviceId) {
1785
1793
  var durationMs,
1786
1794
  silenceThreshold,
1787
1795
  stream,
@@ -1791,16 +1799,16 @@ function _isDeviceProducingAudio() {
1791
1799
  bufferLength,
1792
1800
  dataArray,
1793
1801
  _stream,
1794
- _args13 = arguments;
1795
- return _regeneratorRuntime().wrap(function _callee13$(_context13) {
1796
- while (1) switch (_context13.prev = _context13.next) {
1802
+ _args12 = arguments;
1803
+ return _regeneratorRuntime().wrap(function _callee12$(_context12) {
1804
+ while (1) switch (_context12.prev = _context12.next) {
1797
1805
  case 0:
1798
- durationMs = _args13.length > 1 && _args13[1] !== undefined ? _args13[1] : 350;
1799
- silenceThreshold = _args13.length > 2 && _args13[2] !== undefined ? _args13[2] : 0.01;
1806
+ durationMs = _args12.length > 1 && _args12[1] !== undefined ? _args12[1] : 350;
1807
+ silenceThreshold = _args12.length > 2 && _args12[2] !== undefined ? _args12[2] : 0.01;
1800
1808
  stream = null;
1801
1809
  audioCtx = null;
1802
- _context13.prev = 4;
1803
- _context13.next = 7;
1810
+ _context12.prev = 4;
1811
+ _context12.next = 7;
1804
1812
  return navigator.mediaDevices.getUserMedia({
1805
1813
  audio: {
1806
1814
  deviceId: {
@@ -1810,7 +1818,7 @@ function _isDeviceProducingAudio() {
1810
1818
  }
1811
1819
  });
1812
1820
  case 7:
1813
- stream = _context13.sent;
1821
+ stream = _context12.sent;
1814
1822
  audioCtx = new AudioContext();
1815
1823
  source = audioCtx.createMediaStreamSource(stream);
1816
1824
  analyser = audioCtx.createAnalyser();
@@ -1818,7 +1826,7 @@ function _isDeviceProducingAudio() {
1818
1826
  source.connect(analyser);
1819
1827
  bufferLength = analyser.frequencyBinCount;
1820
1828
  dataArray = new Float32Array(bufferLength);
1821
- _context13.next = 17;
1829
+ _context12.next = 17;
1822
1830
  return new Promise(function (resolve) {
1823
1831
  var maxRms = 0;
1824
1832
  var startTime = performance.now();
@@ -1839,25 +1847,25 @@ function _isDeviceProducingAudio() {
1839
1847
  requestAnimationFrame(sample);
1840
1848
  });
1841
1849
  case 17:
1842
- return _context13.abrupt("return", _context13.sent);
1850
+ return _context12.abrupt("return", _context12.sent);
1843
1851
  case 20:
1844
- _context13.prev = 20;
1845
- _context13.t0 = _context13["catch"](4);
1846
- return _context13.abrupt("return", false);
1852
+ _context12.prev = 20;
1853
+ _context12.t0 = _context12["catch"](4);
1854
+ return _context12.abrupt("return", false);
1847
1855
  case 23:
1848
- _context13.prev = 23;
1856
+ _context12.prev = 23;
1849
1857
  (_stream = stream) === null || _stream === void 0 || _stream.getTracks().forEach(function (t) {
1850
1858
  return t.stop();
1851
1859
  });
1852
1860
  if (audioCtx && audioCtx.state !== "closed") {
1853
1861
  audioCtx.close().catch(function () {});
1854
1862
  }
1855
- return _context13.finish(23);
1863
+ return _context12.finish(23);
1856
1864
  case 27:
1857
1865
  case "end":
1858
- return _context13.stop();
1866
+ return _context12.stop();
1859
1867
  }
1860
- }, _callee13, null, [[4, 20, 23, 27]]);
1868
+ }, _callee12, null, [[4, 20, 23, 27]]);
1861
1869
  }));
1862
1870
  return _isDeviceProducingAudio.apply(this, arguments);
1863
1871
  }
@@ -1865,70 +1873,70 @@ function findFirstActiveAudioDevice(_x7) {
1865
1873
  return _findFirstActiveAudioDevice.apply(this, arguments);
1866
1874
  }
1867
1875
  function _findFirstActiveAudioDevice() {
1868
- _findFirstActiveAudioDevice = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee14(excludeDeviceId) {
1876
+ _findFirstActiveAudioDevice = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee13(excludeDeviceId) {
1869
1877
  var devices,
1870
1878
  audioInputs,
1871
1879
  _iterator,
1872
1880
  _step,
1873
1881
  device,
1874
1882
  active;
1875
- return _regeneratorRuntime().wrap(function _callee14$(_context14) {
1876
- while (1) switch (_context14.prev = _context14.next) {
1883
+ return _regeneratorRuntime().wrap(function _callee13$(_context13) {
1884
+ while (1) switch (_context13.prev = _context13.next) {
1877
1885
  case 0:
1878
- _context14.prev = 1;
1879
- _context14.next = 4;
1886
+ _context13.prev = 1;
1887
+ _context13.next = 4;
1880
1888
  return navigator.mediaDevices.enumerateDevices();
1881
1889
  case 4:
1882
- devices = _context14.sent;
1883
- _context14.next = 10;
1890
+ devices = _context13.sent;
1891
+ _context13.next = 10;
1884
1892
  break;
1885
1893
  case 7:
1886
- _context14.prev = 7;
1887
- _context14.t0 = _context14["catch"](1);
1888
- return _context14.abrupt("return", null);
1894
+ _context13.prev = 7;
1895
+ _context13.t0 = _context13["catch"](1);
1896
+ return _context13.abrupt("return", null);
1889
1897
  case 10:
1890
1898
  audioInputs = devices.filter(function (d) {
1891
1899
  return d.kind === "audioinput" && d.deviceId !== excludeDeviceId;
1892
1900
  });
1893
1901
  _iterator = _createForOfIteratorHelper(audioInputs);
1894
- _context14.prev = 12;
1902
+ _context13.prev = 12;
1895
1903
  _iterator.s();
1896
1904
  case 14:
1897
1905
  if ((_step = _iterator.n()).done) {
1898
- _context14.next = 23;
1906
+ _context13.next = 23;
1899
1907
  break;
1900
1908
  }
1901
1909
  device = _step.value;
1902
- _context14.next = 18;
1910
+ _context13.next = 18;
1903
1911
  return isDeviceProducingAudio(device.deviceId);
1904
1912
  case 18:
1905
- active = _context14.sent;
1913
+ active = _context13.sent;
1906
1914
  if (!active) {
1907
- _context14.next = 21;
1915
+ _context13.next = 21;
1908
1916
  break;
1909
1917
  }
1910
- return _context14.abrupt("return", device.deviceId);
1918
+ return _context13.abrupt("return", device.deviceId);
1911
1919
  case 21:
1912
- _context14.next = 14;
1920
+ _context13.next = 14;
1913
1921
  break;
1914
1922
  case 23:
1915
- _context14.next = 28;
1923
+ _context13.next = 28;
1916
1924
  break;
1917
1925
  case 25:
1918
- _context14.prev = 25;
1919
- _context14.t1 = _context14["catch"](12);
1920
- _iterator.e(_context14.t1);
1926
+ _context13.prev = 25;
1927
+ _context13.t1 = _context13["catch"](12);
1928
+ _iterator.e(_context13.t1);
1921
1929
  case 28:
1922
- _context14.prev = 28;
1930
+ _context13.prev = 28;
1923
1931
  _iterator.f();
1924
- return _context14.finish(28);
1932
+ return _context13.finish(28);
1925
1933
  case 31:
1926
- return _context14.abrupt("return", null);
1934
+ return _context13.abrupt("return", null);
1927
1935
  case 32:
1928
1936
  case "end":
1929
- return _context14.stop();
1937
+ return _context13.stop();
1930
1938
  }
1931
- }, _callee14, null, [[1, 7], [12, 25, 28, 31]]);
1939
+ }, _callee13, null, [[1, 7], [12, 25, 28, 31]]);
1932
1940
  }));
1933
1941
  return _findFirstActiveAudioDevice.apply(this, arguments);
1934
1942
  }