@bigbinary/neeto-media-recorder 2.7.56 → 2.7.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core.js CHANGED
@@ -1271,9 +1271,8 @@ var isMp4Supported = function isMp4Supported() {
1271
1271
  var mimeType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getSupportedMimeType();
1272
1272
  return mimeType.includes(MIME_TYPE.mp4);
1273
1273
  };
1274
- var addGainNode = function addGainNode(audioStream) {
1275
- var gain = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1.5;
1276
- var audioContext = new AudioContext();
1274
+ var addGainNode = function addGainNode(audioContext, audioStream) {
1275
+ var gain = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1.5;
1277
1276
  var audioStreamSource = audioContext.createMediaStreamSource(audioStream);
1278
1277
  var destinationStream = audioContext.createMediaStreamDestination();
1279
1278
  var gainNode = audioContext.createGain();
@@ -2113,6 +2112,7 @@ var _stopRecordingDueToLimitReachedAudio = /*#__PURE__*/new WeakMap();
2113
2112
  var _stream = /*#__PURE__*/new WeakMap();
2114
2113
  var _audioStream = /*#__PURE__*/new WeakMap();
2115
2114
  var _micAudioStream = /*#__PURE__*/new WeakMap();
2115
+ var _audioContexts = /*#__PURE__*/new WeakMap();
2116
2116
  var _timeLimit = /*#__PURE__*/new WeakMap();
2117
2117
  var _startRecordingTimeoutID = /*#__PURE__*/new WeakMap();
2118
2118
  var _enableNoiseCancellation = /*#__PURE__*/new WeakMap();
@@ -2123,6 +2123,8 @@ var _dataReceiving = /*#__PURE__*/new WeakMap();
2123
2123
  var _recordSystemAudio = /*#__PURE__*/new WeakMap();
2124
2124
  var _hasSpeechSourceForTitle = /*#__PURE__*/new WeakMap();
2125
2125
  var _stopAllStreams = /*#__PURE__*/new WeakMap();
2126
+ var _createAudioContext = /*#__PURE__*/new WeakMap();
2127
+ var _releaseAudio = /*#__PURE__*/new WeakMap();
2126
2128
  var _playCountdownBeep = /*#__PURE__*/new WeakMap();
2127
2129
  var _checkCompatibility = /*#__PURE__*/new WeakMap();
2128
2130
  var _acquireMediaStream = /*#__PURE__*/new WeakMap();
@@ -2140,6 +2142,9 @@ var _startTimer = /*#__PURE__*/new WeakMap();
2140
2142
  var _stopTimer = /*#__PURE__*/new WeakMap();
2141
2143
  var _checkIfTimeLimitReached = /*#__PURE__*/new WeakMap();
2142
2144
  var ScreenRecorder = /*#__PURE__*/function () {
2145
+ // Every AudioContext created for gain, noise suppression and mixing. Kept so
2146
+ // they can be closed when the streams stop instead of leaking per recording.
2147
+
2143
2148
  // Lets a host (e.g. the chrome extension) take over the countdown beeps and
2144
2149
  // recording-start chime so it can schedule them via Web Audio. Defaults to
2145
2150
  // true to preserve behavior for callers that don't manage audio themselves.
@@ -2223,6 +2228,10 @@ var ScreenRecorder = /*#__PURE__*/function () {
2223
2228
  writable: true,
2224
2229
  value: void 0
2225
2230
  });
2231
+ _classPrivateFieldInitSpec(this, _audioContexts, {
2232
+ writable: true,
2233
+ value: []
2234
+ });
2226
2235
  _classPrivateFieldInitSpec(this, _timeLimit, {
2227
2236
  writable: true,
2228
2237
  value: RECORDING_TIME_LIMIT_FREE_PLAN
@@ -2353,15 +2362,19 @@ var ScreenRecorder = /*#__PURE__*/function () {
2353
2362
  return _classPrivateFieldGet(_this, _acquireMediaStream).call(_this);
2354
2363
  case 6:
2355
2364
  if (!(_classPrivateFieldGet(_this, _mediaStream) && isStreamEnded(_classPrivateFieldGet(_this, _mediaStream)))) {
2356
- _context.next = 10;
2365
+ _context.next = 11;
2357
2366
  break;
2358
2367
  }
2359
2368
  _classPrivateFieldGet(_this, _logger).info("startRecording -> media stream ended, re-acquiring", _classPrivateFieldGet(_this, _summarizeStream).call(_this, _classPrivateFieldGet(_this, _mediaStream)));
2360
- _context.next = 10;
2369
+ // Re-acquiring opens a new mic stream, so release the old one first or
2370
+ // the previous mic stays in use. Only the audio side is released: an
2371
+ // injected videoStream is reused as-is by #acquireMediaStream.
2372
+ _classPrivateFieldGet(_this, _releaseAudio).call(_this);
2373
+ _context.next = 11;
2361
2374
  return _classPrivateFieldGet(_this, _acquireMediaStream).call(_this);
2362
- case 10:
2375
+ case 11:
2363
2376
  if (!(!_classPrivateFieldGet(_this, _mediaStream) || isStreamEnded(_classPrivateFieldGet(_this, _mediaStream)))) {
2364
- _context.next = 13;
2377
+ _context.next = 14;
2365
2378
  break;
2366
2379
  }
2367
2380
  _classPrivateFieldGet(_this, _logger).warn("startRecording -> aborting, media stream unavailable", {
@@ -2369,7 +2382,7 @@ var ScreenRecorder = /*#__PURE__*/function () {
2369
2382
  isEnded: _classPrivateFieldGet(_this, _mediaStream) ? isStreamEnded(_classPrivateFieldGet(_this, _mediaStream)) : true
2370
2383
  });
2371
2384
  return _context.abrupt("return");
2372
- case 13:
2385
+ case 14:
2373
2386
  options = getMediaRecorderOptions();
2374
2387
  _classPrivateFieldGet(_this, _logger).info("startRecording -> creating MediaRecorder", {
2375
2388
  options: options,
@@ -2377,13 +2390,13 @@ var ScreenRecorder = /*#__PURE__*/function () {
2377
2390
  stream: _classPrivateFieldGet(_this, _summarizeStream).call(_this, _classPrivateFieldGet(_this, _mediaStream))
2378
2391
  });
2379
2392
  _classPrivateFieldSet(_this, _mediaChunks, []);
2380
- _context.prev = 16;
2393
+ _context.prev = 17;
2381
2394
  _classPrivateFieldSet(_this, _mediaRecorder, new MediaRecorder(_classPrivateFieldGet(_this, _mediaStream), options));
2382
- _context.next = 25;
2395
+ _context.next = 26;
2383
2396
  break;
2384
- case 20:
2385
- _context.prev = 20;
2386
- _context.t0 = _context["catch"](16);
2397
+ case 21:
2398
+ _context.prev = 21;
2399
+ _context.t0 = _context["catch"](17);
2387
2400
  _classPrivateFieldGet(_this, _logger).error("startRecording -> failed to construct MediaRecorder", _classPrivateFieldGet(_this, _serializeError).call(_this, _context.t0), {
2388
2401
  options: options,
2389
2402
  mimeType: _classPrivateFieldGet(_this, _mimeType)
@@ -2393,7 +2406,7 @@ var ScreenRecorder = /*#__PURE__*/function () {
2393
2406
  error: SCREEN_RECORDER_ERROR.NoRecorder
2394
2407
  });
2395
2408
  return _context.abrupt("return");
2396
- case 25:
2409
+ case 26:
2397
2410
  _classPrivateFieldGet(_this, _logger).info("startRecording -> MediaRecorder created", {
2398
2411
  state: _classPrivateFieldGet(_this, _mediaRecorder).state,
2399
2412
  mimeType: _classPrivateFieldGet(_this, _mediaRecorder).mimeType,
@@ -2428,11 +2441,11 @@ var ScreenRecorder = /*#__PURE__*/function () {
2428
2441
  });
2429
2442
  _classPrivateFieldGet(_this, _startMediaRecorder).call(_this);
2430
2443
  }
2431
- case 31:
2444
+ case 32:
2432
2445
  case "end":
2433
2446
  return _context.stop();
2434
2447
  }
2435
- }, _callee, null, [[16, 20]]);
2448
+ }, _callee, null, [[17, 21]]);
2436
2449
  })));
2437
2450
  _defineProperty(this, "stopRecording", function () {
2438
2451
  var _classPrivateFieldGet5;
@@ -2578,7 +2591,7 @@ var ScreenRecorder = /*#__PURE__*/function () {
2578
2591
  _classPrivateFieldInitSpec(this, _stopAllStreams, {
2579
2592
  writable: true,
2580
2593
  value: function value() {
2581
- var _classPrivateFieldGet14, _classPrivateFieldGet15, _classPrivateFieldGet16, _classPrivateFieldGet17, _classPrivateFieldGet18, _classPrivateFieldGet19;
2594
+ var _classPrivateFieldGet14, _classPrivateFieldGet15;
2582
2595
  getFastTitleRunner().stop();
2583
2596
  _classPrivateFieldGet(_this, _logger).info("stopAllStreams", {
2584
2597
  mediaStream: _classPrivateFieldGet(_this, _summarizeStream).call(_this, _classPrivateFieldGet(_this, _mediaStream)),
@@ -2592,12 +2605,31 @@ var ScreenRecorder = /*#__PURE__*/function () {
2592
2605
  (_classPrivateFieldGet15 = _classPrivateFieldGet(_this, _stream)) === null || _classPrivateFieldGet15 === void 0 ? void 0 : _classPrivateFieldGet15.getTracks().forEach(function (track) {
2593
2606
  return track.stop();
2594
2607
  });
2608
+ _classPrivateFieldGet(_this, _releaseAudio).call(_this);
2609
+ }
2610
+ });
2611
+ _classPrivateFieldInitSpec(this, _createAudioContext, {
2612
+ writable: true,
2613
+ value: function value() {
2614
+ var audioContext = new AudioContext();
2615
+ _classPrivateFieldGet(_this, _audioContexts).push(audioContext);
2616
+ return audioContext;
2617
+ }
2618
+ });
2619
+ _classPrivateFieldInitSpec(this, _releaseAudio, {
2620
+ writable: true,
2621
+ value: function value() {
2622
+ var _classPrivateFieldGet16, _classPrivateFieldGet17, _classPrivateFieldGet18, _classPrivateFieldGet19;
2595
2623
  (_classPrivateFieldGet16 = _classPrivateFieldGet(_this, _audioStream)) === null || _classPrivateFieldGet16 === void 0 ? void 0 : (_classPrivateFieldGet17 = _classPrivateFieldGet16.getAudioTracks()) === null || _classPrivateFieldGet17 === void 0 ? void 0 : _classPrivateFieldGet17.forEach(function (track) {
2596
2624
  return track.stop();
2597
2625
  });
2598
2626
  (_classPrivateFieldGet18 = _classPrivateFieldGet(_this, _micAudioStream)) === null || _classPrivateFieldGet18 === void 0 ? void 0 : (_classPrivateFieldGet19 = _classPrivateFieldGet18.getAudioTracks()) === null || _classPrivateFieldGet19 === void 0 ? void 0 : _classPrivateFieldGet19.forEach(function (track) {
2599
2627
  return track.stop();
2600
2628
  });
2629
+ _classPrivateFieldGet(_this, _audioContexts).forEach(function (audioContext) {
2630
+ if (audioContext.state !== "closed") audioContext.close();
2631
+ });
2632
+ _classPrivateFieldSet(_this, _audioContexts, []);
2601
2633
  }
2602
2634
  });
2603
2635
  _classPrivateFieldInitSpec(this, _playCountdownBeep, {
@@ -2630,7 +2662,7 @@ var ScreenRecorder = /*#__PURE__*/function () {
2630
2662
  writable: true,
2631
2663
  value: function () {
2632
2664
  var _value = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
2633
- var acquireStartedAt, micState, stream, constraints, displayMediaStartedAt, audioConfig, micStartedAt, audioStream, workletUrl, workletStartedAt, audioContext, audioStreamSource, destinationStream, noiseSuppressorNode, finalStream, _audioContext, desktopAudio, microphoneAudio, combinedAudio;
2665
+ var acquireStartedAt, micState, stream, hasAcquiredMedia, constraints, displayMediaStartedAt, audioConfig, micStartedAt, audioStream, workletUrl, workletStartedAt, audioContext, audioStreamSource, destinationStream, noiseSuppressorNode, finalStream, _audioContext, desktopAudio, microphoneAudio, combinedAudio;
2634
2666
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
2635
2667
  while (1) switch (_context2.prev = _context2.next) {
2636
2668
  case 0:
@@ -2665,37 +2697,38 @@ var ScreenRecorder = /*#__PURE__*/function () {
2665
2697
  });
2666
2698
  return _context2.abrupt("return");
2667
2699
  case 11:
2668
- _context2.prev = 11;
2700
+ hasAcquiredMedia = false;
2701
+ _context2.prev = 12;
2669
2702
  if (!_classPrivateFieldGet(_this, _videoStream)) {
2670
- _context2.next = 17;
2703
+ _context2.next = 18;
2671
2704
  break;
2672
2705
  }
2673
2706
  _classPrivateFieldGet(_this, _logger).info("acquireMediaStream -> using injected videoStream", _classPrivateFieldGet(_this, _summarizeStream).call(_this, _classPrivateFieldGet(_this, _videoStream)));
2674
2707
  stream = _classPrivateFieldGet(_this, _videoStream);
2675
- _context2.next = 25;
2708
+ _context2.next = 26;
2676
2709
  break;
2677
- case 17:
2710
+ case 18:
2678
2711
  constraints = {
2679
2712
  video: _classPrivateFieldGet(_this, _video),
2680
2713
  audio: _classPrivateFieldGet(_this, _recordSystemAudio)
2681
2714
  };
2682
2715
  _classPrivateFieldGet(_this, _logger).info("acquireMediaStream -> getDisplayMedia constraints", constraints);
2683
2716
  displayMediaStartedAt = Date.now();
2684
- _context2.next = 22;
2717
+ _context2.next = 23;
2685
2718
  return window.navigator.mediaDevices.getDisplayMedia(constraints);
2686
- case 22:
2719
+ case 23:
2687
2720
  stream = _context2.sent;
2688
2721
  _classPrivateFieldGet(_this, _logger).info("acquireMediaStream -> getDisplayMedia resolved", {
2689
2722
  durationMs: Date.now() - displayMediaStartedAt,
2690
2723
  stream: _classPrivateFieldGet(_this, _summarizeStream).call(_this, stream)
2691
2724
  });
2692
2725
  _classPrivateFieldGet(_this, _fireCallbacks).call(_this, SCREEN_RECORDER_EVENT.onShareSelected);
2693
- case 25:
2726
+ case 26:
2694
2727
  if (!_classPrivateFieldGet(_this, _audio)) {
2695
- _context2.next = 68;
2728
+ _context2.next = 69;
2696
2729
  break;
2697
2730
  }
2698
- _context2.prev = 26;
2731
+ _context2.prev = 27;
2699
2732
  audioConfig = {
2700
2733
  audio: _objectSpread(_objectSpread({
2701
2734
  echoCancellation: false
@@ -2710,31 +2743,31 @@ var ScreenRecorder = /*#__PURE__*/function () {
2710
2743
  _context2.t0 = _classPrivateFieldSet;
2711
2744
  _context2.t1 = _this;
2712
2745
  _context2.t2 = _micAudioStream;
2713
- _context2.next = 35;
2746
+ _context2.next = 36;
2714
2747
  return window.navigator.mediaDevices.getUserMedia(audioConfig);
2715
- case 35:
2748
+ case 36:
2716
2749
  _context2.t3 = _context2.sent;
2717
2750
  (0, _context2.t0)(_context2.t1, _context2.t2, _context2.t3);
2718
2751
  _classPrivateFieldGet(_this, _logger).info("acquireMediaStream -> mic acquired", {
2719
2752
  durationMs: Date.now() - micStartedAt,
2720
2753
  stream: _classPrivateFieldGet(_this, _summarizeStream).call(_this, _classPrivateFieldGet(_this, _micAudioStream))
2721
2754
  });
2722
- audioStream = addGainNode(_classPrivateFieldGet(_this, _micAudioStream), 1.75); // Increase volume by 50%
2755
+ audioStream = addGainNode(_classPrivateFieldGet(_this, _createAudioContext).call(_this), _classPrivateFieldGet(_this, _micAudioStream), 1.75); // Increase volume by 50%
2723
2756
  _classPrivateFieldSet(_this, _audioStream, audioStream);
2724
2757
  if (!_classPrivateFieldGet(_this, _enableNoiseCancellation)) {
2725
- _context2.next = 60;
2758
+ _context2.next = 61;
2726
2759
  break;
2727
2760
  }
2728
- _context2.prev = 41;
2761
+ _context2.prev = 42;
2729
2762
  workletUrl = IS_EXTENSION ? chrome.runtime.getURL("public/NoiseSuppressorWorklet.js") : "NoiseSuppressorWorklet.js";
2730
2763
  _classPrivateFieldGet(_this, _logger).info("acquireMediaStream -> loading noise suppressor worklet", {
2731
2764
  workletUrl: workletUrl
2732
2765
  });
2733
2766
  workletStartedAt = Date.now();
2734
- audioContext = new AudioContext();
2735
- _context2.next = 48;
2767
+ audioContext = _classPrivateFieldGet(_this, _createAudioContext).call(_this);
2768
+ _context2.next = 49;
2736
2769
  return audioContext.audioWorklet.addModule(workletUrl);
2737
- case 48:
2770
+ case 49:
2738
2771
  audioStreamSource = audioContext.createMediaStreamSource(audioStream);
2739
2772
  destinationStream = audioContext.createMediaStreamDestination();
2740
2773
  noiseSuppressorNode = new AudioWorkletNode(audioContext, "nn-suppressor-processor");
@@ -2744,18 +2777,18 @@ var ScreenRecorder = /*#__PURE__*/function () {
2744
2777
  _classPrivateFieldGet(_this, _logger).info("acquireMediaStream -> noise suppressor wired up", {
2745
2778
  durationMs: Date.now() - workletStartedAt
2746
2779
  });
2747
- _context2.next = 60;
2780
+ _context2.next = 61;
2748
2781
  break;
2749
- case 57:
2750
- _context2.prev = 57;
2751
- _context2.t4 = _context2["catch"](41);
2782
+ case 58:
2783
+ _context2.prev = 58;
2784
+ _context2.t4 = _context2["catch"](42);
2752
2785
  _classPrivateFieldGet(_this, _logger).error("acquireMediaStream -> failed to load audio worklet", _classPrivateFieldGet(_this, _serializeError).call(_this, _context2.t4));
2753
- case 60:
2754
- _context2.next = 68;
2786
+ case 61:
2787
+ _context2.next = 69;
2755
2788
  break;
2756
- case 62:
2757
- _context2.prev = 62;
2758
- _context2.t5 = _context2["catch"](26);
2789
+ case 63:
2790
+ _context2.prev = 63;
2791
+ _context2.t5 = _context2["catch"](27);
2759
2792
  // Mic access can fail independently of screen capture (OS-level
2760
2793
  // block, no device, deviceId mismatch). Stop the screen stream and
2761
2794
  // surface a mic-only error so the user sees the proper callout
@@ -2775,7 +2808,7 @@ var ScreenRecorder = /*#__PURE__*/function () {
2775
2808
  status: SCREEN_RECORDER_STATUS.idle
2776
2809
  });
2777
2810
  return _context2.abrupt("return");
2778
- case 68:
2811
+ case 69:
2779
2812
  // Fired when capture ends without the app calling stop() — the browser's
2780
2813
  // "Stop sharing" pill or an OS-level termination. When a consumer is
2781
2814
  // listening for onUnexpectedEnd, hand the decision (finish/discard, show
@@ -2800,7 +2833,7 @@ var ScreenRecorder = /*#__PURE__*/function () {
2800
2833
  if (_classPrivateFieldGet(_this, _audio) && _classPrivateFieldGet(_this, _audioStream)) {
2801
2834
  if (isNotEmpty(stream.getAudioTracks())) {
2802
2835
  _classPrivateFieldGet(_this, _logger).info("acquireMediaStream -> mixing system audio + mic");
2803
- _audioContext = new AudioContext();
2836
+ _audioContext = _classPrivateFieldGet(_this, _createAudioContext).call(_this);
2804
2837
  desktopAudio = _audioContext.createMediaStreamSource(stream);
2805
2838
  microphoneAudio = _audioContext.createMediaStreamSource(_classPrivateFieldGet(_this, _audioStream));
2806
2839
  combinedAudio = _audioContext.createMediaStreamDestination();
@@ -2828,6 +2861,7 @@ var ScreenRecorder = /*#__PURE__*/function () {
2828
2861
  });
2829
2862
  _classPrivateFieldSet(_this, _mediaStream, finalStream);
2830
2863
  _classPrivateFieldSet(_this, _stream, stream);
2864
+ hasAcquiredMedia = true;
2831
2865
  _classPrivateFieldGet(_this, _store).setState({
2832
2866
  status: SCREEN_RECORDER_STATUS.media_acquired
2833
2867
  });
@@ -2835,11 +2869,11 @@ var ScreenRecorder = /*#__PURE__*/function () {
2835
2869
  totalDurationMs: Date.now() - acquireStartedAt,
2836
2870
  finalStream: _classPrivateFieldGet(_this, _summarizeStream).call(_this, _classPrivateFieldGet(_this, _mediaStream))
2837
2871
  });
2838
- _context2.next = 82;
2872
+ _context2.next = 85;
2839
2873
  break;
2840
- case 78:
2841
- _context2.prev = 78;
2842
- _context2.t6 = _context2["catch"](11);
2874
+ case 80:
2875
+ _context2.prev = 80;
2876
+ _context2.t6 = _context2["catch"](12);
2843
2877
  _classPrivateFieldGet(_this, _logger).error("acquireMediaStream -> error", _classPrivateFieldGet(_this, _serializeError).call(_this, _context2.t6), {
2844
2878
  totalDurationMs: Date.now() - acquireStartedAt,
2845
2879
  hasAudio: Boolean(_classPrivateFieldGet(_this, _audio)),
@@ -2862,11 +2896,27 @@ var ScreenRecorder = /*#__PURE__*/function () {
2862
2896
  status: SCREEN_RECORDER_STATUS.idle
2863
2897
  });
2864
2898
  }
2865
- case 82:
2899
+
2900
+ // A failure after the display/mic were opened but before they were
2901
+ // handed to #mediaStream leaves them running with nothing to stop them,
2902
+ // keeping the mic in use. Release them here, after the error checks
2903
+ // above have read #audioStream. An injected videoStream is owned by the
2904
+ // caller, so it is left alone.
2905
+ if (!hasAcquiredMedia) {
2906
+ if (stream && stream !== _classPrivateFieldGet(_this, _videoStream)) {
2907
+ stream.getTracks().forEach(function (track) {
2908
+ return track.stop();
2909
+ });
2910
+ }
2911
+ _classPrivateFieldGet(_this, _releaseAudio).call(_this);
2912
+ _classPrivateFieldSet(_this, _audioStream, null);
2913
+ _classPrivateFieldSet(_this, _micAudioStream, null);
2914
+ }
2915
+ case 85:
2866
2916
  case "end":
2867
2917
  return _context2.stop();
2868
2918
  }
2869
- }, _callee2, null, [[11, 78], [26, 62], [41, 57]]);
2919
+ }, _callee2, null, [[12, 80], [27, 63], [42, 58]]);
2870
2920
  }));
2871
2921
  function value() {
2872
2922
  return _value.apply(this, arguments);