react-use#useRafLoop TypeScript Examples

The following examples show how to use react-use#useRafLoop. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: MediaStream.tsx    From back-home-safe with GNU General Public License v3.0 4 votes vote down vote up
MediaStream = ({ onFrame, suppressError = false }: Props) => {
  const { t } = useTranslation("qr_reader");
  const { preferredCameraId } = useCamera();
  const [showUnSupportErrorModal, setShowUnSupportErrorModal] = useState(false);
  const [showCameraActivationErrorModal, setShowCameraActivationErrorModal] =
    useState(false);

  const videoRef = useRef<HTMLVideoElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);

  const [loopStop, loopStart] = useRafLoop(() => {
    const canvasElement = canvasRef.current;
    const videoElement = videoRef.current;

    if (
      canvasElement &&
      videoElement &&
      videoElement.readyState === videoElement.HAVE_ENOUGH_DATA
    ) {
      const canvas = canvasElement.getContext("2d");
      if (!canvas) return;

      canvasElement.height = videoElement.videoHeight;
      canvasElement.width = videoElement.videoWidth;
      canvas.drawImage(
        videoElement,
        0,
        0,
        canvasElement.width,
        canvasElement.height
      );

      const imageData = canvas.getImageData(
        0,
        0,
        canvasElement.width,
        canvasElement.height
      );

      onFrame && onFrame(imageData);
    }
  }, false);

  const initMediaStream = useCallback(async () => {
    const videoElement = videoRef.current;
    if (!videoElement) return;
    try {
      const stream = await getMediaStream(
        preferredCameraId === "AUTO" ? undefined : preferredCameraId
      );

      if (!stream) return;
      videoElement.srcObject = stream;
      videoElement.play();
      loopStart();
    } catch (e) {
      if (e instanceof Error) {
        switch (e.message) {
          case mediaStreamErrorType.GET_USER_MEDIA_NOT_FOUND:
            setShowUnSupportErrorModal(true);
            break;
          case mediaStreamErrorType.CAMERA_ACTIVATE_ERROR:
            if (suppressError) return;
            setShowCameraActivationErrorModal(true);
            break;
          default:
            console.error(e);
        }
      }
    }
  }, [loopStart, preferredCameraId, suppressError]);

  useEffect(() => {
    const videoElement = videoRef.current;
    initMediaStream();

    return () => {
      loopStop();
      if (videoElement) {
        const stream = videoElement.srcObject as MediaStream | null;
        if (!stream) return;
        const tracks = stream.getTracks();

        tracks.forEach((track) => {
          track.stop();
        });

        videoElement.srcObject = null;
      }
    };
  }, [loopStart, loopStop, videoRef, initMediaStream, preferredCameraId]);

  return (
    <>
      <Video ref={videoRef} playsInline />
      <Canvas ref={canvasRef} />
      <Dialog
        open={showUnSupportErrorModal}
        keepMounted
        aria-labelledby="unsupported-device-title"
        aria-describedby="unsupported-device-description"
      >
        <DialogTitle id="unsupported-device-title">不支援的裝置</DialogTitle>
        <DialogContent>
          <DialogContentText id="unsupported-device-description">
            {t("message.doesnt_support_get_user_media")}
            {isIOS && <>{t("message.sure_latest_ios")}</>}
          </DialogContentText>
        </DialogContent>
        <DialogActions>
          <Link to="/">
            <Button color="primary">{t("button.back_home")}</Button>
          </Link>
        </DialogActions>
      </Dialog>
      <Dialog
        open={showCameraActivationErrorModal}
        keepMounted
        aria-labelledby="camera-activation-title"
        aria-describedby="camera-activation-description"
      >
        <DialogTitle id="camera-activation-title">
          {t("dialog.cannot_open_camera.title")}
        </DialogTitle>
        <DialogContent>
          <DialogContentText id="camera-activation-description">
            {t("dialog.cannot_open_camera.content")}
          </DialogContentText>
        </DialogContent>
        <DialogActions>
          <Link to="/">
            <Button color="primary">{t("button.back_home")}</Button>
          </Link>
          <Link to="/cameraSetting">
            <Button color="primary">{t("button.camera_setting")}</Button>
          </Link>
        </DialogActions>
      </Dialog>
    </>
  );
}