I'm developing a React application to conduct webcam interviews with candidates, and I'm using the react-media-recorder package. However, I've encountered an issue. When I click on the handleStartRecording function, it triggers the startTimer() function, which is used to calculate the video recording time.
Unfortunately, this startTimer function is causing some problems. Specifically, it distorts the VideoFrame. I can't name the exact error, but what happens is that the webcam frame starts blinking and distorting. Interestingly, when I commented out the startTimer function within the handleStartRecording function, everything works ok.
I've attempted to solve this issue either by checking the recording status in the startTimer, but it seems that the timer runs a bit faster than the webcam.
import { useReactMediaRecorder } from 'react-media-recorder';
const VideoPreview = ({ stream }) => {
const videoRef = useRef(null);
useEffect(() => {
console.log(stream);
const videoElement = videoRef.current;
if (videoElement && stream) {
videoElement.srcObject = stream;
}
return () => {
if (videoElement) {
videoElement.srcObject = null;
}
};
}, [stream]);
if (!stream) {
return null;
}
const videoWidth = stream.getVideoTracks()[0].getSettings().width;
const videoHeight = stream.getVideoTracks()[0].getSettings().height;
const aspectRatio = videoWidth / videoHeight;
return (
<video
ref={videoRef}
autoPlay
style={{ width: '100%', height: `calc(100% / ${aspectRatio})`, objectFit: 'cover' }}
/>
);
};
const Index = (props) => {
const { status, startRecording, stopRecording, previewStream, mediaBlobUrl } = useReactMediaRecorder({ video: true });
let history = useHistory();
const [timer, setTimer] = useState(0);
const [video, setVideo] = useState(null);
const [isRecording, setIsRecording] = useState(false);
const [showStartAgain, setShowStartAgain] = useState(false);
const [isVideoComplete, setIsVideoComplete] = useState(false);
const timeIntervalRef = useRef(null);
const maxRecordingTime = 180;
const stopTimer = () => {
clearInterval(timeIntervalRef.current);
};
const formatTime = (seconds) => {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return `${minutes}:${remainingSeconds < 10 ? '0' : ''}${remainingSeconds}`;
};
const handleStopRecording = () => {
setIsVideoComplete(true);
setShowStartAgain(true);
stopTimer();
if (isRecording) {
setIsRecording(false);
setVideo(mediaBlobUrl);
stopRecording();
}
};
const startTimer = () => {
console.log(status !== 'idle' || status !== 'stopped' || status !== 'acquiring_media');
if (status !== 'idle' || status !== 'stopped' || status !== 'acquiring_media') {
setTimer(0);
timeIntervalRef.current = setInterval(() => {
setTimer((prevTimer) => {
if (prevTimer >= maxRecordingTime) {
clearInterval(timeIntervalRef.current);
handleStopRecording();
return prevTimer;
}
return prevTimer + 1;
});
}, 1000);
}
};
const handleStartRecording = () => {
setShowStartAgain(false);
setIsVideoComplete(false);
if (!isRecording) {
setIsRecording(true);
startRecording();
startTimer();
}
};
const handleCompleteRecording = () => {
setShowStartAgain(true);
if (video) {
sendVideo(video);
}
};
const handleStartAgain = () => {
stopRecording();
setIsVideoComplete(false);
setVideo(null);
setIsRecording(false);
stopTimer();
setTimer(0);
setShowStartAgain(false);
};
return (
<Grid container>
<Grid item xs={12} md={12} className={classes.recordingScreen}>
<div>
{isRecording ? (
<VideoPreview stream={previewStream} />
) : (
<video
src={mediaBlobUrl}
controls
// autoPlay
style={{
width: '100%',
height: 'auto',
objectFit: 'cover',
}}
/>
)}
{status}
</div>
</Grid>
</Grid>
);
};
const materialStyles = (theme) => ({
recordingScreen: {
margin: '1.875rem 0 1.875rem 0',
},
});
export default withStyles(materialStyles)(Index);