diff --git a/package.json b/package.json index 7948ced6..95b5bdbf 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,9 @@ "canvas-confetti": "^1.9.2", "character-error-rate": "^1.1.4", "classnames": "^2.3.1", + "eslint-plugin-import": "^2.28.0", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.1", "faker": "^5.5.3", "homophones": "^1.0.1", "jwt-decode": "^4.0.0", @@ -38,15 +41,13 @@ "react-virtualized": "^9.22.3", "react-virtualized-auto-sizer": "^1.0.6", "react-window": "^1.8.6", + "recordrtc": "^5.6.2", "redux": "^4.1.2", "redux-saga": "^1.1.3", "sass": "^1.44.0", "split-graphemes": "^0.5.0", "use-sound": "^4.0.1", - "web-vitals": "^2.1.4", - "eslint-plugin-import": "^2.28.0", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-react": "^7.33.1" + "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", @@ -87,16 +88,16 @@ ] }, "devDependencies": { + "@mui/styles": "^5.15.10", "eslint": "^7.32.0", - "prettier": "^2.3.2", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^3.4.0", "husky": "^9.0.11", "lint-staged": "^11.0.0", - "react": "^18.2.0", - "@mui/styles": "^5.15.10" + "prettier": "^2.3.2", + "react": "^18.2.0" }, - "lint-staged": { + "lint-staged": { "src/**/*.{js,jsx}": [ "npx eslint --fix", "npx prettier --write" diff --git a/src/utils/AudioCompare.js b/src/utils/AudioCompare.js index 90f38655..8caacbca 100644 --- a/src/utils/AudioCompare.js +++ b/src/utils/AudioCompare.js @@ -1,87 +1,104 @@ -import React, { useState } from "react"; -import AudioAnalyser from "react-audio-analyser"; +import React, { useState, useEffect, useRef } from "react"; +import RecordRTC from "recordrtc"; import { Box } from "@mui/material"; import { ListenButton, RetryIcon, SpeakButton, StopButton } from "./constants"; import RecordVoiceVisualizer from "./RecordVoiceVisualizer"; -import useAudioDetection from "./useAudioDetection"; -const AudioRecorderCompair = (props) => { - const { startDetection, stopDetection, isSilent, isRunning, audioDetected } = useAudioDetection(); +const AudioRecorder = (props) => { + const [isRecording, setIsRecording] = useState(false); const [status, setStatus] = useState(""); - const [audioSrc, setAudioSrc] = useState(""); - const [recordingInitialized, setRecordingInitialized] = useState(false); - const audioType = "audio/wav"; + const [audioBlob, setAudioBlob] = useState(null); + const recorderRef = useRef(null); + const mediaStreamRef = useRef(null); - const controlAudio = async (status) => { - if (status === "recording") { - await startDetection(); - } else { - stopDetection(); - } - setStatus(status); - }; - - const resetRecording = () => { - setAudioSrc(""); - setRecordingInitialized(false); - }; + useEffect(() => { + // Cleanup when component unmounts + return () => { + if (recorderRef.current) { + recorderRef.current.destroy(); + } + if (mediaStreamRef.current) { + mediaStreamRef.current.getTracks().forEach((track) => track.stop()); + } + }; + }, []); - const handleMic = async () => { + const startRecording = async () => { + setStatus("recording"); if (props.setEnableNext) { props.setEnableNext(false); } - document.getElementById("startaudio_compair").click(); - resetRecording(); + try { + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + mediaStreamRef.current = stream; + + // Use RecordRTC with specific configurations to match the blob structure + recorderRef.current = new RecordRTC(stream, { + type: "audio", + mimeType: "audio/wav", // Ensuring the same MIME type as AudioRecorderCompair + recorderType: RecordRTC.StereoAudioRecorder, // Use StereoAudioRecorder for better compatibility + numberOfAudioChannels: 1, // Match the same number of audio channels + desiredSampRate: 16000, // Adjust the sample rate if necessary to match + }); + + recorderRef.current.startRecording(); + + setIsRecording(true); + } catch (err) { + console.error("Failed to start recording:", err); + } }; - const handleStop = () => { + const stopRecording = () => { + setStatus("inactive"); + if (recorderRef.current) { + recorderRef.current.stopRecording(() => { + const blob = recorderRef.current.getBlob(); + + if (blob) { + setAudioBlob(blob); + saveBlob(blob); // Persist the blob + } else { + console.error("Failed to retrieve audio blob."); + } + + // Stop the media stream + if (mediaStreamRef.current) { + mediaStreamRef.current.getTracks().forEach((track) => track.stop()); + } + + setIsRecording(false); + }); + } if (props.setEnableNext) { props.setEnableNext(true); } - document.getElementById("stopaudio_compair").click(); }; - const audioProps = { - audioType, - status, - audioSrc, - timeslice: 1000, - startCallback: (e) => { - setAudioSrc(""); - setRecordingInitialized(true); - props.setRecordedAudio(""); - }, - pauseCallback: (e) => {}, - stopCallback: (e) => { - const temp_audioSrc = window.URL.createObjectURL(e); - setAudioSrc(temp_audioSrc); - if (!audioDetected) { - props?.setOpenMessageDialog({ - message: "Please Speak Louder and Clear", - isError: true, - }); - if (props.setEnableNext) { - props.setEnableNext(false); - } - } else { - props.setRecordedAudio(temp_audioSrc); - } - setRecordingInitialized(false); - }, - onRecordCallback: (e) => {}, - errorCallback: (err) => {}, - backgroundColor: "hsla(0, 100%, 0%, 0)", - strokeColor: "#73DD24", + const saveBlob = (blob) => { + const url = window.URL.createObjectURL(blob); + props?.setRecordedAudio(url); }; return (