@bigbinary/neeto-media-recorder 2.7.6 → 2.7.8

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/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { shallow } from 'zustand/shallow';
2
- import { useEffect, useState, forwardRef, useRef, useImperativeHandle } from 'react';
2
+ import { useState, useRef, useCallback, useEffect, forwardRef, useImperativeHandle } from 'react';
3
3
  import classNames from 'classnames';
4
4
  import { isNotEmpty, noop } from '@bigbinary/neeto-cist';
5
- import { SCREEN_RECORDER_STATUS, UPLOAD_STATUS as UPLOAD_STATUS$1, ONE_SECOND_IN_MILLISECONDS as ONE_SECOND_IN_MILLISECONDS$1, MIME_TYPE as MIME_TYPE$1, ONE_MINUTE_IN_MILLISECONDS as ONE_MINUTE_IN_MILLISECONDS$1, IS_EXTENSION as IS_EXTENSION$1, SCREEN_RECORDER_ERROR, IS_SAFARI_EXTENSION, SCREEN_RECORDER_EVENT, UPLOAD_EVENT } from '@bigbinary/neeto-media-recorder/constants';
5
+ import { SCREEN_RECORDER_STATUS, UPLOAD_STATUS as UPLOAD_STATUS$1, ONE_SECOND_IN_MILLISECONDS as ONE_SECOND_IN_MILLISECONDS$1, MIME_TYPE as MIME_TYPE$1, ONE_MINUTE_IN_MILLISECONDS as ONE_MINUTE_IN_MILLISECONDS$1, IS_EXTENSION as IS_EXTENSION$1, SCREEN_RECORDER_ERROR, IS_SAFARI_EXTENSION, MIC_NOT_WORKING_SILENCE_TIMEOUT, SCREEN_RECORDER_EVENT, UPLOAD_EVENT } from '@bigbinary/neeto-media-recorder/constants';
6
6
  import { screenRecorder, useMultipartS3UploadStatus, getMultipartS3Uploader } from '@bigbinary/neeto-media-recorder/core';
7
7
  import PageLoader from '@bigbinary/neeto-molecules/PageLoader';
8
8
  import Alert from '@bigbinary/neetoui/Alert';
@@ -512,7 +512,6 @@ var MIME_TYPE = {
512
512
  mp4: "video/mp4",
513
513
  webmH264: "video/webm;codecs=h264"
514
514
  };
515
- // 2 hours
516
515
 
517
516
  var getSupportedMimeType = function getSupportedMimeType() {
518
517
  return MIME_TYPE.webmH264;
@@ -921,6 +920,177 @@ var Controls = function Controls(_ref) {
921
920
  });
922
921
  };
923
922
 
923
+ var getAnalyser = function getAnalyser() {
924
+ var _screenRecorder$getAu;
925
+ var stream = (_screenRecorder$getAu = screenRecorder.getAudioStream) === null || _screenRecorder$getAu === void 0 ? void 0 : _screenRecorder$getAu.call(screenRecorder);
926
+ if (!stream) return null;
927
+ var ctx = new (window.AudioContext || window.webkitAudioContext)();
928
+ var source = ctx.createMediaStreamSource(stream);
929
+ var analyser = ctx.createAnalyser();
930
+ analyser.fftSize = 2048;
931
+ source.connect(analyser);
932
+ var data = new Uint8Array(analyser.fftSize);
933
+ return {
934
+ ctx: ctx,
935
+ source: source,
936
+ analyser: analyser,
937
+ data: data
938
+ };
939
+ };
940
+ var hasChrome = typeof chrome !== "undefined" && chrome.runtime && chrome.runtime.onMessage;
941
+ var useAudioIsCapturing = function useAudioIsCapturing(_ref) {
942
+ var isMicOn = _ref.isMicOn;
943
+ var _useState = useState(true),
944
+ _useState2 = _slicedToArray(_useState, 2),
945
+ hasAudio = _useState2[0],
946
+ setHasAudio = _useState2[1];
947
+ var _useState3 = useState(false),
948
+ _useState4 = _slicedToArray(_useState3, 2),
949
+ disable = _useState4[0],
950
+ setDisable = _useState4[1];
951
+ var _useState5 = useState(false),
952
+ _useState6 = _slicedToArray(_useState5, 2),
953
+ timerStarted = _useState6[0],
954
+ setTimerStarted = _useState6[1];
955
+ var timerRef = useRef(null);
956
+ var remainingRef = useRef(MIC_NOT_WORKING_SILENCE_TIMEOUT);
957
+ var startedAtRef = useRef(null);
958
+ var clearTimer = function clearTimer() {
959
+ if (timerRef.current) clearTimeout(timerRef.current);
960
+ timerRef.current = null;
961
+ };
962
+ var armTimer = function armTimer() {
963
+ if (timerRef.current || !timerStarted) return;
964
+ logger.info("useAudioIsCapturing new timer");
965
+ startedAtRef.current = Date.now();
966
+ timerRef.current = setTimeout(function () {
967
+ return setHasAudio(false);
968
+ }, remainingRef.current);
969
+ };
970
+ var pauseTimer = function pauseTimer() {
971
+ if (!timerRef.current) return;
972
+ var elapsed = Date.now() - startedAtRef.current;
973
+ remainingRef.current = Math.max(0, remainingRef.current - elapsed);
974
+ clearTimer();
975
+ };
976
+ var resumeTimer = function resumeTimer() {
977
+ if (timerRef.current || !timerStarted || disable) return;
978
+ logger.info("useAudioIsCapturing resumeTimer");
979
+ startedAtRef.current = Date.now();
980
+ timerRef.current = setTimeout(function () {
981
+ return setHasAudio(false);
982
+ }, remainingRef.current);
983
+ };
984
+ var reset = useCallback(function () {
985
+ logger.info("useAudioIsCapturing reset");
986
+ clearTimer();
987
+ remainingRef.current = MIC_NOT_WORKING_SILENCE_TIMEOUT;
988
+ setTimerStarted(false);
989
+ setHasAudio(true);
990
+ }, []);
991
+
992
+ // Listen for Chrome extension messages
993
+ useEffect(function () {
994
+ var handleMessage = function handleMessage(message) {
995
+ if (!(message.type === "IGNORE_AUDIO_NOT_CAPTURING")) return;
996
+ logger.info("useAudioIsCapturing -> IGNORE_AUDIO_NOT_CAPTURING received");
997
+ setDisable(true);
998
+ };
999
+
1000
+ // Check if we're in a Chrome extension context
1001
+ if (hasChrome) {
1002
+ chrome.runtime.onMessage.addListener(handleMessage);
1003
+ }
1004
+ return function () {
1005
+ if (hasChrome) {
1006
+ var _chrome, _chrome$runtime, _chrome$runtime$onMes;
1007
+ (_chrome = chrome) === null || _chrome === void 0 ? void 0 : (_chrome$runtime = _chrome.runtime) === null || _chrome$runtime === void 0 ? void 0 : (_chrome$runtime$onMes = _chrome$runtime.onMessage) === null || _chrome$runtime$onMes === void 0 ? void 0 : _chrome$runtime$onMes.removeListener(handleMessage);
1008
+ }
1009
+ };
1010
+ }, []);
1011
+ useEffect(function () {
1012
+ if (!isMicOn || !timerStarted || disable) return noop;
1013
+ var analyserObj = null;
1014
+ var rafId;
1015
+ var loop = function loop() {
1016
+ if (!analyserObj) analyserObj = getAnalyser();
1017
+ // if no stream yet or analyser failed, treat as silence
1018
+ var isSilent = !analyserObj ? true : function () {
1019
+ analyserObj.analyser.getByteTimeDomainData(analyserObj.data);
1020
+ return analyserObj.data.every(function (v) {
1021
+ return v === 128;
1022
+ }); // absolute silence
1023
+ }();
1024
+
1025
+ if (isSilent) {
1026
+ armTimer();
1027
+ } else {
1028
+ clearTimer();
1029
+ remainingRef.current = MIC_NOT_WORKING_SILENCE_TIMEOUT;
1030
+ if (!hasAudio) setHasAudio(true);
1031
+ }
1032
+ rafId = requestAnimationFrame(loop);
1033
+ };
1034
+ loop();
1035
+ return function () {
1036
+ cancelAnimationFrame(rafId);
1037
+ clearTimer();
1038
+ if (analyserObj) {
1039
+ analyserObj.source.disconnect();
1040
+ analyserObj.ctx.close();
1041
+ }
1042
+ };
1043
+ }, [timerStarted, hasAudio, isMicOn, disable]);
1044
+ useEffect(function () {
1045
+ var _callbacks;
1046
+ if (!isMicOn) return noop;
1047
+ var callbacks = (_callbacks = {}, _defineProperty(_callbacks, SCREEN_RECORDER_EVENT.onStart, function () {
1048
+ reset();
1049
+ setTimerStarted(true);
1050
+ armTimer();
1051
+ }), _defineProperty(_callbacks, SCREEN_RECORDER_EVENT.onRestart, function () {
1052
+ reset();
1053
+ setTimerStarted(true);
1054
+ armTimer();
1055
+ }), _defineProperty(_callbacks, SCREEN_RECORDER_EVENT.onResume, function () {
1056
+ setTimerStarted(true);
1057
+ resumeTimer();
1058
+ }), _defineProperty(_callbacks, SCREEN_RECORDER_EVENT.onPause, function () {
1059
+ pauseTimer();
1060
+ }), _defineProperty(_callbacks, SCREEN_RECORDER_EVENT.onStop, function () {
1061
+ clearTimer();
1062
+ reset();
1063
+ }), _defineProperty(_callbacks, "disable-mic-not-working-warning", function disableMicNotWorkingWarning() {
1064
+ logger.info("useAudioIsCapturing -> disable-mic-not-working-warning");
1065
+ setDisable(true);
1066
+ setTimeout(function () {
1067
+ clearTimer();
1068
+ reset();
1069
+ }, 500);
1070
+ }), _callbacks);
1071
+ // start straight a way.
1072
+ callbacks[SCREEN_RECORDER_EVENT.onStart]();
1073
+ Object.entries(callbacks).forEach(function (_ref2) {
1074
+ var _ref3 = _slicedToArray(_ref2, 2),
1075
+ ev = _ref3[0],
1076
+ fn = _ref3[1];
1077
+ return screenRecorder.addCallback(ev, fn);
1078
+ });
1079
+ return function () {
1080
+ Object.entries(callbacks).forEach(function (_ref4) {
1081
+ var _ref5 = _slicedToArray(_ref4, 2),
1082
+ ev = _ref5[0],
1083
+ fn = _ref5[1];
1084
+ return screenRecorder.removeCallback(ev, fn);
1085
+ });
1086
+ };
1087
+ }, [isMicOn, reset]);
1088
+ return {
1089
+ hasAudio: hasAudio,
1090
+ reset: reset
1091
+ };
1092
+ };
1093
+
924
1094
  var useHandleErrors = function useHandleErrors(_ref) {
925
1095
  var error = _ref.error,
926
1096
  recorderStatus = _ref.recorderStatus;
@@ -1286,7 +1456,13 @@ var MediaRecorder = function MediaRecorder(_ref, ref) {
1286
1456
  appName = _ref$appName === void 0 ? globalProps.appName : _ref$appName,
1287
1457
  _ref$mimeType = _ref.mimeType,
1288
1458
  mimeType = _ref$mimeType === void 0 ? getSupportedMimeType() : _ref$mimeType,
1289
- folderId = _ref.folderId;
1459
+ folderId = _ref.folderId,
1460
+ _ref$isMicOn = _ref.isMicOn,
1461
+ isMicOn = _ref$isMicOn === void 0 ? false : _ref$isMicOn,
1462
+ _ref$onAudioNotCaptur = _ref.onAudioNotCapturing,
1463
+ onAudioNotCapturing = _ref$onAudioNotCaptur === void 0 ? function () {} : _ref$onAudioNotCaptur,
1464
+ _ref$onError = _ref.onError,
1465
+ onError = _ref$onError === void 0 ? function () {} : _ref$onError;
1290
1466
  var _useTranslation = useTranslation(),
1291
1467
  t = _useTranslation.t;
1292
1468
  var _useState = useState(false),
@@ -1306,6 +1482,18 @@ var MediaRecorder = function MediaRecorder(_ref, ref) {
1306
1482
  isRetryUpload = _useState8[0],
1307
1483
  setIsRetryUpload = _useState8[1];
1308
1484
  var recordingRef = useRef({});
1485
+ var _useAudioIsCapturing = useAudioIsCapturing({
1486
+ isMicOn: isMicOn
1487
+ }),
1488
+ hasAudio = _useAudioIsCapturing.hasAudio,
1489
+ reset = _useAudioIsCapturing.reset;
1490
+ useEffect(function () {
1491
+ if (hasAudio) return;
1492
+ onAudioNotCapturing();
1493
+ setTimeout(function () {
1494
+ reset();
1495
+ }, 1000);
1496
+ }, [hasAudio]);
1309
1497
 
1310
1498
  /**
1311
1499
  * @type {React.RefObject<Promise<unknown> | null>}
@@ -1359,6 +1547,16 @@ var MediaRecorder = function MediaRecorder(_ref, ref) {
1359
1547
  _useCreateRecording$d2 = _useCreateRecording$d === void 0 ? {} : _useCreateRecording$d,
1360
1548
  _useCreateRecording$d3 = _useCreateRecording$d2.recording,
1361
1549
  recording = _useCreateRecording$d3 === void 0 ? {} : _useCreateRecording$d3;
1550
+ useEffect(function () {
1551
+ var elapsedTimeInSec = Math.round(elapsedTime / 1000);
1552
+ var checkDelay = 7; // we get data every 5 sec, 7 for safety
1553
+ // If data is insufficient after n secs, there is some issue with media recorder, discard.
1554
+ if (elapsedTimeInSec < checkDelay) return;
1555
+ if (!screenRecorder.hasData() && recorderStatus === SCREEN_RECORDER_STATUS.recording) {
1556
+ screenRecorder.setError(SCREEN_RECORDER_ERROR.InsufficientData);
1557
+ onError(SCREEN_RECORDER_ERROR.InsufficientData);
1558
+ }
1559
+ }, [elapsedTime]);
1362
1560
  recordingRef.current = recording;
1363
1561
  var handleCreateRecording = /*#__PURE__*/function () {
1364
1562
  var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
@@ -1588,7 +1786,12 @@ var MediaRecorder = function MediaRecorder(_ref, ref) {
1588
1786
  className: "flex h-screen w-full flex-col items-center justify-start py-10 xl:py-14 2xl:py-20",
1589
1787
  children: [/*#__PURE__*/jsxs("div", {
1590
1788
  className: classNames("w-full max-w-3xl"),
1591
- children: [/*#__PURE__*/jsx(UseDesktopAppCallout, {}), error === SCREEN_RECORDER_ERROR.NotAllowedError && /*#__PURE__*/jsxs("div", {
1789
+ children: [/*#__PURE__*/jsx(UseDesktopAppCallout, {}), error === SCREEN_RECORDER_ERROR.InsufficientData && /*#__PURE__*/jsx(Callout, {
1790
+ className: "mb-2 p-3",
1791
+ "data-cy": "recorder-insufficient-data-error-callout",
1792
+ style: "danger",
1793
+ children: t("neetoMediaRecorder.insufficientDataError")
1794
+ }), error === SCREEN_RECORDER_ERROR.NotAllowedError && /*#__PURE__*/jsxs("div", {
1592
1795
  className: "flex flex-col items-center",
1593
1796
  children: [/*#__PURE__*/jsx(Typography, {
1594
1797
  className: "mb-2",