react-native-vision-camera icon indicating copy to clipboard operation
react-native-vision-camera copied to clipboard

🐛 Photo Camera isn't correctly detached on Android

Open isinuyk opened this issue 8 months ago • 5 comments

What's happening?

I wanted to use back camera after front but I got the black screen. In the device logs I see different errors

 UNKNOWN_CAMERA_DEVICE_ERROR
[session/camera-not-ready] The Camera is not ready yet! Wait for the onInitialized
[session/camera-has-been-disconnected] : DISCONNECTED
and TOO_MANY_CAMERA_DEVICE_OPENED

Case 1. front to back

https://github.com/mrousavy/react-native-vision-camera/assets/72970722/357d7b3f-807c-4f26-9ff6-26956d00666f

Then I cold boot the app;

Case 2. back to front

https://github.com/mrousavy/react-native-vision-camera/assets/72970722/32cd48d8-a890-46d1-93f9-75159a8770ba

Then I found a pretty similar but alreadycmerged PRand applied the suggested code from there.

After patch:

https://github.com/mrousavy/react-native-vision-camera/assets/72970722/3c71f37d-c2ef-4931-9738-a501db8019c3

In additional I tried to search for this Log.i(TAG, "Destroying session..") line in the logs but it wasn't fired. Right after I applied the patch it was there. Please help me to figure out where is the problem or maybe I am missing something. Thanks!

Reproduceable Code

const TestScreenInitial = () => {
  return (
    <View>
      <Button onPress={() => navigationRef.navigate('test1')} title="back" />
      <Button onPress={() => navigationRef.navigate('test2')} title="front" />
    </View>
  );
};

const TestScreen = () => {
  const device = useCameraDevice('back');
  const isForeground = useIsFocused();
  console.log('device', device);
  if (device == null) return null;
  return (
    <Camera
      style={StyleSheet.absoluteFill}
      device={device}
      isActive={isForeground}
      photo={true}
    />
  );
};

const TestScreen2 = () => {
  const device = useCameraDevice('front');
  const isForeground = useIsFocused();

  if (device == null) return null;
  return (
    <Camera
      style={StyleSheet.absoluteFill}
      device={device}
      isActive={isForeground}
      photo={true}
    />
  );
};

Relevant log output

Camera Device android.hardware.camera2.impl.CameraDeviceImpl@19fe9fb has been disconnected!
com.mrousavy.camera.core.CameraDisconnectedError: [session/camera-has-been-disconnected] The given Camera device (id: 0) has been disconnected! Error: UNKNOWN_CAMERA_DEVICE_ERROR
	at com.mrousavy.camera.extensions.CameraManager_openCameraKt$openCamera$2$callback$1.onError(CameraManager+openCamera.kt:49)
	at
2023-10-31T14:34:12.991Z
24671
CameraSession
PreviewView Surface destroyed! Surface(name=null)/@0xc2a297e
2023-10-31T14:34:12.992Z
24671
CameraSession
Destroying Preview Output...
2023-10-31T14:34:12.993Z
24671
CameraSession
Updating CameraSession Configuration...
2023-10-31T14:34:12.995Z
24671
CameraSession
Configuring Session for Camera #0...
2023-10-31T14:34:13.000Z
24671
CameraSession
Adding 4208 x 3120 Photo Output in Format #256...
2023-10-31T14:34:13.005Z
24671
CameraSession
Failed to configure CameraSession! Error: CameraDevice was already closed, Config-Diff: Difference(deviceChanged=false, outputsChanged=true, sidePropsChanged=true)
java.lang.IllegalStateException: CameraDevice was already closed
	at android.hardware.camera2.impl.CameraDeviceImpl.checkIfCameraClosedOrInError(CameraDeviceImpl.java:2375)
	at android.hardware.camera2.impl.CameraDeviceImpl.createCaptur
2023-10-31T14:34:13.006Z
24671
System.err
	at com.mrousavy.camera.core.CameraSession.configureOutputs(CameraSession.kt:351)
2023-10-31T14:34:13.006Z
24671
System.err
	at com.mrousavy.camera.core.CameraSession.configure(CameraSession.kt:136)
2023-10-31T14:34:13.006Z
24671
System.err
	at com.mrousavy.camera.core.CameraSession$destroyPreviewOutputSync$1.invokeSuspend(CameraSession.kt:213)
2023-10-31T14:34:13.006Z
24671
System.err
	at com.mrousavy.camera.core.CameraSession.destroyPreviewOutputSync(CameraSession.kt:212)
2023-10-31T14:34:13.006Z
24671
System.err
	at com.mrousavy.camera.core.CameraSession.access$destroyPreviewOutputSync(CameraSession.kt:57)
2023-10-31T14:34:13.006Z
24671
System.err
	at com.mrousavy.camera.core.CameraSession$createPreviewView$previewView$1.surfaceDestroyed(CameraSession.kt:193)

Camera Device

formats: Array(544)
hardwareLevel: "full"
hasFlash: true
hasTorch: true
id: "0"
isMultiCam: false
maxZoom: 8
minZoom: 1
name: "BACK (0)"
neutralZoom: 1
physicalDevices: Array(1)
position: "back"
sensorOrientation: "landscape-right"
supportsFocus: true
supportsLowLightBoost: false
supportsRawCapture: true

Device

Samsung Galaxy A11 (Android 12)

VisionCamera Version

3.6.4

Can you reproduce this issue in the VisionCamera Example app?

Yes, I can reproduce the same issue in the Example app here

Additional information

isinuyk avatar Oct 31 '23 14:10 isinuyk

I had a similar error and found simple workaround for it. In short, we need to remount Camera component after Andoid disabled camera device. I did it by adding onError handler to Camera component:

// Add state variable that allow us to force disable camera.
const [cameraDisabled, setCameraDisabled] = useState(false);

const resetCamera = () => {
  setCameraDisabled(true);
  // Theoretically with zero timeout React can decide that there is no need to re-mount component, so I set here 100ms.
  setTimeout(() => setCameraDisabled(false), 100);
};

if (cameraDisabled) {
  return (
    // Some placeholder component.
  );
}
return (
<Camera
    ref={cameraRef}
    device={device}
     photo
    isActive={hasPermission && isFocused && appState === 'active' }
    style={styles.camera}
    enableZoomGesture
    onError={resetCamera} // This is the solution.
  />
);

alexey-kuznetsov avatar Nov 05 '23 10:11 alexey-kuznetsov

My adb logs are bit different.

Failed to configure CameraSession! Error: CameraDevice was already closed, Config-Diff: Difference(deviceChanged=false, outputsChanged=true, sidePropsChanged=true)
	java.lang.IllegalStateException: CameraDevice was already closed
		at android.hardware.camera2.impl.CameraDeviceImpl.checkIfCameraClosedOrInError(CameraDeviceImpl.java:2456)
		at android.hardware.camera2.impl.CameraDeviceImpl.createCaptureSessionInternal(CameraDeviceImpl.java:692)
		at android.hardware.camera2.impl.CameraDeviceImpl.createCaptureSession(CameraDeviceImpl.java:677)
		at com.mrousavy.camera.extensions.CameraDevice_createCaptureSessionKt.createCaptureSession(CameraDevice+createCaptureSession.kt:57)
		at com.mrousavy.camera.core.CameraSession.configureOutputs(CameraSession.kt:352)
		at com.mrousavy.camera.core.CameraSession.configure(CameraSession.kt:136)
		at com.mrousavy.camera.core.CameraSession$createPreviewOutput$1.invokeSuspend(CameraSession.kt:204)
		at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
		at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
		at android.os.Handler.handleCallback(Handler.java:942)
		at android.os.Handler.dispatchMessage(Handler.java:99)
		at android.os.Looper.loopOnce(Looper.java:226)
		at android.os.Looper.loop(Looper.java:313)
		at android.os.HandlerThread.run(HandlerThread.java:67)

bglgwyng avatar Nov 11 '23 09:11 bglgwyng

Small workaround (similiar to the solution above, but) by setting key=


  const [resetKey, setResetKey] = useState(0)
  <Camera
    key={`${resetKey}`}
    onError={error => {
      if (error.message.includes('CameraDevice was already closed')) {
        setResetKey(prev => prev + 1)
      }
    }}
  />

Happens only on android and it solved the issue.

patlux avatar Nov 16 '23 11:11 patlux

@bglgwyng I'm facing similar crash. were you able to fix this crash with above workaround?

deepakv-z14 avatar Dec 12 '23 07:12 deepakv-z14

@bglgwyng I'm facing similar crash. were you able to fix this crash with above workaround?

No. I dont even know how to reproduce it yet

bglgwyng avatar Dec 12 '23 13:12 bglgwyng

Hey - I think I fixed this in the latest version of VisionCamera. :)

mrousavy avatar Jan 15 '24 13:01 mrousavy