opentok/opentok-android-sdk-samples

com.opentok.android.Camera2VideoCapturer$Camera2Exception: CAMERA_DISABLED (1): validateClientPermissionsLocked:1502: Caller "com.company" cannot open camera "3" from background

balu-m opened this issue ยท 50 comments

Caused by : swithing app foreground to background multiple times getting below crash

com.opentok.android.Camera2VideoCapturer$Camera2Exception: CAMERA_DISABLED (1):
validateClientPermissionsLocked:1502: Caller "com.company" (PID 103, UID 255) cannot open camera "3" from background (calling UID 103 proc state 16)
at com.opentok.android.Camera2VideoCapturer.initCamera(Unknown Source:101)
at com.opentok.android.Camera2VideoCapturer.a(Unknown Source:12)
at com.opentok.android.Camera2VideoCapturer.$r8$lambda$EOJ6zJ_KyEal1aLQznxfTJOPcJc(Unknown Source)
at com.opentok.android.Camera2VideoCapturer$$ExternalSyntheticLambda3.run(Unknown Source:4)
at com.opentok.android.Camera2VideoCapturer$4.onClosed(Unknown Source:44)
at android.hardware.camera2.impl.CameraDeviceImpl$5.run(CameraDeviceImpl.java:229)
at android.os.Handler.handleCallback(Handler.java:938)
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.app.ActivityThread.main(ActivityThread.java:8663)
at java.lang.reflect.Method.invoke(Method.java:-2)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)

any updates on this ? :)

Same here. Any updates on this?

Hi ๐Ÿ‘‹,

Is this issue reproducible on the latest version of the SDK? Please advise. Thanks! ๐Ÿ™

for me this only happens on the newest version

Thanks, @AndreasKarlzzon.

Which models of phone are you able to reproduce this with?

samsung o1s (Galaxy S21 5G), samsung beyond1 (Galaxy S10), samsung x1s (Galaxy S20 5G) and more :)

Just wanted to provide an update. We tried to reproduce on an Samsung Galaxy Z Flip 4 but didn't have any luck.

I'll see if someone has one of the devices listed and try again.

Just wanted to provide an update. We weren't able reproduce the issue on an Samsung Galaxy S10+ either.

I wonder if we're missing a key step. @AndreasKarlzzon can you provide more detailed steps to reproduce please? Thanks!

Just a sample:

  • Pixel 6 Pro
  • Galaxy S21 5G
  • Galaxy A53 5G
  • Galaxy A13 5G
  • moto g stylus 5G
  • Galaxy S9
  • Galaxy Note9
  • Galaxy Note20 5G

Looks like there is no correlation between the error and device. Android 9, 11, 12, 13

For us, we saw this on any device that has more than 1 back camera and uses the Camera2 capturer, had to roll back from 2.24 to 2.22.3 and include the Huawei patch in our own code

Siarl commented

One of my projects has been experiencing this issue since at least SDK version 2.23.0, but I'm quite sure it happened before then as well.

My phone has four cameras, three on the back and one on the front. The cycleCamera() function switches through these four cameras, but when the last camera is selected and cycleCamera() is called again, the app crashes with a similar log.

To look into this, I ran the following code on my device:

val manager: CameraManager = getSystemService(CAMERA_SERVICE) as CameraManager
manager.cameraIdList.forEach {
            Log.d(
                "camera",
                "id: $it isBackFacing: ${
                    (manager.getCameraCharacteristics(it)
                        .get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_BACK)
                }"
            )
        }

I get the following result in the logs:

D/camera  (13482): id: 0 isBackFacing: true
D/camera  (13482): id: 1 isBackFacing: false
D/camera  (13482): id: 2 isBackFacing: true
D/camera  (13482): id: 3 isBackFacing: true
D/camera  (13482): id: 4 isBackFacing: true
D/camera  (13482): id: 5 isBackFacing: true
D/camera  (13482): id: 6 isBackFacing: true
D/camera  (13482): id: 7 isBackFacing: false

So the CameraManager is returning more cameras than there actually are. I then use a (deprecated) function to set the cameraId to an id of a camera that should exist: publisher?.cameraId = 0 and then one that should not exist: publisher?.cameraId = 7. CameraId 0 works, but CameraId 7 results in a crash.

Logs
E/AndroidRuntime(16771): com.opentok.android.Camera2VideoCapturer$Camera2Exception: CAMERA_ERROR (3): endConfigure:559: Camera 7: Error configuring streams: Function not implemented (-38)
E/AndroidRuntime(16771): 	at com.opentok.android.Camera2VideoCapturer.doStartCapture(Unknown Source:173)
E/AndroidRuntime(16771): 	at com.opentok.android.Camera2VideoCapturer.c(Unknown Source:0)
E/AndroidRuntime(16771): 	at com.opentok.android.Camera2VideoCapturer.$r8$lambda$Ja1sVxV4wLYhzOqCHGFwz3iLgIQ(Unknown Source:0)
E/AndroidRuntime(16771): 	at com.opentok.android.Camera2VideoCapturer$$ExternalSyntheticLambda0.run(Unknown Source:2)
E/AndroidRuntime(16771): 	at com.opentok.android.Camera2VideoCapturer$4.onOpened(Unknown Source:40)
E/AndroidRuntime(16771): 	at android.hardware.camera2.impl.CameraDeviceImpl$1.run(CameraDeviceImpl.java:165)
E/AndroidRuntime(16771): 	at android.os.Handler.handleCallback(Handler.java:938)
E/AndroidRuntime(16771): 	at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(16771): 	at android.os.Looper.loopOnce(Looper.java:201)
E/AndroidRuntime(16771): 	at android.os.Looper.loop(Looper.java:288)
E/AndroidRuntime(16771): 	at android.app.ActivityThread.main(ActivityThread.java:7842)
E/AndroidRuntime(16771): 	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(16771): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:550)
E/AndroidRuntime(16771): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

Notice how the first line says "Camera 7: Error configuring streams: Function not implemented". OpenTok/Vonage should implement a handler that takes care of this issue.


I currently "fix" this issue using the following code:

val manager: CameraManager = getSystemService(CAMERA_SERVICE) as CameraManager
val frontCameraId: String? = manager.cameraIdList.first { id: String ->
     manager.getCameraCharacteristics(id)
           .get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT
     }
val backCameraId: String? = manager.cameraIdList.first { id: String ->
     manager.getCameraCharacteristics(id)
           .get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_BACK
     }

binding.buttonSwitchCam.setOnClickListener {
    if (mPublisher?.cameraId == frontCameraId?.toInt()) {
          backCameraId?.toInt()?.let {
                  mPublisher?.cameraId = it
          }
     } else {
          frontCameraId?.toInt()?.let {
                  mPublisher?.cameraId = it
           }
     }
}

I would like to request OpenTok does not deprecate the getCameraId/setCameraId functionality, but update it to accept strings in stead of integers, as the CameraManager returns camera ids in the form of strings.


Update:

After releasing this code I noticed some crashes. If you use this solution make sure you have the camera permission. Updated code:

val frontCameraIndex: Int = manager.cameraIdList.indexOfFirst { id: String ->
    manager.getCameraCharacteristics(id)
        .get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT
}
val backCameraIndex: Int = manager.cameraIdList.indexOfFirst { id: String ->
    manager.getCameraCharacteristics(id)
        .get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_BACK
}

buttonSwitchCam.setOnClickListener {
    if (mPublisher?.cameraId == frontCameraIndex) {
        if (backCameraIndex != -1) {
            mPublisher?.cameraId = backCameraIndex
        }
    } else {
        if (frontCameraIndex != -1) {
            mPublisher?.cameraId = frontCameraIndex
        }
    }
}

This works better with the implementation of Publisher.getCameraId/setCameraId.

Any updates on this?

We started seeing this in Crashlytics after updating to the latest version (2.24.0).
The problem seems to be indeed caused by cycling the camera and it happened so far on the following devices (according to Crashlytics):
Xiaomi Mi 10 lite
Xiaomi Redmi Note 10 Pro
Samsung Galaxy S10e
Galaxy S20
Galaxy Tab S7 FE

We have started seeing this issue too, I am not sure if we have seen it before 2.24.0. A recent crash happened on Galaxy S21+ 5G running Android 12.

It seems that the latest OpenTok versions don't really play well with devices that have multiple cameras. For example Huawei P30 is broken, but Pixel 4a is fine.

How to reproduce: Use a device with more than 2 cameras. Start a session with camera and then call swapCamera() to switch to the back camera. Now end session. If you start another session again (without restarting the app process) then the camera view will be black.

This has been a bug for so long - we already had a workaround in the past where we would call swapCamera() again to switch back to the front camera when you end the call. But on 2.24.0 this doesn't work because of the multiple camera support bug.

So basically we now use a similar code like posted above, we keep a list of front and back cameras IDs. And when you end the call we check if user.cameraId is an ID from the list of back cameras. If yes then we use user.cameraId = frontCameraIndexes.first() to switch to the front camera again. This fixes the bug when next sessions have a black camara view. But it's just a horrible hack and workaround around OpenTok issues.

Also - swapCamera() will iterate over all cameras on the device. So on a Huwaei it will not switch between front and back, it will switch to back normal, back wide, back macro and then front. I think that OpenTok should only switch between the default back and front. You can use user.cameraId to switch to a specific camera.

Thanks everyone for all your input.

Someone on the team has a Pixel 6, which has multiple cameras. We'll try to reproduce using that. Will keep you posted.

Hi, @v-kpheng I would appreciate if you have any status updates on this.

I work for a large organization that uses OpenTalk and we are suffering from the same issue after using the 2.24.0 version.

Thanks

@fpiresca, sorry for the lack of updates. The "someone" on the team with the Pixel 6 was me and I just came back from vacation.

Issue is still on our sprint. Will provide an update soon.

Thanks for the fast response @v-kpheng I appreciate the support.

Fatal Exception: com.opentok.android.Camera2VideoCapturer$Camera2Exception: CAMERA_DISABLED (1): validateClientPermissionsLocked:1226: Caller "com.android.phoenix" (PID 10042, UID 25578) cannot open camera "0" from background (calling UID 10042 proc state 12).

can any body help

@v-kpheng any updates? We are also seeing this issue in production.

driq commented

Same here. We have an app in production that is affected by this issue, and we have not come up with a way to workaround it.

Hi @v-kpheng, could you please provide an update on this issue? It's been over a month since you promised an update. ๐Ÿ˜ž We see lots of these crashes happening in our production app, and the number of crash-free sessions has plummeted significantly due to this issue.

@Roman-hub, sorry, progress was stalled because of my vacation and higher priority items. I have bandwidth to look into this now.

Just wanted to share an update. I couldn't reproduce on my Pixel 6. While doing cycleCamera I noticed that only one of the rear cameras appeared. This is probably why I can't reproduce.

I asked my colleague to try to reproduce again on her Samsung Z Fold 4, which has three physical rear cameras.

Hello @v-kpheng According to our crash data, 90% of crashes are coming from samsung devices and 100% background. Could you please try to reproduce this from Samsung Note. this is critical issue for us. thanks
Fatal Exception: com.opentok.android.Camera2VideoCapturer$Camera2Exception: CAMERA_DISABLED (1): validateClientPermissionsLocked:1299/.../cannot open camera "1" from background

Thanks, @pc-anuruddha. We'll need to try to get our hands on a Samsung Note ๐Ÿคž.

My colleague tried to reproduce again on her Samsung Z Fold 3 but couldn't, despite it having multiple rear cameras. This was her test method:

  • Use "cycleCamera" to iterate through cameras until a rear camera is displayed
  • Send app to background and back to foreground multiple times, to try to get it to crash

The app never crashed. She also tried to set it to a different rear camera, but no luck there either.

@v-kpheng Could there be a problem with a session restart? In our app an event can be sent to the signaling channel indicating the need to restart the session. In that case current session is ended, using session.disconnect(), and a new one is started. We don't call cycleCamera() anywhere in our code.

@Roman-hub, can you please create a PR against one of the sample apps? Hopefully we'll be able to reproduce it this time ๐Ÿคž

This can also happen if the app is running the video stream in the background and it swaps the camera

fix this crash, please!

This is a very bad bug that has a bad impact on the user experience, our company gets a lot of negativity. Please raise the priority of the problem.

Can someone please see if the issue goes away with 2.24.2? The crashes might be due to camera resources not being released properly, which was recently fixed.

@v-kpheng We still see these crashes with 2.24.2 library version.

It's even worse in the latest library version. A new crash started popping up, on top of the old ones mentioned in this thread:

Fatal Exception: java.lang.IllegalStateException: Session has been closed; further changes are illegal.
at android.hardware.camera2.impl.CameraCaptureSessionImpl.checkNotClosed(CameraCaptureSessionImpl.java:834)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.stopRepeating(CameraCaptureSessionImpl.java:402)
at com.opentok.android.Camera2VideoCapturer.stopCapture(:29)
at com.opentok.android.PublisherKit.d(:4)
at com.opentok.android.PublisherKit.$r8$lambda$6BMkMXi2EstSU_HgeV7ZQb4y6yA()
at com.opentok.android.PublisherKit$$ExternalSyntheticLambda14.run(:2)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)

@Roman-hub

I was able to get rid of this newest crash by making sure that we don't call session.onPause + session.onResume more than once in quick succession. Maybe add logging when you do this calls to see if you are not calling it several times. But - OpenTok should make sure we don't need to add workarounds and they should handle this internally.

Overall the newest version helped us to get rid of all the other workarounds we had in code to get OpenTok to work correctly. But we will see if we keep getting new crashes once we deploy this to production...

@DanielNovak Thanks for the advice! Will check it out.

@DanielNovak, @Roman-hub, or anyone, really...

Can someone please give me an example (maybe as a PR?) of how to reproduce this problem using one of the sample apps?

Plus one on the thread.
I tried a few things but still couldn't find a workaround for this.

I dont know if my logs add any value but I am guessing they could help fix this issue so here goes:

Most affected device: Moto g pure
Most affected android version: 13
Place of crash : 95% background

com.opentok.android.Camera2VideoCapturer$Camera2Exception: CAMERA_DISABLED (1): validateClientPermissionsLocked:1560: Caller "com.varsitytutors.tutoringtools" (PID 10270, UID 12887) cannot open camera "1" from background (calling UID 10270 proc state 15)
    com.opentok.android.Camera2VideoCapturer.initCamera(SourceFile:70)
    com.opentok.android.Camera2VideoCapturer.$r8$lambda$EOJ6zJ_KyEal1aLQznxfTJOPcJc(SourceFile:15)
    com.opentok.android.Camera2VideoCapturer.$r8$lambda$EOJ6zJ_KyEal1aLQznxfTJOPcJc(SourceFile:0)
    com.opentok.android.Camera2VideoCapturer$$InternalSyntheticLambda$1$a584d3ebc8d132fd4b66cb4078f8bb1f3b20fd84f6152b5277de9aa5ac276da7$0.run(Camera2VideoCapturer.java:4)
    com.opentok.android.Camera2VideoCapturer$4.onClosed(SourceFile:44)
    android.hardware.camera2.impl.CameraDeviceImpl$5.run(CameraDeviceImpl.java:237)
    android.os.Handler.handleCallback(Handler.java:942)
    android.os.Handler.dispatchMessage(Handler.java:99)
    android.os.Looper.loopOnce(Looper.java:226)
    android.os.Looper.loop(Looper.java:313)
    android.app.ActivityThread.main(ActivityThread.java:8757)
    java.lang.reflect.Method.invoke(Method.java:0)
    com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
    com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)

In my case this issue seems to be caused when trying to establish a video call while an app is in the background. So any app on android 11 or higher will see this if there is an attempt to start the video. Here is the android documentation on this.

I'm going to put this back in the backlog. Sorry.
If someone can provide a simple sample app to reproduce the issue, we'll look into it again.

@v-kpheng have you tried changing the camera or starting the call when you have the app goes to/is in the background? seems that it does not consider this and tries = Crash

This issue doesn't happen regularly, is difficult to replicate reliably, and in my opinion, is isolated to slower devices. I tested with the emulator, and was not seeing it occur, but when tested on a older, slower device it occurred once every 4 minutes of testing.

I was not able to reproduce this reliably, but one way was to call onResume and onPause on the session object in quick succession. This was my stack trace of the crash on a slow device:

Fatal Exception: com.opentok.android.Camera2VideoCapturer$Camera2Exception: CAMERA_IN_USE (4): connectHelper:1749: Higher-priority client using camera, ID "0" currently unavailable
at com.opentok.android.Camera2VideoCapturer.initCamera(Camera2VideoCapturer.java:79)
at com.opentok.android.Camera2VideoCapturer.startCapture(Camera2VideoCapturer.java:51)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:250)
at android.app.ActivityThread.main(ActivityThread.java:7851)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:958)

This is happening on production for us also.
Device: Pixel 6 Android 13
Vonage SDK: 2.26

We see this occur when closing a previous session and creating a new close together. There seems to be no 'good' or recommended way to close a session other than nulling its reference and hoping that the garbage collector collects. That being said we are trying to use the life cycle methods to gracefully close the vonage session. Currently we are doing the following to close the old session before creating a new one:

If you run this code to close the previous sessions references x3-4 times you will run into the error i got.

session?.onPause()
patientPublisher?.onStop()

The main issue seems to be that vonage is attempting to remove something that does not exist.

The fact that I have to jump though so many hoops just to dispose and ensure vonage is not controlling the camera anymore is a bit crazy to me.

FATAL EXCEPTION: main
Process: com.transcarent.app, PID: 550
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Handler.removeCallbacks(java.lang.Runnable)' on a null object reference
	at com.opentok.android.Camera2VideoCapturer.stopDisplayOrientationCache(Unknown Source:4)
	at com.opentok.android.Camera2VideoCapturer.destroy(Unknown Source:11)
	at com.opentok.android.PublisherKit.a(Unknown Source:4)
	at com.opentok.android.PublisherKit.z(Unknown Source:0)
	at com.opentok.android.m0.run(Unknown Source:2)
	at android.os.Handler.handleCallback(Handler.java:942)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loopOnce(Looper.java:201)
	at android.os.Looper.loop(Looper.java:288)
	at android.app.ActivityThread.main(ActivityThread.java:7918)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

It should be noted we have also tried to go directly to the capture of the publisher and stop that however stopping that results in a separate error.

Please give us a guaranteed way to COMPLETELY dispose of a session/publisher this is so frustrating.

We are experiencing this issue too, most devices are Samsung.

Not able to repro on Galaxy M51 and Huawei P30 with latest code. Closing this.