3

I seem to have noticed a regression with getUserMedia in iOS 14 Safari. Here are steps to reproduce:

  1. Go to https://webrtc.github.io/samples/src/content/getusermedia/gum/ on iOS 14 Safari
  2. Click "Open camera" and accept camera permissions; you should see local camera video.
  3. Click the power button and lock the phone; let the phone go to sleep
  4. Unlock/wake the phone; the local camera video is gone.

This does not happen on devices running iOS 13.

My questions are:

  1. Can anyone else confirm this on their devices? I have only tested on iPhone 11 so far.
  2. Has anyone found a solution yet?
zzxx53
  • 413
  • 3
  • 12

3 Answers3

2

Yes, I am having the a similar strange issue with iOS 14.2 and getUserMedia I can only get navigator.mediaDevices.getUserMedia({video: true }) to work If I change it to: navigator.mediaDevices.getUserMedia({ audio: true, video: true }) it will fail. It's not an issue with code as I tested my project on safari MacOS, chrome for MacOS, linux Firefox.

As a temp fix so I could move on with my life for the moment I did this:

const constraints = navigator.userAgent.includes("iPhone") ? {video:true} : {
audio:true,
  video: {
      width: { ideal: 640 },
      height: {ideal: 400 }
      }    
};
reliableJ
  • 51
  • 4
1

Yes also here!

I check this behavior in Browserstack with iOS:

  • 12.x: ✓
  • 13.x: ✓
  • 14.x: ✗

Try this:

navigator.mediaDevices.getUserMedia({ audio: true, video: true })
 .then(stream => {
   const videoTracks = stream.getVideoTracks();
   console.log(videoTracks[0].enabled);
   document.querySelector('video').srcObject = stream;
 });

// Output
true <-- ?

Then if you try again get the camera, but replacing the video track on the previous MediaStream works.

Sometimes if you use video constraints with facingMode: 'user' also works, why? I don't know.

I still can't find a consistent solution.

Matias L.
  • 23
  • 6
0

Having the same issue on iPad pro 2nd generation with iOS 14.7.1 and iPhone 7 iOS 14.6.x. The only solution I found that seems to constantly work is to call getUserMedia separated by audio and video constraints. As an example:

async function getMedia(constraints) {
  let videoStream = null;
  let audioStream = null;

  try {
    videoStream = await navigator.mediaDevices.getUserMedia({video: true});
    audioStream = await navigator.mediaDevices.getUserMedia({audio: true});
    /* use the stream */
  } catch (err) {
    /* handle the error */
  }
}

You can replace {video: true} or {audio: true} with your desired constraints. Then you can either work with the separate MediaStream objects or to construct your own MediaStream object from the audio and video tracks of your streams.

ilpianoforte
  • 1,180
  • 1
  • 10
  • 28