deluxan
deluxan

Reputation: 422

MediaDevices.getUserMedia() support for ios

I was trying to get browser settings details (Camera, Microphone permission) in ReactJS project. Based on that I will show some error message in the UI if it is blocked. I use the following code.

useEffect(()=>{
collectUserLogData();
},[]);

const collectUserLogData = () => {
    navigator.getMedia =
      navigator.getUserMedia ||
      navigator.webkitGetUserMedia ||
      navigator.mozGetUserMedia ||
      navigator.msGetUserMedia;

    navigator.getMedia(
      { video: true },
      () => {
        setCamera(true);
        console.log("Permission_", "camera ON");
      },
      () => {
        console.log("Permission_", "Camera OFF");
      }
    );

    navigator.getMedia(
      { audio: true },
      () => {
        setMic(true);
        console.log("Permission_", "Mic ON");
      },
      () => {
        console.log("Permission_", "Mic OFF");
      }
    );

    navigator.geolocation.getCurrentPosition(
      () => {
        setLocation(true);
        console.log("Permission_", "Geo ON");
      },
      () => {
        console.log("Permission_", "Geo OFF");
      }
    );
  };

This is working in the windows and android browsers but not in the ios browsers. I did not test it in the mac ios. The popup is not showing in ios browsers. How to fix this.

Upvotes: 2

Views: 9944

Answers (2)

O. Jones
O. Jones

Reputation: 108851

getUserMedia() works properly on recent version of iOS. Generally 11.1 and beyond are OK.

To troubleshoot this stuff, you need to connect your iOS device to a Mac and use the Safari remote debugging setup. That way you can get a console and javascript debugger.

enumerateDevices() works if you have already used getUserMedia() to ask the user for permission to use the camera and/or mic. Without that permission, the emumerateDevices() results are vague or missing. This is to prevent browser fingerprinting. Because cybercreeps.

In the versions of iOS where getUserMedia actually works, you don't need to look around in various namespaces to find it. navigator.mediaDevices.getUserMedia() is sufficient.

Here's code like what I've used to enumerate media sources on all kinds of different browser platforms incl. iOS, Android, and various desktops. I've used async / await because it's an easy way to handle the Promise returned by getUserMedia(). But you could use the Promise directly if you wish. (Please note I've edited this code to remove my application-specific stuff, but I haven't debugged it.)

async function enumerateSources() {
    if(      navigator 
          && navigator.mediaDevices 
          && typeof navigator.mediaDevices.enumerateDevices === 'function' ) {
      try {
        /* open a generic stream to get permission to see devices; 
         * Mobile Safari insists */
        const stream = await navigator.mediaDevices.getUserMedia(
                { video: true, audio: true} )
        let devices = await navigator.mediaDevices.enumerateDevices()
        const cameras = devices.filter( device => {
          return device.kind === 'videoinput'
        })
        if (cameras.length >= 1) console.log ('cameras avail')
        const mics = devices.filter( device => {
          return device.kind === 'audioinput'
        })
        if (mics.length >= 1) console.log ('mics avail')

       /* release stream */
        const tracks = stream.getTracks()
        if( tracks ) {
          for( let t = 0; t < tracks.length; t++ ) tracks[t].stop()
        }
        return ({cameras, mics})
      } catch(error) {
        /* user refused permission, or media busy, or some other problem */
        console.error(error.name, error.message)
        return {cameras:[], mics:[]})
      }
    }
    else throw ('media device stuff not available in this browser')
}

Upvotes: 3

s&#231;u&#231;u
s&#231;u&#231;u

Reputation: 3070

The new API works like

navigator.mediaDevices.getUserMedia()

I suggest you to add to the support logic statement of yours to supersede all the others which are the old API.

You then need to to use the stream that promise resolve with. You can have a video element in our DOM and set its srcObj property with the stream.

navigator.getMedia(
      { video: true },
      (stream) => {
        video.srcObj = stream;
        setCamera(true);
        console.log("Permission_", "camera ON");
      },
      () => {
        console.log("Permission_", "Camera OFF");
      }
    );

Upvotes: 0

Related Questions