Ray
Ray

Reputation: 67

iOS13 getUserMedia not working on chrome and edge

Me and my friend are building an app that requires camera access and we're having some issue with getting the camera working with iOS (we're using iOS13):

Safari freeze right after getting the camera content, chrome and edge doesn't acquire camera access at all. Our code is as follow:

let windowWidth=window.innerWidth;
let windowHeight=window.innerHeight;

function isMobile() {
    const isAndroid = /Android/i.test(navigator.userAgent);
    const isiOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
    return isAndroid || isiOS;
}

async function setupCamera() {
    video = document.getElementById('video');
    console.log("a")

    video.setAttribute('autoplay', '');
    video.setAttribute('muted', '');
    video.setAttribute('playsinline', '');

    const stream = await navigator.mediaDevices.getUserMedia({
        'audio': false,
        'video': {
            facingMode: 'user',
            width: mobile ? undefined : windowWidth,
            height: mobile ? undefined : windowHeight
        },
    });
    console.log("b")
    video.srcObject = stream;

    return new Promise((resolve) => {
        video.onloadedmetadata = () => {
            resolve(video);
        };
    });
}

According to the console, 'a' always gets printed but never 'b'. Any clue on what's wrong will be greatly appreciated!

Upvotes: 3

Views: 7786

Answers (1)

Marcus
Marcus

Reputation: 1938

Update - 19/11/2020

WKWebView can use getUserMedia in iOS 14.3 beta 1.

Browser compatibility

I've been following this problem for years via other posts (e.g. NotReadableError: Could not start source) . As of this date there is no access to getUserMedia outside of Safari standalone view (webapp) or the iOS Safari app.

Any browser on iOS other than Safari does not have getUserMedia access. This is because under the hood they are using WKWebView.

A bug ticket has been filed specifically for WKWebView. No support. https://bugs.webkit.org/show_bug.cgi?id=208667

Updates to standalone mode gaining getUserMedia access in iOS 13.4 https://bugs.webkit.org/show_bug.cgi?id=185448#c6

Safari freezing

You are passing in constraints which are invalid (e.g. window width and height). You need to use standard camera resolutions e.g. 640x480, 1280x720, etc. When you use an atypical resolution WebRTC spec states the browser will try emulate your desired feed however this often results in the camera freezing or looking warped.

If you are trying to capture the front camera and fullscreen it you can look at: getUserMedia (Selfie) Full Screen on Mobile

There also maybe 1 or 2 bugs with the use of async/await. Below is a demo which should work (However within stackoverflow it will error due to security permissions, but should work locally or hosted). Let me know if I can help further.

function isMobile() {
  const isAndroid = /Android/i.test(navigator.userAgent);
  const isiOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
  return isAndroid || isiOS;
}

async function setupCamera() {
  const isPortrait = true; // do logic here

  let video = document.getElementById('video');

  console.log("Getting video");

  video.setAttribute('autoplay', '');
  video.setAttribute('muted', '');
  video.setAttribute('playsinline', '');

  console.log("Calling getUserMedia");

  return new Promise((resolve) => {
    (async() => {
      await navigator.mediaDevices.getUserMedia({
          'audio': false,
          'video': {
            facingMode: 'user',
            width: isPortrait ? 480 : 640,
            height: isPortrait ? 640 : 480,
          },
        })
        .then((stream) => {
          console.log("Got getUserMedia stream");
          video.srcObject = stream;
          video.play();
          resolve(true);
        })
        .catch((err) => {
          console.log("Encountered getUserMedia error", err);
          resolve(false);
        });
    })();
  });

}

(async() => {
  const ret = await setupCamera();
  console.log(`Initialised camera: ${ret}`)
})();
html,
body {
  height: 100%;
  margin: 0;
}

div {
  position: relative;
  min-height: 100%;
  min-width: 100%;
  overflow: hidden;
  object-fit: cover;
}

video {
  width: 480px;
  height: 640px;
  background-color: black;
}
<div><video id="video"></video></div>

Upvotes: 9

Related Questions