mozmorris / react-webcam

Webcam component
https://codepen.io/mozmorris/pen/JLZdoP
MIT License
1.67k stars 284 forks source link

Switching deviceId in audio/video constraints freezes the browser in Chrome for Android #244

Open keithpickering opened 4 years ago

keithpickering commented 4 years ago

Hi, please see this example for testing: https://dev.boothpics.com/booth/xlqp3o

This previous (now closed) issue features some codepen examples that also exhibit the issue: https://github.com/mozmorris/react-webcam/issues/170

Changing the videoConstraints or audioConstraints seems to freeze the entire browser, requiring a force close. I've tried to solve the issue by stopping media streams before switching the constraints, unmounting the Webcam component before remounting with the new constraints, and even a 5 second timeout (currently active in the example I linked)

Does anyone have a known solution for this?

mozmorris commented 4 years ago

Hi @keithpickering - thanks for the report and trying to solve it.

I don't currently have an Android I can test on as I'm working from home. As a suggestion, I was wondering you might try creating a pure js solution eg no React, on user input calling getUserMedia with the new constraints, and seeing what result you get.

If that works, then it might be easier to track down where in the lifecycle we're doing something wrong.

ChrisZieba commented 3 years ago

I've been running into the same problem, but also notice chrome will freeze in Android if I just try and capture an image. Tried all types of video constraints. I haven't been able to isolate the problem yet, but I started using https://github.com/MABelanger/react-html5-camera-photo as a drop in replacement and it seems to work when changing the facing mode on the fly, and also captures images without any problems. Maybe that will help someone.

jellevwezel commented 3 years ago

I have this same issue on all Android 11 devices. Are there any updates on this?

I found that putting the phone in standbye and on again "unstucks" it. Maybe it reinitializes the camera?

keithpickering commented 3 years ago

Still looking for updates on this as well. We're on a tight sprint schedule so I haven't had time to debug the package itself. I just know the way it's supposed to work is causing a freeze.

@jellevwezel I've noticed this as well. Sometimes just going to the home screen and back can initiate the "unstick". I've tried a bunch of solutions for unmounting/remounting the camera, including totally removing the Webcam component from the DOM and then reinserting it with a different deviceId. Nothing seems to make it work as intended.

RodolfoSarkisRocha commented 3 years ago

Hey guys,

I had the same issue, the problem can be replicated when stopping media tracks on android 11.

I found that this is a bug with this version of android and it can be found here:

https://issuetracker.google.com/u/1/issues/173142922

mozmorris commented 3 years ago

@RodolfoSarkisRocha thanks for the link.

I'm still working from home (🦠) and don't have access to any Android devices to observe the bug myself.

mozmorris commented 3 years ago

@keithpickering I know you've been looking for an update for a while now. Did you ever come up with a workaround?

ctrlaltdylan commented 3 years ago

It looks like in a near future Android Chrome version will fix this:

https://issuetracker.google.com/u/0/issues/173142922

Another thread: https://bugs.chromium.org/p/chromium/issues/detail?id=1138823#c25

Here's a really hacky workaround I haven't tested yet: https://gist.github.com/erdgzl/4220083e8f69083c42eda8b1aafb1ad9

Maybe programmatically resizing the window for just a split second will fix it as well.

ctrlaltdylan commented 3 years ago

From what I can tell, you can't access the stream object outside of the context of the Webcam class. Which means the workaround can't be used without forking the library.

The other option is to somehow access the MediaStream from the video ref object. I'm just not sure if that's possible or not.

Then you could do something like this:

          const stream = videoRef.current.srcObject; // or however you'd access the stream from the video ref
          if (stream) {
            stream.getTracks().forEach(track => {
                track.stop();
            });
            stream = null;
        }

Excuse the spacing, I'm just pseudocoding right in Github here.

mozmorris commented 3 years ago

@ctrlaltdylan that should work. And the stream is also passed to the onUserMedia callback prop.

guilngou commented 3 years ago

This worked for me : https://github.com/twilio/twilio-video-app-react/issues/355#issuecomment-780368725

ctrlaltdylan commented 3 years ago

This is my final solution, works on my Pixel 4.

I use this little hack after uploading the photo from the videoRef.current.doScreenshot. Hopefully it helps y'all!

                        let stream = videoRef.current.video.srcObject;
                        if (stream) {
                          videoRef.current.video.srcObject = null;
                          stream.getTracks().forEach((track) => {
                            stream.removeTrack(track);
                            track.stop();
                          });
                          stream = null; // this is probably redundant, but it fixes it so I'm happy.
                        }
mozmorris commented 3 years ago

@keithpickering thanks to the help of @BrendonSled there's a new version published under the next tag and a CodePen using it here: https://codepen.io/mozmorris/pen/vYxZgrP

Could you see if this solves the problem?

mozmorris commented 3 years ago

Now released in 5.2.4