React Timer Distorting the Video Recording Frame

50 Views Asked by At

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. Distorted VideoFrame 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);
0

There are 0 best solutions below