mrousavy / react-native-vision-camera

๐Ÿ“ธ A powerful, high-performance React Native Camera library.
https://react-native-vision-camera.com
MIT License
7.57k stars 1.1k forks source link

๐Ÿ› Disabled Audio has 5-10 seconds delay in finish video recording #2218

Closed MrSolimanKing closed 11 months ago

MrSolimanKing commented 11 months ago

What's happening?

My Camera app has 2 options one to record video with audio and one to record without audio, I noticed when I finish recording when the audio is false audio={false} it has a 5 - 10 seconds delay in comparison with when the Audio is enabled audio={true} which it trigger onRecordingFinished: async (video) => {} immediately when finish recording

Reproduceable Code

`
 <ReanimatedCamera
            style={[{           
                height: height,
                width: "100%",
                zIndex: -2,
                borderRadius: 30,
                overflow: 'hidden'
            }]}
            ref={cameraRef}
            device={device}
            isActive={true}
            torch={flash}
            photo={true}
            zoom={Math.abs(cameraZoomValue * 1000)}
            video={true}
            audio={captureAudio}
            format={format}
            fps={30}  
            enableZoomGesture
            orientation="portrait"
        />
`

Relevant log output

No logs

Camera Device

{
  "sensorOrientation": "landscape-right",
  "hardwareLevel": "full",
  "isMultiCam": false,
  "minZoom": 1,
  "position": "back",
  "supportsRawCapture": false,
  "supportsFocus": true,
  "neutralZoom": 1,
  "physicalDevices": [
    "wide-angle-camera"
  ],
  "supportsLowLightBoost": false,
  "maxZoom": 123.75,
  "name": "Back Camera",
  "hasFlash": true,
}

Device

iPhone 12

VisionCamera Version

3.6.10

Can you reproduce this issue in the VisionCamera Example app?

I didn't try (โš ๏ธ your issue might get ignored & closed if you don't try this)

Additional information

mrousavy commented 11 months ago

Whoops, sorry. Fixed this in https://github.com/mrousavy/react-native-vision-camera/pull/2221! :) Let me know if that works for you :)

MrSolimanKing commented 11 months ago

@mrousavy Fantastic! It's now working flawlessly and perfectly. Thank you so much for your tremendous efforts; I truly appreciate everything you've done.

mrousavy commented 11 months ago

Released that fix in VisionCamera 3.6.11! :)

If you appreciate my time and dedication in maintaining and improving this project, please consider ๐Ÿ’– sponsoring me on GitHub ๐Ÿ’– so I can keep improving VisionCamera!

dgreasi commented 6 months ago

I am having a similar issue (almost the same) with the latest v4.0.3 version of the lib. I had the same issue with versions v3.7.0, v3.7.1, v3.9.2.

This issue only occurs for iOS devices. In my case audio is false too.

I can see that the onRecordingFinished callback is triggered always after a delay of 4-5 seconds only for iOS devices. On Android it's triggered without delay.

You can find my component below:

const QualityCheckVideoRecording = ({ lines, setVideoRecorded }) => {
  const dispatch = useDispatch();
  const cameraDevice = useSelector((state) => state.currentCameraOrientation);
  const device = useCameraDevice(cameraDevice);
  const appState = useRef(AppState.currentState);
  const format = useCameraFormat(device, [{ videoResolution: { width: 640, height: 480 } }]);
  const cameraRef = useRef(null);

  const [isCameraInitialized, setIsCameraInitialized] = useState(false);
  const [isCameraActive, setCameraActive] = useState(true);

  const isCameraShown = useMemo(() => {
    if (platform.isAndroid) {
      return device && isCameraActive;
    }

    return device;
  }, [isCameraActive, device]);

  useEffect(() => {
    cameraRequestPermissionFlow();
  }, []);

  useEffect(() => {
    KeepAwake.activate();
    return () => {
      KeepAwake.deactivate();
      setCameraActive(false);
      setIsCameraInitialized(false);
    };
  }, []);

  const handleAppStateChange = useCallback(
    (nextAppState) => {
      if (appState.current === 'active' && nextAppState.match(/inactive|background/) && cameraRef.current) {
        setCameraActive(false);
        setIsCameraInitialized(false);
      }

      if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
        Alert.alert('Recording was interrupted', 'Do you want to start it over again?', [
          {
            text: 'Yes',
            onPress: () => {
              setCameraActive(true);
            },
          },
          {
            style: 'cancel',
            text: 'No',
            onPress: () => dispatch(navigatePop()),
          },
        ]);
      }

      appState.current = nextAppState;
    },
    [cameraRef],
  );

  useEffect(() => {
    const appStateEventSubscription = AppState.addEventListener('change', handleAppStateChange);

    return () => {
      appStateEventSubscription.remove();
    };
  }, [handleAppStateChange]);

  useEffect(() => {
    if (isCameraInitialized && cameraRef.current && isCameraActive && isCameraShown) {
      console.log('WILL RUN START RECORDING');
      cameraRef.current.startRecording({
        onRecordingFinished: (video) => {
          console.log('4 - date: ', new Date());
          console.log('==== handleVideoUpload');
          setCameraActive(false);
          setIsCameraInitialized(false);
          setVideoRecorded(video);
          console.log('5 date: ', new Date());
          dispatch(navigatePop());
        },
        onRecordingError: (e) => Sentry.captureException(e),
        fileType: DEFAULT_VIDEO_FORMAT,
        videoBitRate: 'low',
      });
    }
  }, [isCameraInitialized, isCameraActive, isCameraShown]);

  const handleCameraInitialized = useCallback(() => {
    setIsCameraInitialized(true);
  }, []);

  const retakeVideo = useCallback(() => {
    setCameraActive(false);
    if (platform.isAndroid) {
      setIsCameraInitialized(false);
    }
    setTimeout(() => setCameraActive(true), 1000);
  }, []);

  const stopRecording = useCallback(
    async (cb) => {
      try {
        console.log('1 date: ', new Date());
        await cameraRef?.current?.stopRecording();
        console.log('2 date: ', new Date());
        cb();
        console.log('3 date: ', new Date());
      } catch (e) {
        console.log('e: ', e);
        Sentry.captureException(e);
        Alert.alert('There was a problem with recording', 'Do you want to start it over again?', [
          {
            text: 'Yes',
            onPress: retakeVideo,
          },
          {
            style: 'cancel',
            text: 'No',
          },
        ]);
      }
    },
    [retakeVideo, cameraRef],
  );

  const showPauseModal = useCallback(() => {
    if (cameraRef.current) {
      cameraRef.current.pauseRecording();
      dispatch(
        showModal({
          key: '/orders/pause-qc-video-recording',
          props: { retakeVideo, stopRecording, lines, setCameraActive },
        }),
      );
    }
  }, [cameraRef, dispatch, stopRecording, retakeVideo, lines]);

  return (
    <View style={styles.contentContainer}>
      {isCameraShown ? (
        <Camera
          collapsable={false}
          style={styles.container}
          ref={cameraRef}
          video
          audio={false}
          device={device}
          onInitialized={handleCameraInitialized}
          isActive={isCameraActive}
          format={format}
        />
      ) : null}
      <Pressable onPress={showPauseModal} style={styles.cameraActions}>
        <Icon style={styles.captureIcon} name="camera" />
      </Pressable>
    </View>
  );
};

My dependencies:

"react": "18.2.0",
"react-native": "0.72.5",
"react-native-vision-camera": "^4.0.3",

Tested on iPhone 12 and Pixel 6a devices

I guess this might be still an issue @mrousavy