santa
santa

Reputation: 12512

Show functionality only for users that have access to environment facing camera

I'm working on a functionality that will allow users taking pictures with their mobile device camera. Is there a reliable way to detect if a user has this access? Currently this is a constraint set by:

facingMode: { exact: "environment" }

I would like to hide this functionality from users that are not able to use device's back camera. Here's the code that works.

<script>
    const player = document.getElementById('player');
    const canvas = document.getElementById('canvas');
    const context = canvas.getContext('2d');
    const captureButton = document.getElementById('capture');

    const constraints = {
        video:
        {
            facingMode: { exact: "environment" }
        }
    };

    captureButton.addEventListener('click', () => {
        // Draw the video frame to the canvas.
        context.drawImage(player, 0, 0, canvas.width, canvas.height);
    });

    // Attach the video stream to the video element and autoplay.
    navigator.mediaDevices.getUserMedia(constraints)
        .then((stream) => {
            player.srcObject = stream;
        });
</script>

Upvotes: 2

Views: 872

Answers (4)

ulou
ulou

Reputation: 5853

How about something like this?

const isMobileDevice = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)

navigator.getMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia
                      || navigator.mozGetUserMedia || navigator.msGetUserMedia)

navigator.getMedia({video: true}, () => {
  if (isMobileDevice) console.log("I'm mobile device with camera")
  console.log("I have camera")
}, () => {
  console.log("I do not have camera")
})

Upvotes: 1

Dmitry
Dmitry

Reputation: 133

You can chain a new 'catch' error handler like above answers and hide that button inside it.

If you still need to switch to the available camera device, you can consider to use navigator.mediaDevices.enumerateDevices method which returns a promise that receives an array of MediaDeviceInfo objects.

Upvotes: 0

Istiaque Ahmed
Istiaque Ahmed

Reputation: 6488

This answer adds an error handling part i.e: .catch(function(err){ to the getUserMedia(...) method in the OP i.e: original post. In the error handling section, all possible errors are detected that would mean the back camera to be unusable and a brief explanation is held as a variable namely error_msg in the if..else.. block.

    <script>
    const player = document.getElementById('player');
    const canvas = document.getElementById('canvas');
    const context = canvas.getContext('2d');
    const captureButton = document.getElementById('capture');
    
    var constraints = {
     
      video:
            {
                facingMode: { exact: "environment" }
            }
    }
    
    captureButton.addEventListener('click', () => {
            // Draw the video frame to the canvas.
            context.drawImage(player, 0, 0, canvas.width, canvas.height);
        });
    
    navigator.mediaDevices.getUserMedia(constraints)
    .then(function success(stream) {
    
        
        player.srcObject = stream;
                    
    }).catch(function(err) {
    //log to console first 
    //console.log(err); /* handle the error */
    var error_msg="";
    if (err.name == "NotFoundError" || err.name == "DevicesNotFoundError") {
    
        
          error_msg="Back camera not found error ";
        //required track is missing 
    } else if (err.name == "NotReadableError" || err.name == "TrackStartError") {
        //webcam or mic are already in use 
        
        error_msg="cam is already in use ";
    } else if (err.name == "OverconstrainedError" || err.name == "ConstraintNotSatisfiedError") {
        //constraints can not be satisfied by avb. devices 
        
        error_msg="constraints can not be satisfied by avb. devices ";
        
        
    }
    else if (err.name == "NotAllowedError" || err.name == "PermissionDeniedError") {
        //permission denied in browser 
        
        error_msg="permission denied in browser ";
        
        
    } else if (err.name == "TypeError" || err.name == "TypeError") {
        //empty constraints object 
        
        error_msg="empty constraints object ";
    } else {
    
        //other errors 
        
        error_msg="Errors somehow";
    }
  captureButton.style.display = 'none';
  
  alert(error_msg);
    
});
    </script>

You can find a jsfiddle here.

In the fiddle the player, canvas and context variables have been omitted as no HTML elements exist with the IDs of the variables. I hope you have the HTML elements with the IDs in your actual production code. Besides a button with the ID capture has been added. These changes were necessary to run the code in the fiddle without producing any errors.

Upvotes: 0

rubenpoppe
rubenpoppe

Reputation: 316

When the exact constraint is not met, a OverconstrainedError is thrown. You can catch the error and hide an element like so.

const video = document.getElementById('video');
const button = document.getElementById('button');

navigator.mediaDevices
  .getUserMedia({
    video: {
      facingMode: {
        exact: 'environment'
      },
    },
  })
  .then((stream) => video.srcObject = stream)
  .catch((_) => button.style.display = 'none');

https://jsfiddle.net/68e5t4z1/13/

Upvotes: 3

Related Questions