react-native-vision-camera
react-native-vision-camera copied to clipboard
🐛 Photo Camera isn't correctly detached on Android
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
- [ ] I am using Expo
- [ ] I have enabled Frame Processors (react-native-worklets-core)
- [X] I have read the Troubleshooting Guide
- [X] I agree to follow this project's Code of Conduct
- [X] I searched for similar issues in this repository and found none.
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.
/>
);
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)
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.
@bglgwyng I'm facing similar crash. were you able to fix this crash with above workaround?
@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
Hey - I think I fixed this in the latest version of VisionCamera. :)