react-native-vision-camera unmount problem : TOO_MANY_OPEN_CAMERAS

362 Views Asked by At

My camera code works just fine, except that if I leave the page and come back I get the error "TOO_MANY_OPEN_CAMERAS". Not that this doesn't hapen if I leave the page while using the back camera, it only happens when the last camera I use before leaving is the front camera. I do try unmounting the camera using the return useEffect with no success.

Here is the code :

//list of imports

export function CameraScreen({route, navigation}): JSX.Element {
  const [selectedCamera, setSelectedCamera] = useState('back'); // Start with the back camera
  const cameraRef = useRef(null);
  const [imageUri, setImageUri] = useState(null);
  const {token, partyCode, partyData} = route.params;
  const [flashMode, setFlashMode] = useState('off'); // or 'on', 'auto'
  const [zoom, setZoom] = useState(0);
  const [lastZoom, setLastZoom] = useState(1);
  const [isCameraActive, setIsCameraActive] = useState(true);

  const requestPermissions = async () => {
    //permission code
  };

  useEffect(() => {
    changeNavigationBarColor('#ffffff');

    return () => {
      console.log('Cleaning up camera...');
      setIsCameraActive(false); // This should deactivate the camera
    };
  }, []);

  const devices = useCameraDevices();

  // Find the index of the device with position "back"
  const backDeviceIndex = devices.findIndex(
    device => device.position === 'back',
  );

  const frontDevice = devices.find(device => device.position === 'front');
  const backDevice = devices.find(device => device.position === 'back');

  const device = selectedCamera === 'back' ? backDevice : frontDevice;

  return (
    <GestureHandlerRootView style={styles.WiteBackground}>
      <View style={styles.WiteBackground}>
        <View style={styles.whiteFooterWrap}></View>
        <PinchGestureHandler
          onGestureEvent={onPinchEvent}
          onHandlerStateChange={onPinchEvent}>
          <TapGestureHandler
            onHandlerStateChange={onDoubleTap}
            numberOfTaps={2} // this is to specify double tap
          >
            <View style={styles.sectionContainer}>
              {device && (
                <Camera
                  ref={cameraRef}
                  style={styles.camera}
                  device={device}
                  isActive={isCameraActive}
                  photo={true}
                  zoom={zoom}
                  onActive={() => console.log('Camera is active')}
                  onError={error => console.log('Camera error:', error)}
                />
              )}

              <Button
                onPress={() => takePhoto(cameraRef, token)}
                style={styles.takePhotoBtn}
              />
              <TouchableOpacity
                onPress={toggleCamera}
                style={styles.switchCameras}>
                <Image
                  source={require('./images/PNG/swtich_cameras.png')} // Replace with the actual path to your logo image
                  style={styles.logoImage}
                />
              </TouchableOpacity>
            </View>
          </TapGestureHandler>
        </PinchGestureHandler>
      </View>
    </GestureHandlerRootView>
  );
}

const styles = StyleSheet.create({
  //list of styles
});

export default CameraScreen;

The documentation tells you to unmount the camera like so

function App() {
  const isFocused = useIsFocused()
  const appState = useAppState()
  const isActive = isFocused && appState === "active"

  return <Camera {...props} isActive={isActive} />
}

So I tried something like :

const cameraRef = useRef(null);
const isFocused = useIsFocused();
const [appState, setAppState] = useState(AppState.currentState);

useEffect(() => {
    const subscription = AppState.addEventListener("change", nextAppState => {
      setAppState(nextAppState);
    });

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

  useEffect(() => {
    const isActive = isFocused && appState === 'active';

    if (!isActive && cameraRef.current) {

      cameraRef.current.stop(); 
    }

    return () => {
      if (cameraRef.current) {
        cameraRef.current.start(); 
      }
    };
  }, [isFocused, appState]);

With no success

0

There are 0 best solutions below